feat(build): add build:fast and start:fast to bypass standalone tracing (#13021)

* feat(build): add build:fast and OMNIROUTE_SKIP_STANDALONE to bypass standalone tracing

* feat(build): add start:fast script to run non-standalone builds locally

* docs(changelog): add fragment for #13021
This commit is contained in:
Tuan Dinh
2026-09-18 22:23:23 +07:00
committed by GitHub
parent e188da6399
commit 45fa62a18e
7 changed files with 47 additions and 10 deletions

View File

@@ -0,0 +1 @@
- **feat(build):** add build:fast and start:fast to bypass standalone tracing ([#13021](https://github.com/diegosouzapw/OmniRoute/pull/13021)) — thanks @tuandinh0801

View File

@@ -10,6 +10,7 @@ import {
nonPageRoutePrefixes,
resolveDashboardEmbedMode,
} from "./scripts/build/dashboardEmbed.mjs";
import { shouldBuildStandalone } from "./scripts/build/backendOnlyPages.mjs";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
const distDir = process.env.NEXT_DIST_DIR || ".build/next";
@@ -109,8 +110,6 @@ function filterKnownInfrastructureWarnings(baseConsole) {
// The resulting artifact is intended to be published as `omniroute-secure`
// for security-sensitive environments. See docs/security/SOCKET_DEV_FINDINGS.md.
const isMinimalBuild = process.env.OMNIROUTE_BUILD_PROFILE === "minimal";
// Contributor builds validate compilation only and do not need a shippable standalone bundle.
const isContributorBuild = process.env.OMNIROUTE_BUILD_PROFILE === "contributor";
// #10273: `null` unless the operator opts in with DASHBOARD_ALLOW_EMBED=vscode. Read at build
// time like every other knob in this file (OMNIROUTE_BASE_PATH, OMNIROUTE_BUILD_PROFILE, …),
@@ -220,7 +219,7 @@ const nextConfig = {
},
],
},
...(isContributorBuild ? {} : { output: "standalone" }),
...(shouldBuildStandalone(process.env) ? { output: "standalone" } : {}),
compress: true,
productionBrowserSourceMaps: false,
// Issue #67: enable React Compiler — automates memoization, removes manual useCallback/useMemo debt.

View File

@@ -105,7 +105,9 @@
"eval:router:trends": "node --import tsx scripts/router-eval/trends.ts",
"release:sync-changelog-i18n": "node scripts/release/sync-changelog-i18n.mjs",
"prebuild": "npm run check:native-deps",
"prebuild:fast": "npm run check:native-deps",
"build": "node scripts/build/build-next-isolated.mjs",
"build:fast": "cross-env OMNIROUTE_SKIP_STANDALONE=1 node scripts/build/build-next-isolated.mjs",
"build:secure": "OMNIROUTE_BUILD_PROFILE=minimal node scripts/build/build-next-isolated.mjs",
"build:backend": "cross-env OMNIROUTE_BUILD_BACKEND_ONLY=1 node scripts/build/build-next-isolated.mjs",
"build:contributor": "cross-env OMNIROUTE_BUILD_PROFILE=contributor OMNIROUTE_USE_TURBOPACK=0 node scripts/build/build-next-isolated.mjs",
@@ -114,6 +116,7 @@
"build:release": "rm -rf .build dist && OMNIROUTE_BUILD_SHA=$(git rev-parse --short HEAD) npm run build && npm run build:cli && node scripts/build/write-build-sha.mjs",
"build:native:tproxy": "cd src/mitm/tproxy/native && npx --yes node-gyp rebuild",
"start": "node scripts/dev/run-next.mjs start",
"start:fast": "cross-env OMNIROUTE_SKIP_STANDALONE=1 node scripts/dev/run-next.mjs start",
"homolog": "node scripts/homolog/run.mjs",
"lint": "eslint . --cache --cache-location .eslintcache --suppressions-location config/quality/eslint-suppressions.json",
"lint:json": "node scripts/quality/run-eslint-json.mjs",

View File

@@ -59,7 +59,8 @@ const ERROR_STUB = `${HEADER}"use client";\nexport default function BackendOnlyE
// global-error replaces the root layout on a root error, so it must render <html>/<body>.
const GLOBAL_ERROR_STUB = `${HEADER}"use client";\nexport default function BackendOnlyGlobalErrorStub() {\n return (\n <html>\n <body></body>\n </html>\n );\n}\n`;
const UI_BASENAME_RE = /^(page|layout|template|loading|error|global-error|not-found|default)\.(tsx|jsx|ts|js)$/;
const UI_BASENAME_RE =
/^(page|layout|template|loading|error|global-error|not-found|default)\.(tsx|jsx|ts|js)$/;
const ROUTE_FILE_RE = /[\\/]route\.(ts|js|tsx|jsx)$/;
/**
@@ -103,6 +104,11 @@ export function isContributorBuild(env = process.env) {
return env.OMNIROUTE_BUILD_PROFILE === "contributor";
}
/** True when standalone output should be packaged (default true; skipped for contributor or fast build). */
export function shouldBuildStandalone(env = process.env) {
return !isContributorBuild(env) && env.OMNIROUTE_SKIP_STANDALONE !== "1";
}
/** Replace the build-only instrumentation entrypoint to avoid pulling the startup graph. */
export function stubContributorInstrumentation(rootDir = process.cwd(), log = console) {
const stubbed = [];

View File

@@ -14,11 +14,14 @@ import {
import {
isBackendOnlyBuild,
isContributorBuild,
shouldBuildStandalone,
stubContributorInstrumentation,
stubDashboardPages,
restoreDashboardPages,
} from "./backendOnlyPages.mjs";
export { shouldBuildStandalone } from "./backendOnlyPages.mjs";
/**
* Layer 1: `app/` has been renamed to `dist/` and the App-Router collision is gone.
* The only transient paths remaining are `.tmp/wine32` (Wine prefix used by some
@@ -310,7 +313,7 @@ export async function main() {
const result = await runNextBuild();
const standaloneDir = path.join(distDir, "standalone");
if (result.code === 0 && (await exists(standaloneDir)) && !isContributorBuild()) {
if (result.code === 0 && (await exists(standaloneDir)) && shouldBuildStandalone()) {
try {
await fs.cp(path.join(projectRoot, "docs"), path.join(standaloneDir, "docs"), {
recursive: true,
@@ -377,9 +380,9 @@ export async function main() {
} catch (assembleErr) {
console.warn("[build-next-isolated] Non-fatal error assembling standalone:", assembleErr);
}
} else if (result.code === 0 && isContributorBuild()) {
} else if (result.code === 0 && !shouldBuildStandalone()) {
console.log(
"[build-next-isolated] Contributor profile: skipped standalone packaging (compile-only validation)"
"[build-next-isolated] Skipped standalone packaging (standalone disabled for fast compile)"
);
}
process.exitCode = result.code;

View File

@@ -9,6 +9,7 @@ import {
movePath,
pruneStandaloneArtifacts,
resolveNextBuildEnv,
shouldBuildStandalone,
syncStandaloneExtraModules,
syncStandaloneNativeAssets,
} from "../../scripts/build/build-next-isolated.mjs";
@@ -223,3 +224,18 @@ test("syncStandaloneExtraModules copies the complete wreq-js runtime", async ()
assert.match(logs[0] ?? "", /wreq-js TLS runtime/);
});
});
test("shouldBuildStandalone honors OMNIROUTE_SKIP_STANDALONE and contributor profile", () => {
assert.equal(shouldBuildStandalone({}), true);
assert.equal(shouldBuildStandalone({ OMNIROUTE_SKIP_STANDALONE: "0" }), true);
assert.equal(shouldBuildStandalone({ OMNIROUTE_SKIP_STANDALONE: "1" }), false);
assert.equal(shouldBuildStandalone({ OMNIROUTE_BUILD_PROFILE: "contributor" }), false);
assert.equal(
shouldBuildStandalone({
OMNIROUTE_SKIP_STANDALONE: "1",
OMNIROUTE_BUILD_PROFILE: "minimal",
}),
false
);
assert.equal(shouldBuildStandalone({ OMNIROUTE_BUILD_PROFILE: "minimal" }), true);
});

View File

@@ -4,6 +4,7 @@ import fs from "node:fs";
import path from "node:path";
import {
isContributorBuild,
shouldBuildStandalone,
stubContributorInstrumentation,
} from "../../../scripts/build/backendOnlyPages.mjs";
@@ -51,10 +52,18 @@ test("contributor instrumentation stubs are reversible", async () => {
await fs.rm(tempRoot, { recursive: true, force: true });
});
test("contributor profile disables standalone output while default keeps it", () => {
assert.match(nextConfigSource, /isContributorBuild/);
test("shouldBuildStandalone disables standalone output for contributor and fast build while default keeps it", () => {
assert.equal(shouldBuildStandalone({}), true);
assert.equal(shouldBuildStandalone({ OMNIROUTE_BUILD_PROFILE: "backend" }), true);
assert.equal(shouldBuildStandalone({ OMNIROUTE_BUILD_PROFILE: "minimal" }), true);
assert.equal(shouldBuildStandalone({ OMNIROUTE_BUILD_PROFILE: "contributor" }), false);
assert.equal(shouldBuildStandalone({ OMNIROUTE_SKIP_STANDALONE: "1" }), false);
assert.match(packageJson.scripts["build:fast"], /OMNIROUTE_SKIP_STANDALONE=1/);
assert.match(packageJson.scripts["prebuild:fast"], /check:native-deps/);
assert.match(packageJson.scripts["start:fast"], /OMNIROUTE_SKIP_STANDALONE=1/);
assert.match(nextConfigSource, /shouldBuildStandalone/);
assert.match(
nextConfigSource,
/\.\.\.\(isContributorBuild \? \{\} : \{ output: "standalone" \}\)/
/\.\.\.\(shouldBuildStandalone\(process\.env\) \? \{ output: "standalone" \} : \{\}\)/
);
});