Skip to content

fix(webpack): interpolate process.env more verbosely to reduce bundle size with DefinePlugin#30826

Merged
Coly010 merged 4 commits intonrwl:masterfrom
coolassassin:define-plugin-fix
Dec 11, 2025
Merged

fix(webpack): interpolate process.env more verbosely to reduce bundle size with DefinePlugin#30826
Coly010 merged 4 commits intonrwl:masterfrom
coolassassin:define-plugin-fix

Conversation

@coolassassin
Copy link
Copy Markdown
Contributor

@coolassassin coolassassin commented Apr 23, 2025

Current Behavior

When we prepare ENVs for the DefinePlugin, we are creating the process.env object.
For example:

// .env
NX_PUBLIC_VALUE1=1
NX_PUBLIC_VALUE2=2
NX_PUBLIC_VALUE3=3

As result we will have:

{
   'process.env': {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
   }
}

As a result, in the final bundle, we will replace process.env with this object.
The issue:
If I use all 3 values in my application DefinePlugin will inject this object 3 times, instead of injecting it once.
It will look like that:

const a = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE1
const b = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE2
const c = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE3

Expected Behavior

DefinePlugin injects values instead of env object in each place

const a = "1"
const b = "2"
const c = "3"

Fixes

  • fixed this issue for webpack
  • fixed this issue for storybook
  • fixed this issue for rspack

TLDR:
now we have object like so:

{
    "process.env.NX_PUBLIC_VALUE1": "1",
    "process.env.NX_PUBLIC_VALUE2": "2",
    "process.env.NX_PUBLIC_VALUE3": "3"
}

@coolassassin coolassassin requested review from a team as code owners April 23, 2025 09:55
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
nx-dev Ready Ready Preview Dec 11, 2025 3:50pm

@Coly010 Coly010 changed the title Define plugin fix fix(webpack): interpolate process.env more verbosely to reduce bundle size with DefinePlugin Apr 25, 2025
@Coly010 Coly010 force-pushed the define-plugin-fix branch from b6eabb8 to 903c22a Compare April 25, 2025 09:04
@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud bot commented Apr 25, 2025

View your CI Pipeline Execution ↗ for commit 6622631

Command Status Duration Result
nx affected --targets=lint,test,test-kt,build,e... ✅ Succeeded 5m 39s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 2m 29s View ↗
nx-cloud record -- nx-cloud conformance:check ✅ Succeeded 11s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 2s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-11 18:42:11 UTC

@coolassassin
Copy link
Copy Markdown
Contributor Author

@Coly010 could you help me. Should I try to fix this failed test, or it is just something flaky?

@coolassassin
Copy link
Copy Markdown
Contributor Author

@Coly010 I can't reproduce this bug in the job on my MacOS laptop:
image

@coolassassin
Copy link
Copy Markdown
Contributor Author

@claude can you take a look at a test? I can't reproduce it on my macOS machine

@netlify
Copy link
Copy Markdown

netlify bot commented Dec 11, 2025

👷 Deploy request for nx-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 6622631

nx-cloud[bot]

This comment was marked as outdated.

The change to define environment variables individually
(e.g., 'process.env.KEY') broke environments where the process
global doesn't exist, such as Cypress component testing.

This adds a fallback 'process.env': '{}' to handle cases where
code accesses process.env directly while maintaining the bundle
size optimization from individual key definitions.
nx-cloud[bot]

This comment was marked as outdated.

@Coly010 Coly010 enabled auto-merge (squash) December 11, 2025 17:02
Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

A new CI pipeline execution was requested that may update the conclusion below...

Nx Cloud is proposing a fix for your failed CI:

These changes fix the webpack dev server timeout by ensuring process.env property access occurs on a single line. The PR's DefinePlugin format change (defining individual keys instead of a process.env object) broke multi-line property access patterns, causing DefinePlugin to replace process.env with "{}" and then attempt property access on a string. By consolidating the property access to single lines in the runtime plugin and utility files, webpack can now correctly match and replace the full expression.

We could not verify this fix.

