Skip to content

feat(javascript): add JavascriptModulesPlugin.getChunkFilenameTemplate - #15280

Open
kakiuwang-ui wants to merge 8 commits into
web-infra-dev:mainfrom
kakiuwang-ui:feat/js-modules-get-chunk-filename-template
Open

feat(javascript): add JavascriptModulesPlugin.getChunkFilenameTemplate#15280
kakiuwang-ui wants to merge 8 commits into
web-infra-dev:mainfrom
kakiuwang-ui:feat/js-modules-get-chunk-filename-template

Conversation

@kakiuwang-ui

Copy link
Copy Markdown
Contributor

Summary

Adds JavascriptModulesPlugin.getChunkFilenameTemplate(chunk, outputOptions), aligning with webpack's static method of the same name. It lets a plugin ask which filename template rspack renders a JS chunk with, instead of re-deriving that rule by hand.

The resolution order mirrors rspack's own get_js_chunk_filename_template in crates/rspack_core/src/options/output.rs:

  1. chunk.filenameTemplate, when the chunk carries its own template
  2. output.filename, when the chunk can be initial
  3. output.chunkFilename otherwise

Everything this needs was already exposed to the JS side (chunk.filenameTemplate and chunk.canBeInitial() on the napi Chunk, compilation.outputOptions), so this is a pure TypeScript addition with no binding or Rust change.

Difference from webpack

webpack has a fourth branch returning output.hotUpdateChunkFilename for HotUpdateChunk instances. Rspack keeps hot update chunks inside the Rust HMR pipeline and never surfaces them to JavaScript, so no chunk reachable from a plugin can be a hot update chunk. There is no JS-observable equivalent of chunk.kind() == ChunkKind::HotUpdate to branch on. This is called out in the docs and in a code comment — happy to expose the chunk kind and add the branch instead if you would rather keep the shape identical to webpack.

Test

Adds a configCases/hooks case covering all three branches from a single entry:

  • main — initial, no template → output.filename
  • async_js — async, no template → output.chunkFilename
  • shared-shared_js — a splitChunks cache group with filename set → its own template (this one is also initial, so it pins the branch ordering)

Besides asserting the exact templates, the case asserts the round trip: for every chunk, compilation.getPath(template, { chunk, contentHashType: "javascript" }) must be one of chunk.files. That way the test checks the returned template is genuinely the one rspack rendered with, rather than restating the implementation.

Related links

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

Aligns with webpack's JavascriptModulesPlugin.getChunkFilenameTemplate so
plugins can resolve the filename template rspack renders a JS chunk with.

Closes web-infra-dev#10012
@codspeed-hq

codspeed-hq Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 50 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing kakiuwang-ui:feat/js-modules-get-chunk-filename-template (b3654b1) with main (aa2ea64)

Open in CodSpeed

Footnotes

  1. 47 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@kakiuwang-ui

Copy link
Copy Markdown
Contributor Author

@hardfist could you approve the CI run here when you have a moment? First contribution, so the workflows need manual approval before they will start — only the Socket and CodSpeed checks have run so far (CodSpeed reports no performance change).

While it is queued, the one thing worth your call is in the description: rspack has no JS-observable equivalent of ChunkKind::HotUpdate, so this deliberately omits webpack's hotUpdateChunkFilename branch and documents the difference instead of guessing. Hot update chunks never reach compilation.chunks, so the branch is unreachable from JS either way. If you would rather expose the chunk kind on the napi Chunk and keep the shape identical to webpack, I am happy to do that instead.

@LingyuCoder

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47756a3754

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/rspack/src/builtin-plugin/JavascriptModulesPlugin.ts
Comment thread website/docs/en/plugins/javascript-modules-plugin.mdx
Comment thread website/docs/en/plugins/webpack/javascript-modules-plugin.mdx Outdated
@LingyuCoder

Copy link
Copy Markdown
Contributor

@SyMind please also take a look

@LingyuCoder
LingyuCoder requested a review from SyMind August 24, 2026 05:23
Comment thread website/docs/zh/plugins/webpack/javascript-modules-plugin.mdx Outdated
getPath and getPathWithInfo are documented as taking a `Filename`
(website/docs/en/api/javascript-api/compilation.mdx), which includes the
function form, but the TypeScript signatures only accepted a string and the
value was passed straight through to the string-only N-API method.

