refactor: build frontend externally, copy dist into nginx image
- frontend.Dockerfile: runtime-only, COPY apps/frontend/dist instead of building in Docker - build.js: add frontend build step (pnpm build) before docker build - drone.yml: remove obsolete frontend-deps/frontend-build steps
This commit is contained in:
parent
3bc381da45
commit
65a34a627f
12
.drone.yml
12
.drone.yml
@ -28,16 +28,6 @@ steps:
|
|||||||
git checkout ${DRONE_TAG}
|
git checkout ${DRONE_TAG}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: frontend-deps
|
|
||||||
image: node:22-alpine
|
|
||||||
commands:
|
|
||||||
- cd apps/frontend && corepack enable && corepack prepare pnpm@10 --activate && pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: frontend-build
|
|
||||||
image: node:22-alpine
|
|
||||||
commands:
|
|
||||||
- cd apps/frontend && pnpm build
|
|
||||||
|
|
||||||
- name: cargo-build
|
- name: cargo-build
|
||||||
image: rust:1.94-bookworm
|
image: rust:1.94-bookworm
|
||||||
commands:
|
commands:
|
||||||
@ -80,7 +70,7 @@ steps:
|
|||||||
/kaniko/executor --context . --dockerfile docker/frontend.Dockerfile \
|
/kaniko/executor --context . --dockerfile docker/frontend.Dockerfile \
|
||||||
--destination ${REGISTRY}/frontend:${TAG} --destination ${REGISTRY}/frontend:latest
|
--destination ${REGISTRY}/frontend:${TAG} --destination ${REGISTRY}/frontend:latest
|
||||||
echo "==> All images pushed"
|
echo "==> All images pushed"
|
||||||
depends_on: [ cargo-build, frontend-build ]
|
depends_on: [ cargo-build ]
|
||||||
|
|
||||||
- name: prepare-kubeconfig
|
- name: prepare-kubeconfig
|
||||||
image: alpine:latest
|
image: alpine:latest
|
||||||
|
|||||||
@ -1,26 +1,8 @@
|
|||||||
# ---- Stage 1: Build ----
|
# Runtime only — frontend built externally via pnpm
|
||||||
FROM node:22-alpine AS builder
|
FROM nginx:alpine
|
||||||
|
|
||||||
WORKDIR /app
|
# Copy pre-built SPA assets
|
||||||
|
COPY apps/frontend/dist /usr/share/nginx/html
|
||||||
# Copy package files
|
|
||||||
COPY package.json pnpm-lock.yaml ./
|
|
||||||
RUN corepack enable && corepack prepare pnpm@10 --activate
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# Copy source
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build
|
|
||||||
RUN pnpm build
|
|
||||||
|
|
||||||
# ---- Stage 2: Serve with nginx ----
|
|
||||||
FROM nginx:alpine AS runtime
|
|
||||||
|
|
||||||
# Copy built assets
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
||||||
|
|
||||||
# nginx configuration for SPA
|
# nginx configuration for SPA
|
||||||
RUN echo 'server { \
|
RUN echo 'server { \
|
||||||
@ -46,5 +28,4 @@ RUN echo 'server { \
|
|||||||
}' > /etc/nginx/conf.d/default.conf
|
}' > /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
*
|
*
|
||||||
* Workflow:
|
* Workflow:
|
||||||
* 1. cargo build --release --target x86_64-unknown-linux-gnu (compile Rust binaries)
|
* 1. cargo build --release --target x86_64-unknown-linux-gnu (compile Rust binaries)
|
||||||
* 2. docker build (copy pre-built binaries into minimal runtime images)
|
* 2. pnpm build (build frontend SPA)
|
||||||
|
* 3. docker build (copy pre-built artifacts into minimal runtime images)
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* node scripts/build.js # Build all images
|
* node scripts/build.js # Build all images
|
||||||
@ -18,19 +19,21 @@
|
|||||||
|
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require('child_process');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
||||||
const TAG = process.env.TAG || new Date().toISOString().slice(0, 13).replace('T', '-');
|
const TAG = process.env.TAG || new Date().toISOString().slice(0, 13).replace('T', '-');
|
||||||
const BUILD_TARGET = process.env.TARGET || 'x86_64-unknown-linux-gnu';
|
const BUILD_TARGET = process.env.TARGET || 'x86_64-unknown-linux-gnu';
|
||||||
|
|
||||||
const RUST_SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'operator', 'static'];
|
const RUST_SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'operator', 'static'];
|
||||||
const ALL_SERVICES = [...RUST_SERVICES, 'frontend'];
|
const FRONTEND_SERVICE = 'frontend';
|
||||||
|
const ALL_SERVICES = [...RUST_SERVICES, FRONTEND_SERVICE];
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const targets = args.length > 0 ? args : ALL_SERVICES;
|
const targets = args.length > 0 ? args : ALL_SERVICES;
|
||||||
|
|
||||||
// Determine which rust services are in targets
|
|
||||||
const rustTargets = targets.filter(s => RUST_SERVICES.includes(s));
|
const rustTargets = targets.filter(s => RUST_SERVICES.includes(s));
|
||||||
|
const needsFrontend = targets.includes(FRONTEND_SERVICE);
|
||||||
|
|
||||||
console.log(`\n=== Build Configuration ===`);
|
console.log(`\n=== Build Configuration ===`);
|
||||||
console.log(`Registry: ${REGISTRY}`);
|
console.log(`Registry: ${REGISTRY}`);
|
||||||
@ -42,21 +45,15 @@ console.log(`Services: ${targets.join(', ')}\n`);
|
|||||||
if (rustTargets.length > 0) {
|
if (rustTargets.length > 0) {
|
||||||
console.log(`\n==> Step 1: Building Rust binaries`);
|
console.log(`\n==> Step 1: Building Rust binaries`);
|
||||||
const cpus = require('os').cpus().length;
|
const cpus = require('os').cpus().length;
|
||||||
const packages = rustTargets.map(s => {
|
|
||||||
const pkgMap = {
|
|
||||||
'app': 'app',
|
|
||||||
'gitserver': 'gitserver',
|
|
||||||
'email-worker': 'email-server',
|
|
||||||
'git-hook': 'git-hook',
|
|
||||||
'operator': 'operator',
|
|
||||||
'static': 'static-server',
|
|
||||||
};
|
|
||||||
return `--package ${pkgMap[s]}`;
|
|
||||||
}).join(' ');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync(
|
execSync(
|
||||||
`cargo build --release --target ${BUILD_TARGET} ${packages} -j ${cpus}`,
|
`cargo build --release --target ${BUILD_TARGET} ${rustTargets.map(s => {
|
||||||
|
const pkgMap = {
|
||||||
|
'app': 'app', 'gitserver': 'gitserver', 'email-worker': 'email-server',
|
||||||
|
'git-hook': 'git-hook', 'operator': 'operator', 'static': 'static-server',
|
||||||
|
};
|
||||||
|
return `--package ${pkgMap[s]}`;
|
||||||
|
}).join(' ')} -j ${cpus}`,
|
||||||
{ stdio: 'inherit', cwd: path.join(__dirname, '..') }
|
{ stdio: 'inherit', cwd: path.join(__dirname, '..') }
|
||||||
);
|
);
|
||||||
console.log(` [OK] Rust binaries built`);
|
console.log(` [OK] Rust binaries built`);
|
||||||
@ -66,8 +63,28 @@ if (rustTargets.length > 0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Build Docker images
|
// Step 2: Build frontend (requires apps/frontend to exist locally)
|
||||||
console.log(`\n==> Step 2: Building Docker images`);
|
if (needsFrontend) {
|
||||||
|
const frontendDir = path.join(__dirname, '..', 'apps', 'frontend');
|
||||||
|
if (!fs.existsSync(frontendDir)) {
|
||||||
|
console.error(`\n [FAIL] apps/frontend not found. Please ensure frontend source exists.`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`\n==> Step 2: Building frontend`);
|
||||||
|
try {
|
||||||
|
execSync(`corepack enable && corepack prepare pnpm@10 --activate && pnpm install --frozen-lockfile && pnpm build`, {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: frontendDir,
|
||||||
|
});
|
||||||
|
console.log(` [OK] Frontend built`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(` [FAIL] Frontend build failed`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Build Docker images
|
||||||
|
console.log(`\n==> Step 3: Building Docker images`);
|
||||||
|
|
||||||
for (const service of targets) {
|
for (const service of targets) {
|
||||||
if (!ALL_SERVICES.includes(service)) {
|
if (!ALL_SERVICES.includes(service)) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user