Skip to content

[BUGFIX] rsbuild: handle plugin version - #773

Draft
Gladorme wants to merge 1 commit into
perses:mainfrom
Gladorme:versioning-lock
Draft

[BUGFIX] rsbuild: handle plugin version#773
Gladorme wants to merge 1 commit into
perses:mainfrom
Gladorme:versioning-lock

Conversation

@Gladorme

@Gladorme Gladorme commented Aug 19, 2026

Copy link
Copy Markdown
Member

Description

In spec of plugin we can define "metadata" (version + registry) and when I wanted to implement it on frontside, I got some issue when there is multiple instances of a same plugin with different versions.

Makes plugin builds version-aware so multiple versions of the same plugin can be installed and loaded side by side. Previously only the latest installed version of a plugin was actually loadable — any other version either failed to load or silently rendered the latest one's code.

1. Version in the asset prefix

getPublicPath now returns /plugins/<name>~<version>/ instead of /plugins/<name>/. The version is read from the plugin's package.json at build time.

Why: a manifest fetched from /plugins/<name>~<version>/mf-manifest.json resolved its (relative) remoteEntry against the version-less prefix. The server maps a path with no ~version to LatestVersion, so an older version requested the latest version's directory. Since chunk filenames are content-hashed, the file didn't exist there:

RUNTIME-008 ScriptNetworkError resourceUrl: /plugins/TimeSeriesChart/__mf/js/TimeSeriesChart.7c5da441.js (404)

This also explains why the newest version always appeared to work, and why an older version worked right up until a newer archive was dropped in.

2. Version in the Module Federation container global name

Sets library: { type: 'global', name: '<Name>_<version>' }, so the manifest's globalName is unique per version.

Why: MF resolves a remote's container via globalThis[globalName], taken from the manifest (assignRemoteInfo in @module-federation/runtime-core), and loadEntryScript early-returns an already-registered container:

  const { entryExports } = getRemoteEntryExports(name, globalName);
  if (entryExports) return entryExports;

With every version sharing the global name, the first version loaded won and later versions silently reused its container without ever fetching their own entry.

3. Version in the webpack chunk registry

Sets output.uniqueName and output.chunkLoadingGlobal to chunk_<Name>_<version>.

Why: async chunks register into a shared global array:

  (self.chunk_TimeSeriesChart = self.chunk_TimeSeriesChart || []).push([["53"], { 10985(...) }])

When two versions share that global, the second one pushes its chunks into the runtime the first installed, and because module IDs are deterministic they collide: both versions resolve to the first one's modules. chunkLoadingGlobal is set explicitly because rspack derives it from uniqueName before the tools.rspack hook runs, so setting uniqueName alone is not enough.

Plugins must be rebuilt for this to take effect; it is not retroactive for already-published archives
I did not handle registry name to have super long name, because I am not sure it will happen often 🙏
I guess if someone has the issue, he can change plugin name as quick win/fix

Checklist

  • Pull request has a descriptive title and context useful to a reviewer.
  • Pull request title follows the [<catalog_entry>] <commit message> naming convention using one of the
    following catalog_entry values: FEATURE, ENHANCEMENT, BUGFIX, BREAKINGCHANGE, DOC,IGNORE.
  • All commits have DCO signoffs.

UI Changes

  • Changes that impact the UI include screenshots and/or screencasts of the relevant changes.
  • Code follows the UI guidelines.

@Gladorme Gladorme changed the title [BUGFIX] rsbuild: Add plugin version in asset prefix [BUGFIX] rsbuild: handle plugin version Aug 19, 2026
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
Comment thread rsbuild.shared.ts
if (process.env.NODE_ENV !== 'development') {
config.output.publicPath = 'auto';
}
// Isolate each version's webpack runtime.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this probably is not needed as we should use the path, regardless if the chunk has the same name

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.

2 participants