Evaluate the callback with the path data before rendering, matching webpack's
Compilation.getAssetPath. getAssetPath and getAssetPathWithInfo get the same
treatment for consistency.
@kakiuwang-ui

Copy link
Copy Markdown
Contributor Author

Thanks for the review @LingyuCoder — both Codex findings are real, I reproduced them. Pushed 02331fa.

Doc suggestions (both applied.)

Compilation.getPath and Filename callbacks — fixed.

Worth noting this turned out to be narrower than a new API decision: getPath and getPathWithInfo are already documented as taking a Filename (website/docs/en/api/javascript-api/compilation.mdx, which embeds Filename.ts including the function form). Only the TypeScript signature and the runtime were string-only, so the implementation was behind the documented contract rather than the contract needing to be widened.

The fix evaluates the callback with the path data before handing the result to the N-API method, matching webpack's Compilation.getAssetPath. Placeholders returned by the callback are still rendered. I applied it to getAssetPath/getAssetPathWithInfo too for consistency — happy to narrow that back to just getPath/getPathWithInfo if you would rather keep the change minimal.

New case configCases/hooks/get-path-filename-callback covers: string templates still work, a callback is evaluated and its placeholders rendered, the callback receives the path data, and all four helpers accept callbacks. I verified it fails without the fix.

Callback-valued chunk.filenameTemplate — I would like your call before implementing.

Confirmed, with splitChunks.cacheGroups.shared.filename set to a function:

emitted file CALLBACK-....js (rendered from the callback)
chunk.filenameTemplate undefined
getChunkFilenameTemplate returns [name].js — wrong

Filename::template() returns None for FilenameKind::Fn (crates/rspack_core/src/options/filename.rs:63), so the getter at chunk.rs:107 maps every callback template to undefined and my method falls through to output.filename.

Exposing it is not quite a one-liner though: a JS filename callback is stored as ThreadSafeFilenameFn wrapping a ThreadsafeFunction (crates/rspack_binding_api/src/filename.rs:51), so the original JsFunction is not retained, and calls through the tsfn are async. That leaves roughly three options:

  1. Keep an extra Ref<JsFunction> alongside the tsfn and return it — faithful and synchronous, but adds a JS reference to every chunk filename template.
  2. Return a wrapper function that calls through the tsfn — no extra retention, but it would be async, unlike webpack where the template callback is synchronous.
  3. Expose only a flag (e.g. chunk.hasFilenameTemplateFn) so getChunkFilenameTemplate can avoid silently returning the wrong template, and revisit exposing the callback later.

Option 1 looks closest to webpack to me, but it touches the binding's memory behaviour, so I did not want to pick unilaterally. Which direction do you prefer? I will implement it with tests once you decide.

One small thing: I set <ApiMeta addedVersion={'2.2.0'} />, but 2.2.0-rc.0 is already cut — should that be 2.3.0?

SyMind commented Aug 27, 2026

Copy link
Copy Markdown
Member

Thanks for the detailed investigation. I’m currently thinking through some broader filename-related design, especially how callback-valued Filename should be represented across the Rust/JavaScript boundary, and this PR overlaps with that work.

I haven’t forgotten about this PR — please give me a little more time to settle on the direction so we don’t ask you to implement something that we may need to change again. I’ll follow up here once I have a concrete recommendation. Thanks for your patience!

…late

2.2.0 shipped without this API, and the recently added compilation.runtimeTemplate
section does not carry an ApiMeta either.
@SyMind

SyMind commented Aug 28, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 75e2b5cf2c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/rspack/src/Compilation.ts Outdated
Comment thread packages/rspack/src/Compilation.ts Outdated
@SyMind

SyMind commented Aug 28, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3654b1014

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/rspack/src/Compilation.ts
@SyMind
SyMind enabled auto-merge (squash) August 28, 2026 09:55
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.

[Feature]: align with webpack: JavascriptModulesPlugin.getChunkFilenameTemplate

3 participants