Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | /*
* Builds the icons previewer (Next.js static export).
*
* The `app/workflow` and `app/api/workflow` routes cannot be part of this build
* (they require a server runtime and break the static export), so this script
* temporarily moves them out of the tree, runs `next build`, and then always
* restores them — even if the build fails.
*/
import { spawn } from 'node:child_process';
import fs from 'node:fs/promises';
import path from 'node:path';
const rootDir = path.resolve(import.meta.dirname, '..');
const backupRoot = path.join(rootDir, '.workflow-build-backup');
const workflowTargets = [path.join(rootDir, 'app', 'workflow'), path.join(rootDir, 'app', 'api', 'workflow')];
/*
* Maps a target folder to its flat, collision-free stash location under
* backupRoot (e.g. app/workflow -> .workflow-build-backup/app__workflow).
* Pure path computation — does no file I/O.
*/
function backupPath(targetPath: string): string {
const relative = path.relative(rootDir, targetPath).replace(/[\\/]/g, '__');
return path.join(backupRoot, relative);
}
/* Returns true if the path exists on disk, false otherwise (never throws). */
async function pathExists(targetPath: string): Promise<boolean> {
try {
await fs.access(targetPath);
return true;
} catch {
return false;
}
}
/*
* Moves each existing workflow route folder out to its backup location so it is
* excluded from the build. Returns the list of targets that were moved, for
* restoreWorkflowRoutes to reverse.
*/
async function disableWorkflowRoutes(): Promise<string[]> {
const moved: string[] = [];
await fs.mkdir(backupRoot, { recursive: true });
for (const target of workflowTargets) {
const backup = backupPath(target);
if (!(await pathExists(target))) {
continue;
}
await fs.rm(backup, { recursive: true, force: true });
await fs.rename(target, backup);
moved.push(target);
}
return moved;
}
/*
* Moves the previously stashed folders back to their original paths and removes
* the backup root. Safe to call even if the build failed partway through.
*/
async function restoreWorkflowRoutes(movedTargets: string[]): Promise<void> {
for (const target of movedTargets.reverse()) {
const backup = backupPath(target);
if (!(await pathExists(backup))) {
continue;
}
await fs.rm(target, { recursive: true, force: true });
await fs.mkdir(path.dirname(target), { recursive: true });
await fs.rename(backup, target);
}
await fs.rm(backupRoot, { recursive: true, force: true });
}
/*
* Runs `next build` in the package root, resolving on exit code 0 and rejecting
* on spawn error or any non-zero exit code.
*/
function runNextBuild(): Promise<void> {
return new Promise((resolve, reject) => {
const child = spawn('next', ['build'], {
cwd: rootDir,
stdio: 'inherit',
shell: true,
env: process.env,
});
child.on('error', reject);
child.on('exit', (code) => {
if (code === 0) {
resolve();
return;
}
reject(new Error(`next build failed with exit code ${code ?? 'unknown'}`));
});
});
}
/*
* Orchestrates the previewer build: disable the workflow routes, run the Next.js
* build, then always restore the routes (even if the build throws).
*/
async function main(): Promise<void> {
const movedTargets = await disableWorkflowRoutes();
try {
await runNextBuild();
} finally {
await restoreWorkflowRoutes(movedTargets);
}
}
await main();
|