Skip to content

Align web/no-modules WASM import namespace to enable cross-target WASM sharing#4850

Merged
guybedford merged 1 commit into
wasm-bindgen:mainfrom
magic-akari:refactor/cli-web
Dec 20, 2025
Merged

Align web/no-modules WASM import namespace to enable cross-target WASM sharing#4850
guybedford merged 1 commit into
wasm-bindgen:mainfrom
magic-akari:refactor/cli-web

Conversation

@magic-akari

@magic-akari magic-akari commented Dec 10, 2025

Copy link
Copy Markdown
Member

Description

This PR updates the WASM import namespace for the web and no-modules target to align with other targets, replacing the placeholder namespace with a relative module path.

Changes

WASM Import Namespace Change

;; Before
(import "__wbindgen_placeholder__" "__wbindgen_init_externref_table" (func ...))

;; After
(import "./reference_test.js" "__wbindgen_init_externref_table" (func ...))

Checklist

  • Verified changelog requirement

@codspeed-hq

codspeed-hq Bot commented Dec 10, 2025

Copy link
Copy Markdown

CodSpeed Performance Report

Merging #4850 will not alter performance

Comparing magic-akari:refactor/cli-web (80e34cf) with main (315cfa1)

Summary

✅ 4 untouched

@magic-akari magic-akari changed the title feat(cli): align web target's WASM interface with bundler Add --target esm to enable cross-target WASM sharing Dec 10, 2025
@magic-akari magic-akari marked this pull request as ready for review December 10, 2025 10:59
Copilot AI review requested due to automatic review settings December 10, 2025 10:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new --target esm compilation target to enable WASM file sharing across different JavaScript environments. The key motivation is backward compatibility: the original plan to modify the web target would have broken wasm-pack, which assumes --target web doesn't produce _bg.js files. The solution adds a new ESM target while preserving the original web target behavior.

Key Changes:

  • Added new --target esm that generates bundler-compatible output with _bg.js and _bg.wasm files
  • Updated WASM import namespace from "wbg" to "./{name}_bg.js" for web and no-modules targets
  • Enhanced package.json generation to include a main field for ESM and Node module targets

Reviewed changes

Copilot reviewed 48 out of 56 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
crates/cli/src/wasm_bindgen.rs Added Esm enum variant and CLI integration
crates/cli-support/src/lib.rs Added ESM output mode, package.json main field generation, and error message updates
crates/cli-support/src/js/mod.rs Implemented ESM-specific code generation with init functions and import handling
crates/cli/tests/wasm-bindgen/reference.rs Extended test to check _bg.js output for ESM target
Reference test files Added comprehensive test outputs for the new ESM target across multiple test scenarios

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

Comment thread crates/cli-support/src/lib.rs Outdated
Comment thread crates/cli/tests/reference/import-target-esm.bg.js Outdated
Comment thread crates/cli/tests/reference/wasm-export-colon-target-esm.bg.js Outdated
Comment thread crates/cli/tests/reference/wasm-export-colon-target-web.js Outdated
Comment thread crates/cli/tests/reference/wasm-export-types-target-web.js Outdated
@guybedford

Copy link
Copy Markdown
Contributor

Thank you for this PR - modernizing the targets is a major goal currently, and we've been needing this for a while.

I want to review this properly, and will make sure to do that next week, thanks for your patience.

@guybedford

Copy link
Copy Markdown
Contributor

I agree with all of the motivations here. The alignment is a huge step forward.

Currently we have the source phase form supported under --target module, which is already an "ESM Target" just a different type of ESM target.

We had the discussion when we landed that target whether to have --target source / --target instance or have a single --target module with a modifier for supporting the instance phase, and the decision was made then that a modifier would be preferred since both source and instances phase are part of the same ESM integration proposal.

Therefore I would like to suggest that we change --target esm in this PR to instead be --target module --instance as a modifier on the module target, which could be implemented as Module(InstancePhase) as opposed to Module(SourcePhase) as the default.

Let me know if that can work for you here and if that can fit into how you see this coming together?

Then as for future composable targets, I wonder if we could separate the concept of the target from the environment and start treating environment hints / feature support as separate fine-grained thing to support to modify the output. In this framing --target deno becomes --target module --env deno say, where deno implies some facts about the environment that might be specific to deno. We can continue this discussion when we get there of course!

I really appreciate your pushing this forward, will be great to land this with the small adjustment soon.

@magic-akari

