Skip to content

refactor: switch asset module support from hard-code to builtin plugin#8546

Merged
graphite-app[bot] merged 1 commit intomainfrom
03-05-refactor_support_asset_module_using_plugin
Mar 6, 2026
Merged

refactor: switch asset module support from hard-code to builtin plugin#8546
graphite-app[bot] merged 1 commit intomainfrom
03-05-refactor_support_asset_module_using_plugin

Conversation

@hyf0
Copy link
Member

@hyf0 hyf0 commented Mar 4, 2026

No description provided.

Copy link
Member Author

hyf0 commented Mar 4, 2026


How to use the Graphite Merge Queue

Add the label graphite: merge-when-ready to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@netlify
Copy link

netlify bot commented Mar 4, 2026

Deploy Preview for rolldown-rs ready!

Name Link
🔨 Latest commit 290a715
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/69aaf01a4979870009f10c6c
😎 Deploy Preview https://deploy-preview-8546--rolldown-rs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@hyf0 hyf0 force-pushed the 03-05-refactor_support_asset_module_using_plugin branch from aeb89e3 to 2202297 Compare March 5, 2026 02:32
@hyf0 hyf0 changed the title refactor: support asset module using plugin refactor: switch asset module support from hard-code to builtin plugin Mar 5, 2026
@hyf0 hyf0 marked this pull request as ready for review March 5, 2026 02:36
Copilot AI review requested due to automatic review settings March 5, 2026 02:36
@hyf0 hyf0 marked this pull request as draft March 5, 2026 02:39
Copy link
Contributor

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

This PR refactors rolldown’s handling of ModuleType::Asset by removing hardcoded core support and replacing it with a built-in Rust plugin (rolldown_plugin_asset_module), aligning asset behavior with existing built-in plugin patterns (e.g. copy-module) and routing asset emission/path resolution through the plugin + FileEmitter.

