Skip to content

[2.x] fix: load each extension's lazy chunks from its own build - #5085

Merged
imorland merged 1 commit into
2.xfrom
im/chunk-id-collisions
Oct 4, 2026
Merged

imorland merged 1 commit into
2.xfrom
im/chunk-id-collisions

Conversation

@imorland

@imorland imorland commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Fixes #5027

Changes proposed in this pull request:

Webpack chunk ids are only unique within one build, but the export registry looked chunks up by id alone and every build shared one JSONP array, so two extensions with the same chunk id loaded each other's file, or failed with TypeError: r[e] is not a function once one of them had loaded. This gives each build its own chunk array, has each runtime tell the registry which extension is asking, and makes the registry resolve chunks by extension and id. Thanks to @datlechin for the analysis in the issue, which this follows.

  • js-packages/webpack-config: output.chunkLoadingGlobal is now webpackChunk_<extension id>, and the __webpack_require__.l override passes the extension id to flarum.reg.loadChunk().
  • framework/core/js/src/common/ExportRegistry.ts: chunks are resolved by namespace:chunkId; getChunk(), chunkUrl() and loadChunk() take the namespace as an optional last argument. Bundles built with an older flarum-webpack-config send none, so for them a colliding chunk is matched by the file name in the URL webpack built, then falls back to the first registered as before. The public chunks map keeps its old meaning.

Reviewers should focus on:

  • The fallback for bundles built before this. Already-published third-party extensions still share one JSONP array with each other until they rebuild against a released flarum-webpack-config, so a flarum-webpack-config release is needed after merge. They no longer share it with core or the bundled extensions, so collisions like core and fof/oauth both using chunk 170 today are fixed straight away.
  • The chunk loading global name: the extension id with non-identifier characters replaced by _.

Screenshot

N/A, no user-facing change.

Necessity

  • Has the problem that is being solved here been clearly explained?
  • If applicable, have various options for solving this problem been considered?
  • For core PRs, does this need to be in core, or could it be in an extension?
  • Are we willing to maintain this for years / potentially forever?

Confirmed

  • Frontend changes: tested on a local Flarum installation.
  • Frontend changes: tests are green (run yarn test in js/).
  • Frontend changes: tests have been added, or are not appropriate here.
  • Backend changes: tests are green (run composer test). (No backend changes.)
  • Backend changes: tests have been added, or are not appropriate here. (No backend changes.)
  • Where applicable, changes are suitable for all supported database drivers (MySQL, MariaDB, PostgreSQL, SQLite). (Not applicable, no database changes.)
  • Core developer confirmed locally this works as intended.
  • The description above is written by me and describes what this pull request actually does.

Webpack chunk ids are only unique within one build, but the export registry
resolved chunks by id alone, and every build shared one JSONP array
(`webpackChunkmodule_exports`). Two extensions with the same chunk id
therefore loaded each other's file, or, once one had loaded, the other's
import resolved with no request and failed with "r[e] is not a function".

- flarum-webpack-config gives each build its own chunk loading global,
  `webpackChunk_<extension id>`, and passes the extension id to
  `flarum.reg.loadChunk()`.
- The registry resolves chunks by namespace and id. Bundles built before
  this send no namespace; for them a colliding chunk is matched by the file
  name in the URL webpack built, then falls back to the first registered,
  as before.

Fixes #5027
@imorland
imorland requested a review from a team as a code owner October 4, 2026 12:39
@imorland imorland changed the title fix: load each extension's lazy chunks from its own build [2.x] fix: load each extension's lazy chunks from its own build Oct 4, 2026
@imorland imorland added this to the 2.0-pre milestone Oct 4, 2026
@imorland
imorland merged commit e20d30b into 2.x Oct 4, 2026
30 checks passed
@imorland
imorland deleted the im/chunk-id-collisions branch October 4, 2026 12:51
@imorland imorland mentioned this pull request Oct 4, 2026
5 of 12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chunk id collisions between extensions: ExportRegistry.chunks is not keyed by namespace

1 participant