magic-akari commented Dec 16, 2025

Copy link
Copy Markdown
Member Author

Thank you for the thoughtful feedback and for planning to review this properly! I'm really glad to see that we are aligned on the goal of modernizing the targets - this has been a pain point for many users and I'm eager to help move it forward.


I completely agree with the idea of separating target from environment. The environment-specific outputs (node, deno) exist primarily to provide convenience for runtimes with filesystem access - they can auto-initialize the WASM module without requiring users to manually pass the path. This is indeed an orthogonal concern from the core module format.

The --env modifier approach makes a lot of sense for this: --target module --env node,deno clearly expresses "module format + environment-specific conveniences".


Regarding --target module --instance vs --target esm:

I do have a slight concern here. As I understand it, the current --target module (SourcePhase) is more forward-looking and aligned with the ESM integration proposal, while what this PR adds is the InstancePhase variant that works in browsers, node, deno and bundlers today.

If we make SourcePhase the default for --target module, there might be some friction:

  • Most users today want "ESM that works now", which is InstancePhase
  • Requiring --instance for the common case feels a bit counterintuitive
  • The SourcePhase isn't yet widely supported

A few possible paths forward:

Option 1: Keep separate target names for now

  • --target module for SourcePhase (current behavior)
  • --target esm for InstancePhase (this PR)
  • We can unify them later when SourcePhase becomes more mainstream

Option 2: Make --instance the default

  • --target module → InstancePhase (common case, simpler)
  • --target module --source → SourcePhase (explicit opt-in for future-looking users)

Option 3: Align SourcePhase to bundler/node-module first

  • I could pivot this PR to modify the existing --target module (SourcePhase), aligning its WASM output to match --target bundler and --target experimental-nodejs-module
  • This would mean removing the new --target esm additions and applying the same WASM alignment changes to the current SourcePhase module target instead
  • Defer the InstancePhase variant discussion to a future PR when we have clearer requirements and broader ecosystem support

Option 4: Implement exactly as suggested

  • --target module remains SourcePhase (default)
  • --target module --instance enables the InstancePhase (this PR)
  • And I will change the SourcePhase module output in this PR as well to match bundler/node-module behavior

I'm open to any of these approaches - what do you think would work best for the project's direction?

@magic-akari

Copy link
Copy Markdown
Member Author

Just following up on my previous comment about Option 3 - I'm planning to start implementing that approach soon (aligning the SourcePhase WASM outputs) since it seems like a good incremental step forward. I'm still waiting for your thoughts on this path vs the others, so I'll hold off until I hear from you.

No rush at all - whenever you have a moment to share your preference, that would be really helpful. Thanks again for your guidance and insights on.

@guybedford

Copy link
Copy Markdown
Contributor

I think option 3 makes sense with the current plans, especially given that it is becoming stable across tools and we expect browsers to start supporting that form soon natively.

I'm happy to include the instance case here too, but if you want to treat that as a follow-on that is fine by me as well.

@guybedford

Copy link
Copy Markdown
Contributor

I'm assuming this PR depends on the others, but please re-request a review if this is ready.

@magic-akari magic-akari marked this pull request as draft December 19, 2025 12:50
@magic-akari magic-akari changed the title Add --target esm to enable cross-target WASM sharing Align web/no-modules WASM import namespace to enable cross-target WASM sharing Dec 19, 2025
@magic-akari magic-akari marked this pull request as ready for review December 19, 2025 18:04
guybedford pushed a commit that referenced this pull request Dec 20, 2025
Change the Node.js (CommonJS) WASM import namespace from
`__wbindgen_placeholder__` to `./{name}_bg.js`, matching the import
convention used by the `bundler` and `experimental-nodejs-module`
targets.

Changes:
* Update `generate_node_imports` to accept a `module_name` parameter.
* Replace `PLACEHOLDER_MODULE` / `__wbindgen_placeholder__` with
  `./{module_name}_bg.js` when emitting Node.js imports.
* Set the `import.module` field for WASM imports in the Node.js target to
  the same `./{module_name}_bg.js` value.

Part of the cross-target WASM sharing initiative (#4850).
@magic-akari

Copy link
Copy Markdown
Member Author

This PR is ready as well.

@guybedford guybedford merged commit f9e8377 into wasm-bindgen:main Dec 20, 2025
58 checks passed
@magic-akari magic-akari deleted the refactor/cli-web branch December 21, 2025 14:19
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.

3 participants