Changes:

  • Add rolldown_plugin_asset_module implementing load + renderChunk to emit assets and rewrite __ROLLDOWN_ASSET__#<ref_id> placeholders to relative output paths.
  • Remove legacy core asset pipeline (AssetView, AssetGenerator, per-chunk asset preliminary filename tables) and add a FileEmitter bridge for new URL(..., import.meta.url) finalization.
  • Extend plugin load args with asserted_module_type and wire it through the loader, plus update relevant snapshots.

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
meta/design/plugin-asset-module.md Design notes for the new built-in asset module plugin and behavior changes.
crates/rolldown_plugin_asset_module/src/lib.rs New built-in plugin that loads asset modules, emits files, and rewrites placeholders in renderChunk.
crates/rolldown_plugin_asset_module/Cargo.toml Declares the new plugin crate and dependencies.
crates/rolldown_plugin/src/types/hook_load_args.rs Adds asserted_module_type to load hook args.
crates/rolldown_plugin/src/plugin_context/plugin_context.rs Exposes associate_module_with_emitted_file on PluginContext.
crates/rolldown_plugin/src/plugin_context/native_plugin_context.rs Plumbs associate_module_with_emitted_file into the native context implementation.
crates/rolldown_common/src/module/normal_module.rs Removes asset_view from NormalModule.
crates/rolldown_common/src/lib.rs Stops re-exporting removed asset-related types/mutations.
crates/rolldown_common/src/file_emitter.rs Adds module_to_emitted_file mapping + accessors for new URL() finalization.
crates/rolldown_common/src/ecmascript/ecma_view.rs Removes the old ImportMetaRolldownAssetReplacer mutation.
crates/rolldown_common/src/chunk/mod.rs Removes per-chunk asset preliminary filename maps.
crates/rolldown_common/src/asset/mod.rs Empties the old asset module (asset view removed).
crates/rolldown_common/src/asset/asset_view.rs Deletes AssetView.
crates/rolldown_binding/src/options/plugin/binding_callable_builtin_plugin.rs Updates load hook invocation to pass asserted_module_type: None.
crates/rolldown/tests/snapshots/integration_rolldown__filename_with_hash.snap Updates expected output filenames/hashes due to new asset pipeline.
crates/rolldown/tests/rolldown/topics/new_url/should_prefer_relative/artifacts.snap Snapshot updates for new URL asset path rewriting.
crates/rolldown/tests/rolldown/topics/new_url/nested_dirs/artifacts.snap Snapshot updates for new URL + chunk layout changes.
crates/rolldown/tests/rolldown/topics/new_url/binary_asset/artifacts.snap Snapshot updates for binary asset emission via plugin.
crates/rolldown/tests/rolldown/function/module_types/issue-6345/artifacts.snap Snapshot updates reflecting new CJS interop wrapping for assets.
crates/rolldown/tests/rolldown/function/module_types/asset/artifacts.snap Snapshot updates for ./-prefixed relative paths and placeholder rewriting.
crates/rolldown/tests/esbuild/loader/loader_file_relative_path_js/artifacts.snap Snapshot updates for relative path computation.
crates/rolldown/tests/esbuild/loader/loader_file_relative_path_asset_names_js/artifacts.snap Snapshot updates for relative path computation with assetNames.
crates/rolldown/tests/esbuild/loader/loader_file_public_path_js/artifacts.snap Snapshot updates for asset URL outputs.
crates/rolldown/tests/esbuild/loader/loader_file_public_path_asset_names_js/artifacts.snap Snapshot updates for asset URL outputs with assetNames.
crates/rolldown/tests/esbuild/loader/loader_file_one_source_two_different_output_paths_js/artifacts.snap Snapshot updates for shared asset emission naming/hash changes.
crates/rolldown/tests/esbuild/loader/loader_file_multiple_no_collision/artifacts.snap Snapshot updates reflecting new emission/wrapping behavior.
crates/rolldown/tests/esbuild/loader/loader_file_ext_path_asset_names_js/artifacts.snap Snapshot updates for path rewriting in nested output paths.
crates/rolldown/tests/esbuild/loader/loader_file_common_js_and_es6/artifacts.snap Snapshot updates for mixed ESM/CJS interop behavior.
crates/rolldown/tests/esbuild/loader/loader_file/artifacts.snap Snapshot updates for basic asset loader output.
crates/rolldown/src/utils/parse_to_ecma_ast.rs Removes ModuleType::Asset preprocessing; errors if asset reaches AST parsing.
crates/rolldown/src/utils/load_source.rs Passes asserted_module_type into load hook and errors when asset type isn’t handled by plugin.
crates/rolldown/src/utils/apply_inner_plugins.rs Registers the new built-in asset module plugin.
crates/rolldown/src/stages/generate_stage/render_chunk_to_assets.rs Removes asset chunk generation path.
crates/rolldown/src/stages/generate_stage/mod.rs Removes asset filename patching pipeline and related imports.
crates/rolldown/src/module_loader/runtime_module_task.rs Drops asset_view initialization.
crates/rolldown/src/module_loader/module_task.rs Removes ModuleType::AssetAssetView conversion; CSS error path remains.
crates/rolldown/src/module_finalizers/mod.rs Switches new URL() finalization to use FileEmitter module→refId bridge.
crates/rolldown/src/asset/mod.rs Removes now-unused asset module helpers.
crates/rolldown/src/asset/asset_generator.rs Deletes old asset generator implementation.
crates/rolldown/Cargo.toml Adds dependency on rolldown_plugin_asset_module.
Cargo.toml Adds the new plugin crate to the workspace dependencies.
Cargo.lock Locks the new crate into the dependency graph.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2026

Benchmarks Rust

  • target: main(36b69d8)
  • pr: 03-05-refactor_support_asset_module_using_plugin(8648d12)
group                                                        pr                                     target
-----                                                        --                                     ------
bundle/bundle@multi-duplicated-top-level-symbol              1.00     74.4±1.40ms        ? ?/sec    1.04     77.4±1.63ms        ? ?/sec
bundle/bundle@multi-duplicated-top-level-symbol-sourcemap    1.00     82.4±1.25ms        ? ?/sec    1.03     84.9±1.39ms        ? ?/sec
bundle/bundle@rome_ts                                        1.01    160.8±4.69ms        ? ?/sec    1.00    159.9±3.46ms        ? ?/sec
bundle/bundle@rome_ts-sourcemap                              1.00    177.3±2.88ms        ? ?/sec    1.01    178.7±8.11ms        ? ?/sec
bundle/bundle@threejs                                        1.00     75.3±2.94ms        ? ?/sec    1.03     77.2±2.83ms        ? ?/sec
bundle/bundle@threejs-sourcemap                              1.02     83.5±0.95ms        ? ?/sec    1.00     81.6±1.19ms        ? ?/sec
bundle/bundle@threejs10x                                     1.00   779.4±12.95ms        ? ?/sec    1.00    782.2±4.98ms        ? ?/sec
bundle/bundle@threejs10x-sourcemap                           1.00    895.7±5.23ms        ? ?/sec    1.00    894.5±4.78ms        ? ?/sec
scan/scan@rome_ts                                            1.00     73.7±1.56ms        ? ?/sec    1.00     73.4±1.57ms        ? ?/sec
scan/scan@threejs                                            1.02     26.9±0.57ms        ? ?/sec    1.00     26.3±0.38ms        ? ?/sec
scan/scan@threejs10x                                         1.01    260.3±3.35ms        ? ?/sec    1.00    256.9±2.36ms        ? ?/sec