Suggested Fix changes
diff --git a/packages/module-federation/src/utils/plugins/runtime-library-control.plugin.ts b/packages/module-federation/src/utils/plugins/runtime-library-control.plugin.ts
index 2f34a68603..6910394ee4 100644
--- a/packages/module-federation/src/utils/plugins/runtime-library-control.plugin.ts
+++ b/packages/module-federation/src/utils/plugins/runtime-library-control.plugin.ts
@@ -10,8 +10,9 @@ const runtimeStore: {
 
 if (process.env.NX_MF_DEV_REMOTES) {
   // process.env.NX_MF_DEV_REMOTES is replaced by an array value via DefinePlugin, even though the original value is a stringified array.
-  runtimeStore.devRemotes = process.env
-    .NX_MF_DEV_REMOTES as unknown as string[];
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-ignore - Must be on single line for DefinePlugin to replace correctly
+  runtimeStore.devRemotes = process.env.NX_MF_DEV_REMOTES as unknown as string[];
 }
 
 const nxRuntimeLibraryControlPlugin: () => ModuleFederationRuntimePlugin =
diff --git a/packages/module-federation/src/with-module-federation/angular/utils.ts b/packages/module-federation/src/with-module-federation/angular/utils.ts
index 34c8b84695..ad17918414 100644
--- a/packages/module-federation/src/with-module-federation/angular/utils.ts
+++ b/packages/module-federation/src/with-module-federation/angular/utils.ts
@@ -71,8 +71,9 @@ export function getFunctionDeterminateRemoteUrl(
     : 'remoteEntry.mjs';
 
   return function (remote: string) {
-    const mappedStaticRemotesFromEnv = process.env
-      .NX_MF_DEV_SERVER_STATIC_REMOTES
+    // Must access process.env.NX_MF_DEV_SERVER_STATIC_REMOTES on single line for DefinePlugin to replace correctly
+    // prettier-ignore
+    const mappedStaticRemotesFromEnv = process.env.NX_MF_DEV_SERVER_STATIC_REMOTES
       ? JSON.parse(process.env.NX_MF_DEV_SERVER_STATIC_REMOTES)
       : undefined;
     if (mappedStaticRemotesFromEnv && mappedStaticRemotesFromEnv[remote]) {
diff --git a/packages/module-federation/src/with-module-federation/rspack/utils.ts b/packages/module-federation/src/with-module-federation/rspack/utils.ts
index b9a141eaf4..bf9752f048 100644
--- a/packages/module-federation/src/with-module-federation/rspack/utils.ts
+++ b/packages/module-federation/src/with-module-federation/rspack/utils.ts
@@ -22,8 +22,9 @@ export function getFunctionDeterminateRemoteUrl(isServer = false) {
   const remoteEntry = isServer ? 'server/remoteEntry.js' : 'remoteEntry.js';
 
   return function (remote: string) {
-    const mappedStaticRemotesFromEnv = process.env
-      .NX_MF_DEV_SERVER_STATIC_REMOTES
+    // Must access process.env.NX_MF_DEV_SERVER_STATIC_REMOTES on single line for DefinePlugin to replace correctly
+    // prettier-ignore
+    const mappedStaticRemotesFromEnv = process.env.NX_MF_DEV_SERVER_STATIC_REMOTES
       ? JSON.parse(process.env.NX_MF_DEV_SERVER_STATIC_REMOTES)
       : undefined;
     if (mappedStaticRemotesFromEnv && mappedStaticRemotesFromEnv[remote]) {
diff --git a/packages/module-federation/src/with-module-federation/webpack/utils.ts b/packages/module-federation/src/with-module-federation/webpack/utils.ts
index ae53ab1dfe..029ee8bf37 100644
--- a/packages/module-federation/src/with-module-federation/webpack/utils.ts
+++ b/packages/module-federation/src/with-module-federation/webpack/utils.ts
@@ -23,8 +23,9 @@ export function getFunctionDeterminateRemoteUrl(isServer: boolean = false) {
   const remoteEntry = isServer ? 'server/remoteEntry.js' : 'remoteEntry.js';
 
   return function (remote: string) {
-    const mappedStaticRemotesFromEnv = process.env
-      .NX_MF_DEV_SERVER_STATIC_REMOTES
+    // Must access process.env.NX_MF_DEV_SERVER_STATIC_REMOTES on single line for DefinePlugin to replace correctly
+    // prettier-ignore
+    const mappedStaticRemotesFromEnv = process.env.NX_MF_DEV_SERVER_STATIC_REMOTES
       ? JSON.parse(process.env.NX_MF_DEV_SERVER_STATIC_REMOTES)
       : undefined;
     if (mappedStaticRemotesFromEnv && mappedStaticRemotesFromEnv[remote]) {

Because this branch comes from a fork, it is not possible for us to apply fixes directly, but you can apply the changes locally using the available options below.

Apply changes locally with:

npx nx-cloud apply-locally QJYE-FuvS

Apply fix locally with your editor ↗   View interactive diff ↗


🎓 Learn more about Self-Healing CI on nx.dev

@Coly010 Coly010 merged commit 205daee into nrwl:master Dec 11, 2025
25 of 27 checks passed
FrozenPandaz pushed a commit that referenced this pull request Dec 15, 2025
… size with DefinePlugin (#30826)

## Current Behavior
When we prepare ENVs for the DefinePlugin, we are creating the
`process.env` object.
For example:
```
// .env
NX_PUBLIC_VALUE1=1
NX_PUBLIC_VALUE2=2
NX_PUBLIC_VALUE3=3
```
As result we will have:
```js
{
   'process.env': {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
   }
}
```

As a result, in the final bundle, we will replace process.env with this
object.
The issue:
If I use all 3 values in my application DefinePlugin will inject this
object 3 times, instead of injecting it once.
It will look like that:
```js
const a = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE1
const b = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE2
const c = {
      "NX_PUBLIC_VALUE1": "1",
      "NX_PUBLIC_VALUE2": "2",
      "NX_PUBLIC_VALUE3": "3"
}.NX_PUBLIC_VALUE3
```

## Expected Behavior
DefinePlugin injects values instead of env object in each place
```js
const a = "1"
const b = "2"
const c = "3"
```

## Fixes
- fixed this issue for webpack
- fixed this issue for storybook
- fixed this issue for rspack

TLDR:
now we have object like so:
```js
{
    "process.env.NX_PUBLIC_VALUE1": "1",
    "process.env.NX_PUBLIC_VALUE2": "2",
    "process.env.NX_PUBLIC_VALUE3": "3"
}
```

---------

Co-authored-by: Colum Ferry <[email protected]>
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 17, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

priority: high High Priority (important issues which affect many people severely)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants