Files
Niklas MischkulnigandGitHub 3f17705979 Turbopack: properly set NODE_ENV for SWC plugins (#92579)
### What?

Closes https://github.com/vercel/next.js/pull/92650
Closes https://github.com/vercel/next.js/issues/92547

When Turbopack runs SWC transform plugins, it passes a `TransformPluginMetadataContext` that includes the current `NODE_ENV`. Previously this value was hardcoded to `"development"` regardless of the actual build mode, causing SWC plugins to misbehave during production builds.

### Why?

`SwcPluginMetadataContext` is used by SWC plugins (e.g. `babel-plugin-styled-components`, `@swc/plugin-emotion`) to conditionally produce development vs. production output — for instance, injecting display names and data attributes only in development. With `NODE_ENV` always set to `"development"`, plugins could never produce their optimised production output, resulting in larger bundles and missing minification in `next build`.

Fixes https://github.com/vercel/next.js/issues/92547

### How?

`NODE_ENV` is now derived from the `process.env.NODE_ENV` compile-time define that is already part of `CompileTimeInfo` (the same source of truth used for dead-code elimination). The resolution happens in `EcmascriptModuleAsset::parse()` via a new shared helper `node_env_from_compile_time_info()` in `parse.rs`, and the value is stored on `TransformContext` so every `CustomTransformer` implementation can read it from `ctx.node_env` without needing access to the broader compilation context.

Key design decisions:

- **`TransformContext`** is the right place: it is the per-file context passed to every `CustomTransformer::transform()` call, so storing `node_env` there follows the existing pattern and avoids coupling the plugin struct to the build mode.
- **Webpack analysis path**: `compile_time_info` is now threaded through `webpack_runtime()`, `module_references()`, and the webpack reference structs (`WebpackModuleAsset`, `WebpackChunkAssetReference`, `WebpackEntryAssetReference`, `WebpackRuntimeAssetReference`) so that webpack-bundled files with SWC plugin transforms also receive the correct `NODE_ENV`.
- **`segment_config.rs`**: passes a placeholder but includes a comment explaining it is irrelevant since `EcmascriptInputTransforms::empty()` means no transforms run.

<!-- NEXT_JS_LLM_PR -->
2026-04-15 14:55:20 +02:00

19 lines
522 B
TypeScript

import { nextTestSetup } from 'e2e-utils'
describe('swc-plugins-env', () => {
const { next, skipped, isNextDev } = nextTestSetup({
files: __dirname,
skipDeployment: true,
})
if (skipped) return
it('should pass correct environment to swc plugins', async () => {
const $ = await next.render$('/')
if (isNextDev) {
expect($('main').text()).toBe('The SWC plugin received env=development')
} else {
expect($('main').text()).toBe('The SWC plugin received env=production')
}
})
})