From 4f5469eab5380f8c8c6d92341cc319370013866e Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Mon, 6 Oct 2025 12:48:33 +0200 Subject: [PATCH 1/6] Remove __NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD flag --- packages/next/src/server/config-shared.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 4b6c4f3f7b32b..d83e7c9a58e67 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -1525,9 +1525,8 @@ export const defaultConfig = Object.freeze({ slowModuleDetection: undefined, globalNotFound: false, browserDebugInfoInTerminal: false, - isolatedDevBuild: - process.env.__NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD === 'true', lockDistDir: true, + isolatedDevBuild: true, }, htmlLimitedBots: undefined, bundlePagesRouterDependencies: false, From 77f67fbb95402417879138502778982180dd7ec2 Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Tue, 7 Oct 2025 00:49:24 +0200 Subject: [PATCH 2/6] Update tests --- test/integration/dist-dir/test/index.test.js | 12 +++------- .../integration/module-ids/test/index.test.js | 23 ++++++++++++++----- .../next-env.d.ts | 2 +- .../test/index.test.js | 12 ---------- test/lib/next-test-utils.ts | 4 +--- test/unit/isolated/config.test.ts | 7 +----- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/test/integration/dist-dir/test/index.test.js b/test/integration/dist-dir/test/index.test.js index 46569866cb0a8..5a6f7f19d7f07 100644 --- a/test/integration/dist-dir/test/index.test.js +++ b/test/integration/dist-dir/test/index.test.js @@ -68,15 +68,9 @@ describe('distDir', () => { it('should build the app within the given `dist` directory', async () => { // In isolated dev build, the distDir for development is `distDir/dev` - if (process.env.__NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD === 'true') { - expect( - await fs.exists(join(__dirname, `/../dist/dev/${BUILD_MANIFEST}`)) - ).toBeTruthy() - } else { - expect( - await fs.exists(join(__dirname, `/../dist/${BUILD_MANIFEST}`)) - ).toBeTruthy() - } + expect( + await fs.exists(join(__dirname, `/../dist/dev/${BUILD_MANIFEST}`)) + ).toBeTruthy() }) it('should not build the app within the default `.next` directory', async () => { expect( diff --git a/test/integration/module-ids/test/index.test.js b/test/integration/module-ids/test/index.test.js index ba2754b891f98..d20e2a5c7ee20 100644 --- a/test/integration/module-ids/test/index.test.js +++ b/test/integration/module-ids/test/index.test.js @@ -8,10 +8,11 @@ import { launchApp, nextBuild, renderViaHTTP, + getDistDir, } from 'next-test-utils' const appDir = join(__dirname, '../') - +const originalIsNextDev = global.isNextDev let appPort let app @@ -23,9 +24,11 @@ describe('minified module ids', () => { let staticBundles = '' beforeAll(async () => { + // getDistDir depends on global.isNextDev + global.isNextDev = false await nextBuild(appDir, []) - const ssrPath = join(appDir, '.next/server/chunks/ssr/') + const ssrPath = join(appDir, `${getDistDir()}/server/chunks/ssr/`) const ssrBundleBasenames = (await fs.readdir(ssrPath)).filter((p) => p.match(/\.js$/) ) @@ -34,7 +37,7 @@ describe('minified module ids', () => { ssrBundles += output } - const staticPath = join(appDir, '.next/static/chunks/') + const staticPath = join(appDir, `${getDistDir()}/static/chunks/`) const staticBundleBasenames = (await fs.readdir(staticPath)).filter((p) => p.match(/\.js$/) ) @@ -43,6 +46,9 @@ describe('minified module ids', () => { staticBundles += output } }) + afterAll(() => { + global.isNextDev = originalIsNextDev + }) it('should have no long module ids for basic modules', async () => { expect(ssrBundles).not.toContain('module-with-long-name') @@ -72,12 +78,14 @@ describe('minified module ids', () => { let staticBundles = '' beforeAll(async () => { + // getDistDir depends on global.isNextDev + global.isNextDev = true appPort = await findPort() app = await launchApp(appDir, appPort) await renderViaHTTP(appPort, '/') - const ssrPath = join(appDir, '.next/server/chunks/ssr/') + const ssrPath = join(appDir, `${getDistDir()}/server/chunks/ssr/`) const ssrBundleBasenames = (await fs.readdir(ssrPath)).filter((p) => p.match(/\.js$/) ) @@ -86,7 +94,7 @@ describe('minified module ids', () => { ssrBundles += output } - const staticPath = join(appDir, '.next/static/chunks/') + const staticPath = join(appDir, `${getDistDir()}/static/chunks/`) const staticBundleBasenames = (await fs.readdir(staticPath)).filter((p) => p.match(/\.js$/) ) @@ -95,7 +103,10 @@ describe('minified module ids', () => { staticBundles += output } }) - afterAll(() => killApp(app)) + afterAll(() => { + global.isNextDev = originalIsNextDev + killApp(app) + }) it('should have long module ids for basic modules', async () => { expect(ssrBundles).toContain('module-with-long-name') diff --git a/test/integration/typescript-app-type-declarations/next-env.d.ts b/test/integration/typescript-app-type-declarations/next-env.d.ts index 19709046afd62..7996d352f43b1 100644 --- a/test/integration/typescript-app-type-declarations/next-env.d.ts +++ b/test/integration/typescript-app-type-declarations/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/test/integration/typescript-app-type-declarations/test/index.test.js b/test/integration/typescript-app-type-declarations/test/index.test.js index eb5a0a98b32fa..fe655be667149 100644 --- a/test/integration/typescript-app-type-declarations/test/index.test.js +++ b/test/integration/typescript-app-type-declarations/test/index.test.js @@ -8,18 +8,6 @@ const appDir = join(__dirname, '..') const appTypeDeclarations = join(appDir, 'next-env.d.ts') describe('TypeScript App Type Declarations', () => { - if (process.env.__NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD === 'true') { - it.skip('should skip on isolated dev build', () => { - // We use static fixture "next-env.d.ts" but the content should differ - // based on the isolated dev build flag. We can't do something like - // "next-env-dev.d.ts" because Next.js Types Plugin emits a file - // "next-env.d.ts", and we have to change its behavior for this test case. - // Rather than that, just skip the test as we're going to remove this flag soon. - // Then modify the content to be ".next/dev/types/routes.d.ts" - }) - return - } - it('should write a new next-env.d.ts if none exist', async () => { const prevContent = await fs.readFile(appTypeDeclarations, 'utf8') try { diff --git a/test/lib/next-test-utils.ts b/test/lib/next-test-utils.ts index 740ea159e1f31..707c445e1cf93 100644 --- a/test/lib/next-test-utils.ts +++ b/test/lib/next-test-utils.ts @@ -1893,9 +1893,7 @@ export function normalizeManifest( export function getDistDir(): '.next' | '.next/dev' { // global.isNextDev is set in e2e/development/production tests. // NEXT_TEST_MODE is set in CI or local test-* commands. - return ((global as any).isNextDev || process.env.NEXT_TEST_MODE === 'dev') && - // Flag for incremental rollout of isolated dev build, set in CI. - process.env.__NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD === 'true' + return (global as any).isNextDev || process.env.NEXT_TEST_MODE === 'dev' ? '.next/dev' : '.next' } diff --git a/test/unit/isolated/config.test.ts b/test/unit/isolated/config.test.ts index 0a2a7f519f3e6..1fdf060c32860 100644 --- a/test/unit/isolated/config.test.ts +++ b/test/unit/isolated/config.test.ts @@ -38,12 +38,7 @@ describe('config', () => { it('Should assign object defaults deeply to user config', async () => { const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, pathToConfigFn) - // In isolatedDevBuild, the default distDir is ".next/dev" during PHASE_DEVELOPMENT_SERVER. - if (process.env.__NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD === 'true') { - expect(config.distDir).toEqual('.next/dev') - } else { - expect(config.distDir).toEqual('.next') - } + expect(config.distDir.replace(/\\/g, '/')).toEqual('.next/dev') expect(config.onDemandEntries.maxInactiveAge).toBeDefined() }) From 66bb9570aed0d92fc323e7f243bb17ec18616b03 Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Tue, 7 Oct 2025 00:49:36 +0200 Subject: [PATCH 3/6] Remove flag from CI --- .github/workflows/build_and_test.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 910379a0ff8d7..6a238243182a0 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -542,9 +542,7 @@ jobs: uses: ./.github/workflows/build_reusable.yml with: nodeVersion: ${{ matrix.node }} - afterBuild: | - export __NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD=true - node run-tests.js --type unit + afterBuild: node run-tests.js --type unit stepName: 'test-unit-${{ matrix.node }}' secrets: inherit @@ -735,7 +733,6 @@ jobs: export IS_WEBPACK_TEST=1 export NEXT_TEST_MODE=dev export NEXT_TEST_REACT_VERSION="${{ matrix.react }}" - export __NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD=true node run-tests.js \ --timings \ @@ -849,7 +846,6 @@ jobs: export IS_WEBPACK_TEST=1 export NEXT_TEST_MODE=start export NEXT_TEST_REACT_VERSION="${{ matrix.react }}" - export __NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD=true node run-tests.js --timings -g ${{ matrix.group }} --type production stepName: 'test-prod-react-${{ matrix.react }}-${{ matrix.group }}' @@ -889,7 +885,6 @@ jobs: afterBuild: | export IS_WEBPACK_TEST=1 export NEXT_TEST_REACT_VERSION="${{ matrix.react }}" - export __NEXT_EXPERIMENTAL_ISOLATED_DEV_BUILD=true node run-tests.js \ --timings \ From 9d1e3ab0a764d2d4b61e5f5530ed82d8aa0fb331 Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Tue, 7 Oct 2025 13:48:26 +0200 Subject: [PATCH 4/6] dev cache at .next/dev/cache --- scripts/devlow-bench.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/devlow-bench.mjs b/scripts/devlow-bench.mjs index cd1e6b570afc9..316c3c7baab28 100644 --- a/scripts/devlow-bench.mjs +++ b/scripts/devlow-bench.mjs @@ -482,6 +482,7 @@ const nextDevWorkflow = const cacheLocation = join( benchmarkDir, '.next', + 'dev', 'cache', 'webpack', 'client-development' From e0717c1f1f12c96bfa46230156ec7041149bdad6 Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Tue, 7 Oct 2025 15:39:16 +0200 Subject: [PATCH 5/6] Remove isolatedDevBuild from test fixture --- test/development/app-dir/isolated-dev-build/next.config.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/development/app-dir/isolated-dev-build/next.config.js b/test/development/app-dir/isolated-dev-build/next.config.js index 3c6fc6116a575..807126e4cf0bf 100644 --- a/test/development/app-dir/isolated-dev-build/next.config.js +++ b/test/development/app-dir/isolated-dev-build/next.config.js @@ -1,10 +1,6 @@ /** * @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - isolatedDevBuild: true, - }, -} +const nextConfig = {} module.exports = nextConfig From f12c36228f207aab4e7ed2d29508feeaa2e57855 Mon Sep 17 00:00:00 2001 From: devjiwonchoi Date: Tue, 7 Oct 2025 15:51:30 +0200 Subject: [PATCH 6/6] Enable telemetry --- packages/next/src/build/index.ts | 4 ++ packages/next/src/telemetry/events/build.ts | 1 + .../integration/telemetry/test/config.test.js | 53 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index fd059406d324a..527f20cb65025 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -2737,6 +2737,10 @@ export default async function build( featureName: 'experimental/ppr', invocationCount: config.experimental.ppr ? 1 : 0, }, + { + featureName: 'experimental/isolatedDevBuild', + invocationCount: config.experimental.isolatedDevBuild ? 1 : 0, + }, { featureName: 'turbopackFileSystemCache', invocationCount: isFileSystemCacheEnabledForBuild(config) ? 1 : 0, diff --git a/packages/next/src/telemetry/events/build.ts b/packages/next/src/telemetry/events/build.ts index 50e1e63ab10cf..ab8d8a2970985 100644 --- a/packages/next/src/telemetry/events/build.ts +++ b/packages/next/src/telemetry/events/build.ts @@ -175,6 +175,7 @@ export type EventBuildFeatureUsage = { | 'experimental/cacheComponents' | 'experimental/optimizeCss' | 'experimental/ppr' + | 'experimental/isolatedDevBuild' | 'swcLoader' | 'swcRelay' | 'swcStyledComponents' diff --git a/test/integration/telemetry/test/config.test.js b/test/integration/telemetry/test/config.test.js index 52ca63eba0cd3..df7cd8fdb4010 100644 --- a/test/integration/telemetry/test/config.test.js +++ b/test/integration/telemetry/test/config.test.js @@ -836,6 +836,59 @@ describe('config telemetry', () => { ) } }) + + it('emits telemetry for isolatedDevBuild enabled by default', async () => { + let stderr + try { + const app = await nextBuild(appDir, [], { + stderr: true, + env: { NEXT_TELEMETRY_DEBUG: 1 }, + }) + stderr = app.stderr + + const featureUsageEvents = findAllTelemetryEvents( + stderr, + 'NEXT_BUILD_FEATURE_USAGE' + ) + expect(featureUsageEvents).toContainEqual({ + featureName: 'experimental/isolatedDevBuild', + invocationCount: 1, + }) + } catch (err) { + require('console').error('failing stderr', stderr, err) + throw err + } + }) + + it('emits telemetry for isolatedDevBuild disabled', async () => { + await fs.writeFile( + path.join(appDir, 'next.config.js'), + `module.exports = { experimental: { isolatedDevBuild: false } }` + ) + + let stderr + try { + const app = await nextBuild(appDir, [], { + stderr: true, + env: { NEXT_TELEMETRY_DEBUG: 1 }, + }) + stderr = app.stderr + + const featureUsageEvents = findAllTelemetryEvents( + stderr, + 'NEXT_BUILD_FEATURE_USAGE' + ) + expect(featureUsageEvents).toContainEqual({ + featureName: 'experimental/isolatedDevBuild', + invocationCount: 0, + }) + } catch (err) { + require('console').error('failing stderr', stderr, err) + throw err + } finally { + await fs.remove(path.join(appDir, 'next.config.js')) + } + }) } ) })