@hyf0 hyf0 force-pushed the 03-05-refactor_support_asset_module_using_plugin branch from 2202297 to 0c41e9c Compare March 6, 2026 03:17
@hyf0 hyf0 marked this pull request as ready for review March 6, 2026 03:21
Copilot AI review requested due to automatic review settings March 6, 2026 03:21
Copy link
Contributor

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

Copilot reviewed 41 out of 42 changed files in this pull request and generated 6 comments.

@IWANABETHATGUY
Copy link
Member

IWANABETHATGUY commented Mar 6, 2026

I noticed the refactor changed some integration snapshots, and some of them even changed the exportsKind. https://github.com/rolldown/rolldown/pull/8546/changes#diff-427ad4271a3fd349fd9ed981f26e4f0804e4d1795461fb288a01b4245b563291

@hyf0
Copy link
Member Author

hyf0 commented Mar 6, 2026

I noticed the refactor changed some integration snapshots, and some of them even changed the exportsKind. https://github.com/rolldown/rolldown/pull/8546/changes#diff-427ad4271a3fd349fd9ed981f26e4f0804e4d1795461fb288a01b4245b563291

I'm updating design to cover this part, but it's expected. The plugin version so far can't use the hasLazyExports mechanism, we have to decide the export type in the load hook.

The bottom line is that no runtime behavior change

@IWANABETHATGUY
Copy link
Member

I noticed the refactor changed some integration snapshots, and some of them even changed the exportsKind. https://github.com/rolldown/rolldown/pull/8546/changes#diff-427ad4271a3fd349fd9ed981f26e4f0804e4d1795461fb288a01b4245b563291

I'm updating design to cover this part, but it's expected. The plugin version so far can't use the hasLazyExports mechanism, we have to decide the export type in the load hook.

The bottom line is that no runtime behavior change

Yeah, __esmMin could simulate the lazy eval behavior, then the only downside is that it would increase the output size.

@hyf0 hyf0 force-pushed the 03-05-refactor_support_asset_module_using_plugin branch from 0c41e9c to 8648d12 Compare March 6, 2026 05:24
@hyf0
Copy link
Member Author

hyf0 commented Mar 6, 2026

I noticed the refactor changed some integration snapshots, and some of them even changed the exportsKind. https://github.com/rolldown/rolldown/pull/8546/changes#diff-427ad4271a3fd349fd9ed981f26e4f0804e4d1795461fb288a01b4245b563291

### Options Considered
**Option 1: `export default "..."` (ESM) — Rejected**
- ESM imports: optimal, zero wrapping overhead
- `new URL()` only: works (valid ESM syntax when inlined as dead code)
- CJS `require()`: **runtime behavior change** — returns `{ __esModule: true, default: "..." }` instead of the string directly, because `__toCommonJS` wraps the ESM namespace
- Rejected: CJS correctness is important and this breaks `require()` consumers
**Option 2: `module.exports = "..."` (CJS) — Chosen**
- CJS `require()`: correct, `__commonJSMin` returns `module.exports` directly (the string)
- ESM imports: works via `__toESM` interop, adds small wrapping overhead
- `new URL()` only: **safe** — the load hook returns `side_effects: false`, so when nothing imports from the module (only `new URL()` references), tree-shaking excludes the module's statements entirely. The `module.exports` line never appears in output. Without `side_effects: false`, the CJS wrapper would be tree-shaken (nothing calls `require_asset()`) but the bare `module.exports` assignment would remain as a side-effectful top-level statement, causing `ERR_AMBIGUOUS_MODULE_SYNTAX` in ESM contexts.
- Chosen: CJS correctness preserved, ESM works with minor overhead, `new URL()` is safe
**Option 3: `has_lazy_export` via plugin API (future)**
- Would need a new plugin architecture feature — e.g. `LoadOutput::LazyDefaultExportExpr`, a special return type in the Rust load hook that lets the plugin return a raw expression without committing to `export default` or `module.exports`
- The linker would then defer the wrapping decision as before via `generate_lazy_export`
- This would restore optimal zero-overhead ESM imports while keeping CJS correct
- Future consideration to close the remaining ESM overhead gap
### Decision
**Use `module.exports = "..."` (Option 2).** This preserves CJS `require()` correctness — the returned value is the string directly, matching the old built-in behavior. ESM `import` works correctly via `__toESM` interop with a small overhead. The `new URL()` only case is safe because the CJS wrapper is tree-shaken when nothing references it.
The remaining ESM overhead gap (compared to the old `has_lazy_export` approach) can be addressed in the future through Option 3 — a `LoadOutput::LazyDefaultExportExpr` plugin API that defers the wrapping decision to the linker.

