perf: 릴리스 프론트엔드 빌드를 안전하게 캐시
Gateway와 Profile 릴리스의 타입검사와 Vite 번들을 별도 Turbo 작업으로 캐시한다. DB 보존 DEPLOY는 game-api만 빌드하고 기본 동시성 1과 기존 산출물 계약은 유지한다.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { cp, mkdir, rename, rm, stat } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
const sanitizeArtifactName = (value) => value.replace(/[^0-9A-Za-z._-]+/g, '_');
|
||||
|
||||
const pathExists = async (target) => {
|
||||
try {
|
||||
await stat(target);
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error?.code === 'ENOENT') return false;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const materializeProfileFrontend = async (workspaceRoot, profileName) => {
|
||||
const normalizedProfileName = profileName.trim();
|
||||
if (!normalizedProfileName) throw new Error('profileName is required.');
|
||||
|
||||
const source = path.join(workspaceRoot, 'app', 'game-frontend', '.release-build');
|
||||
const target = path.join(
|
||||
workspaceRoot,
|
||||
'.release-dist',
|
||||
sanitizeArtifactName(normalizedProfileName),
|
||||
'game-frontend'
|
||||
);
|
||||
await stat(path.join(source, 'index.html'));
|
||||
|
||||
const parent = path.dirname(target);
|
||||
const nonce = `${process.pid}-${randomUUID()}`;
|
||||
const staging = path.join(parent, `.game-frontend-staging-${nonce}`);
|
||||
const previous = path.join(parent, `.game-frontend-previous-${nonce}`);
|
||||
await mkdir(parent, { recursive: true });
|
||||
await cp(source, staging, { recursive: true, errorOnExist: true, force: false });
|
||||
|
||||
let movedPrevious = false;
|
||||
try {
|
||||
if (await pathExists(target)) {
|
||||
await rename(target, previous);
|
||||
movedPrevious = true;
|
||||
}
|
||||
await rename(staging, target);
|
||||
if (movedPrevious) await rm(previous, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
await rm(staging, { recursive: true, force: true });
|
||||
if (movedPrevious && !(await pathExists(target))) await rename(previous, target);
|
||||
throw error;
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
const isDirectExecution = process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
|
||||
if (isDirectExecution) {
|
||||
const profileName = process.argv[2];
|
||||
if (!profileName) throw new Error('Usage: materialize-profile-frontend.mjs <profileName>');
|
||||
const target = await materializeProfileFrontend(process.cwd(), profileName);
|
||||
process.stdout.write(`Profile frontend materialized at ${target}\n`);
|
||||
}
|
||||
Reference in New Issue
Block a user