Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: walk define arguments in harmony modules (fixes #17063)#20542

Open
aryanraj45 wants to merge 1 commit intowebpack:mainfrom
aryanraj45:fix/define-harmony-import-binding
Open

fix: walk define arguments in harmony modules (fixes #17063)#20542
aryanraj45 wants to merge 1 commit intowebpack:mainfrom
aryanraj45:fix/define-harmony-import-binding

Conversation

@aryanraj45
Copy link
Contributor

Fixes #17063
Summary

In harmony (ESM) mode, HarmonyDetectionParserPlugin blocks AMD processing by returning true from a skipInHarmony tap on hooks.call.for("define"). This bail-out happens before the parser walks expression.arguments, so import bindings inside define() callbacks are never renamed causing a ReferenceError at runtime.

Example that was broken:

import { foo } from "./foo.js";

define(["dep"], function () {
    foo(); // ReferenceError: foo is not defined
});

Webpack correctly renames foo everywhere else, but skips it here because skipInHarmony bails walkCallExpression before it reaches the arguments.

Fix: add a stage: -1 tap on hooks.call.for("define") that walks expression.arguments before skipInHarmony (stage 0) fires. This ensures bindings are renamed, while AMD processing is still correctly skipped in harmony mode.

What kind of change does this PR introduce?

fix

Did you add tests for your changes?

Yes. Added test/cases/parsing/issue-17063/ — an ESM file that imports a binding and calls it inside define(). Without the fix this throws ReferenceError. With the fix it passes.

Also added test/configCases/target/web-webworker/ and test/configCases/target/web-webworker-auto-public-path/ which were previously missing coverage for the ["web", "webworker"] target combination.

Does this PR introduce a breaking change?

No. The fix only activates when HarmonyExports.isEnabled() is true (ESM files). Plain CJS files are unaffected.

If relevant, what needs to be documented once your changes are merged?

No documentation needed. This is a silent runtime bug fix with no API or config changes.]

@changeset-bot
Copy link

changeset-bot bot commented Feb 25, 2026

⚠️ No Changeset found

Latest commit: e061c66

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@alexander-akait
Copy link
Member

Wrong solution, no define in ECMA modules

@aryanraj45
Copy link
Contributor Author

yeah yeah totally Agree, define has no special meaning in ESM.
But the concern is how the parser handles it in ESM it's just a regular identifier, so shouldn't the parser still walk its arguments like any other function call?
Right now skipInHarmony bails before walking the AST, so import bindings inside the callback never get renamed and webpack silently emits broken output.

Would it make sense to just walk the arguments without treating it as AMD at all?

@alexander-akait
Copy link
Member

We should not just handle it

@aryanraj45
Copy link
Contributor Author

okay how about we would a build warning like "define is not supported in EcmaScript modules" work? So webpack actively flags it instead of silently emitting broken output

@alexander-akait
Copy link
Member

We should output nothing, define is just a function in ECMA modules, and we should not break code too

@aryanraj45 aryanraj45 force-pushed the fix/define-harmony-import-binding branch from 7601dc9 to ac46443 Compare February 25, 2026 21:23
@aryanraj45
Copy link
Contributor Author

Thanks for the suggestion Alexander Since define behaves like a regular function in ESM, I’ve removed the Stage -1 hack and updated the logic to simply walk through its arguments so any import bindings inside it don’t break, and then return true to prevent the AMD plugin from processing it.

optimization: {
minimize: false
}
};
Copy link
Member

Choose a reason for hiding this comment

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

Please avoid pushing not related things

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so so sorry actually webworker one was my another test for the upcoming PR by mistake it came under this branch and pushed in this commit .will surely take care of this in future also I have fixed it and kept only [test/cases/parsing/issue-17063/]

@aryanraj45 aryanraj45 force-pushed the fix/define-harmony-import-binding branch from ac46443 to 8311efc Compare February 25, 2026 22:25
@aryanraj45
Copy link
Contributor Author

@alexander-akait can u please review once again whenever u have a moment
thank you

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 27, 2026

Merging this PR will not alter performance

✅ 144 untouched benchmarks


Comparing aryanraj45:fix/define-harmony-import-binding (bd8eb04) with main (b8e9b05)

Open in CodSpeed

@alexander-akait
Copy link
Member

Tests are failed, we need improve logic here

@aryanraj45
Copy link
Contributor Author

Tests are failed, we need improve logic here

I think the CI is failing because we're blocking the AMD plugin from processing define. Would it be okay if I just stop skipping define in ESM and let the AMD plugin handle it naturally?

@aryanraj45 aryanraj45 force-pushed the fix/define-harmony-import-binding branch from 8311efc to bd8eb04 Compare February 28, 2026 13:30
@alexander-akait
Copy link
Member

I don't know, that is why it is a bug, it requires investigate

@aryanraj45
Copy link
Contributor Author

I know we usually avoid define in ESM, but blocking it actually breaks about 25+ existing tests that seem to mix both. Letting the AMD plugin handle it naturally fixes the bug (#17063) and keeps the CI green (coz i have tested locally both 45/45 test passed and even the new test case which I added in my latest push). Can we trigger a re-run to check? Thanks!

@aryanraj45 aryanraj45 force-pushed the fix/define-harmony-import-binding branch from bd8eb04 to e061c66 Compare March 1, 2026 18:10
Copilot AI review requested due to automatic review settings March 1, 2026 18:10
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a Harmony (ESM) parsing edge case where define(...) calls were bailing out before their arguments were walked, preventing imported bindings used inside define() callbacks from being renamed and causing runtime ReferenceErrors.

Changes:

  • Add a pre-bail (stage -1) define call hook in HarmonyDetectionParserPlugin to walk expression.arguments in Harmony mode.
  • Add regression tests covering an ESM import referenced inside a define() callback.
  • Add a configCase covering the same scenario in the configCases harness.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/dependencies/HarmonyDetectionParserPlugin.js Walks define() call arguments in Harmony mode before the existing “skip in harmony” bail-out runs.
test/cases/parsing/issue-17063/index.js Regression test ensuring an imported binding used inside define() callback is correctly renamed.
test/cases/parsing/issue-17063/foo.js Fixture module returning a value used by the regression test.
test/configCases/amd/define-harmony-import/index.js ConfigCase reproduction asserting the imported default binding is usable inside define() callback.
test/configCases/amd/define-harmony-import/lib.js Fixture default export used by the configCase.
test/configCases/amd/define-harmony-import/webpack.config.js Minimal config for the new configCase.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +102 to +108
parser.hooks.call
.for("define")
.tap({ name: PLUGIN_NAME, stage: -1 }, (expression) => {
if (HarmonyExports.isEnabled(parser.state) && expression.arguments) {
parser.walkExpressions(expression.arguments);
}
});
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

PR description says it also adds test/configCases/target/web-webworker/ and test/configCases/target/web-webworker-auto-public-path/, but those directories/files don't appear in the changes. Please either include those missing test additions or update the PR description so it matches what’s actually in the diff.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

import binding not linked in define function

3 participants