diff --git a/scripts/dev/webpack-config-light.test.cjs b/scripts/dev/webpack-config-light.test.cjs index 38301c192..eab250329 100644 --- a/scripts/dev/webpack-config-light.test.cjs +++ b/scripts/dev/webpack-config-light.test.cjs @@ -49,6 +49,41 @@ test("light dev disables webpack dev-server browser client", () => { assert.equal(htmlPlugin?.userOptions?.retryMainScriptLoad, false); }); +test("development cache stays memory-only and bounded to one generation", () => { + for (const lightDev of [false, true]) { + const config = withEnv( + { + ORGII_LIGHT_DEV: lightDev ? "true" : null, + FAST_DEV: lightDev ? "true" : null, + DEV_SOURCEMAPS: lightDev ? "false" : null, + }, + () => createWebpackConfig({}, { mode: "development" }) + ); + + assert.deepEqual(config.cache, { + type: "memory", + maxGenerations: 1, + }); + } +}); + +test("production keeps its isolated filesystem cache", () => { + for (const fastProd of [false, true]) { + const config = withEnv( + { + FAST_PROD: fastProd ? "true" : null, + }, + () => createWebpackConfig({}, { mode: "production" }) + ); + + assert.equal(config.cache.type, "filesystem"); + assert.equal( + config.cache.version, + `${fastProd ? "prod-fast" : "prod"}-11` + ); + } +}); + test("retrying main script loader disables static HTML injection in dev", () => { const config = withEnv( { diff --git a/webpack.config.js b/webpack.config.js index 0ad0e91df..989233200 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -62,24 +62,32 @@ module.exports = (env, argv) => { chunkFilename: isProduction ? "[name].[contenthash].js" : "[name].js", clean: true, }, - cache: { - type: "filesystem", - // FAST_PROD swaps both the transpiler and minimizer. Keep it in a - // separate filesystem-cache namespace so webpack cannot reuse cached - // runtime-condition code generated by the regular production pipeline. - // Mixing those caches can leave async chunks guarded by a stale runtime - // id (for example `__webpack_require__.j == 9121` while the emitted - // runtime id is `49121`), which turns otherwise valid imports into - // `undefined` only in the packaged app. - version: `${ - isProduction ? (useFastProd ? "prod-fast" : "prod") : "dev" - }-11`, - buildDependencies: { - config: [__filename], - }, - // Don't compress - avoids sass serialization issues - compression: false, - }, + cache: isProduction + ? { + type: "filesystem", + // FAST_PROD swaps both the transpiler and minimizer. Keep it in a + // separate filesystem-cache namespace so webpack cannot reuse cached + // runtime-condition code generated by the regular production pipeline. + // Mixing those caches can leave async chunks guarded by a stale runtime + // id (for example `__webpack_require__.j == 9121` while the emitted + // runtime id is `49121`), which turns otherwise valid imports into + // `undefined` only in the packaged app. + version: `${useFastProd ? "prod-fast" : "prod"}-11`, + buildDependencies: { + config: [__filename], + }, + // Don't compress - avoids sass serialization issues + compression: false, + } + : { + // Webpack's filesystem cache serialized 1–4+ GB pack files for this + // app and deserializing them pushed the long-lived dev server to a + // 7–9 GB physical footprint. Dev mode already keeps the active + // compilation graph in memory, so retain only one unused generation + // for rebuilds and never persist that graph across process restarts. + type: "memory", + maxGenerations: 1, + }, // Snapshot: use timestamps for node_modules instead of content hashing. // node_modules rarely change during a dev session; timestamp checks are much faster. snapshot: {