From 4a0e45a49a01533a9f8ecfa8f9c4f6320ceb5fe4 Mon Sep 17 00:00:00 2001 From: zahid emre zorbaz Date: Thu, 24 Sep 2026 12:25:48 +0300 Subject: [PATCH] fix(rolldown): run the devtools build with a production NODE_ENV "Run build with devtools" spawns `vite build` from the dev server, so the child inherits `NODE_ENV=development` that Vite set for the dev server. `vite build` keeps an already-set `NODE_ENV`, so the build kept every library's dev-only branches and the Rolldown panel analysed a development bundle. Pin `NODE_ENV=production`, which is what a plain `vite build` resolves to. Fixes #586 Co-Authored-By: Claude Opus 5.5 (1M context) --- .../rolldown/__tests__/build-runner.test.ts | 41 +++++++++++++++++++ .../src/node/rolldown/build-runner.ts | 9 +++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 packages/rolldown/src/node/rolldown/__tests__/build-runner.test.ts diff --git a/packages/rolldown/src/node/rolldown/__tests__/build-runner.test.ts b/packages/rolldown/src/node/rolldown/__tests__/build-runner.test.ts new file mode 100644 index 000000000..406fbe624 --- /dev/null +++ b/packages/rolldown/src/node/rolldown/__tests__/build-runner.test.ts @@ -0,0 +1,41 @@ +import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import { describe, expect, it, vi } from 'vitest' +import { getBuildCommand, ROLLDOWN_DEVTOOLS_ENV, startBuild } from '../build-runner' + +function fakeContext() { + const startChildProcess = vi.fn(async (_exec: unknown, meta: { id: string }) => ({ + ...meta, + status: 'running', + terminate: vi.fn(async () => {}), + getResult: vi.fn(), + })) + const context = { + cwd: '/project', + terminals: { sessions: new Map(), startChildProcess }, + } as unknown as ViteDevToolsNodeContext + return { context, startChildProcess } +} + +describe('rolldown build runner', () => { + it('builds for production even though the dev server runs with NODE_ENV=development', () => { + const { context } = fakeContext() + // The dev server sets `NODE_ENV=development`, and the spawned build + // inherits the dev server's env. Vite keeps an already-set `NODE_ENV`, + // so the build must override it to get a production bundle. + expect(getBuildCommand(context)).toEqual({ + command: 'vite', + args: ['build'], + cwd: '/project', + env: { NODE_ENV: 'production', [ROLLDOWN_DEVTOOLS_ENV]: 'true' }, + }) + }) + + it('spawns the build with the production NODE_ENV', async () => { + const { context, startChildProcess } = fakeContext() + await startBuild(context) + expect(startChildProcess).toHaveBeenCalledTimes(1) + expect(startChildProcess.mock.calls[0]![0]).toMatchObject({ + env: { NODE_ENV: 'production' }, + }) + }) +}) diff --git a/packages/rolldown/src/node/rolldown/build-runner.ts b/packages/rolldown/src/node/rolldown/build-runner.ts index 3d4e18663..e4a6eba00 100644 --- a/packages/rolldown/src/node/rolldown/build-runner.ts +++ b/packages/rolldown/src/node/rolldown/build-runner.ts @@ -43,7 +43,14 @@ export function getBuildCommand(context: ViteDevToolsNodeContext): DevToolsChild command: 'vite', args: ['build'], cwd: context.cwd ?? process.cwd(), - env: { [ROLLDOWN_DEVTOOLS_ENV]: 'true' }, + env: { + // The child inherits the dev server's env, where Vite has set + // `NODE_ENV=development`. `vite build` keeps an already-set `NODE_ENV`, + // which would keep every library's dev-only branches in the bundle, so + // pin what a plain `vite build` resolves to. + NODE_ENV: 'production', + [ROLLDOWN_DEVTOOLS_ENV]: 'true', + }, } }