Copy link
Member Author

hyf0 commented Mar 6, 2026

Merge activity

@graphite-app graphite-app bot force-pushed the 03-05-refactor_support_asset_module_using_plugin branch from 8648d12 to 290a715 Compare March 6, 2026 15:17
@graphite-app graphite-app bot merged commit 290a715 into main Mar 6, 2026
33 checks passed
@graphite-app graphite-app bot deleted the 03-05-refactor_support_asset_module_using_plugin branch March 6, 2026 15:29
@github-actions github-actions bot mentioned this pull request Mar 9, 2026
shulaoda added a commit that referenced this pull request Mar 9, 2026
## [1.0.0-rc.8] - 2026-03-09

### 🚀 Features

- watch: enable full functional fs watcher in wasm (#8575) by @hyf0
- watch: expose debounce related options (#8572) by @hyf0

### 🐛 Bug Fixes

- detect new URL(…, import.meta.url) with no-sub template literal (#8565) by @char
- devtools: trace dynamic imports in devtools (#8581) by @cal-gooo
- watch: rebuild when a previously missing file is created (#8562) by @hyf0-agent
- watch: filter out Access events to prevent infinite rebuild loop on Linux (#8557) by @hyf0-agent

### 🚜 Refactor

- watch: remove auto watch for fail imports (#8585) by @hyf0
- fs_watcher: unify the way of constructing watcher (#8571) by @hyf0
- cli: migrate CLI to CAC (#8551) by @h-a-n-a
- switch asset module support from hard-code to builtin plugin (#8546) by @hyf0

### 📚 Documentation

- fix subject-verb agreement in why-bundlers.md (#8591) by @brandonzylstra
- maintenance: align release and canary workflow guide (#8538) by @minsoo-web
- add `format` option to directives example config (#8590) by @shulaoda
- fix: change twitter to x logo in team (#8552) by @mdong1909
- correct composable filter support explanation (#8550) by @sapphi-red

### ⚡ Performance

- testing: share tokio runtime across fixture tests (#8567) by @Boshen

### 🧪 Testing

- hmr: fix infinite loop in dev server test retry logic (#8576) by @hyf0-agent
- cli: add more cli-e2e test cases (#8548) by @h-a-n-a

### ⚙️ Miscellaneous Tasks

- docs: update in-depth/directives for `output.strict` option (#8535) by @minsoo-web
- add PNPM_HOME Dev Drive mapping to Windows CI workflows (#8589) by @Boshen
- deps: update github-actions (#8588) by @renovate[bot]
- move Windows cargo target dir to Dev Drive (#8586) by @Boshen
- optimize cache keys to fix race conditions and reduce usage (#8578) by @Boshen
- remove WASI build & test pipeline (#8580) by @Boshen
- remove unnecessary submodule checkouts (#8577) by @Boshen
- use Dev Drive for Windows CI jobs (#8574) by @Boshen
- skip redundant native binding build for browser and remove standalone job (#8573) by @Boshen
- parallelize Node tests on ubuntu, single Node 24 on macOS/windows (#8570) by @Boshen
- docs: bump @voidzero-dev/vitepress-theme to 4.8.0 (#8558) by @crusty-voidzero
- dedupe type-check from dev server workflow (#8554) by @Boshen

### ❤️ New Contributors

* @brandonzylstra made their first contribution in [#8591](#8591)
* @char made their first contribution in [#8565](#8565)
* @cal-gooo made their first contribution in [#8581](#8581)
* @hyf0-agent made their first contribution in [#8562](#8562)
* @h-a-n-a made their first contribution in [#8551](#8551)

Co-authored-by: shulaoda <165626830+shulaoda@users.noreply.github.com>
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