fix: prevent circular dependency via asset file imports in shared mod…#891
Merged
gioboa merged 5 commits intoJul 10, 2026
Merged
Conversation
Contributor
|
Hi! Could this also cover query/hash-suffixed asset specifiers here? Vite commonly supports asset imports such as: @ui-lib/assets/icon.svg?url
@ui-lib/assets/logo.png?raw
@ui-lib/assets/style.css?inlineThe new regex is anchored with $, so it only seems to match specifiers that end directly with the asset extension. |
commit: |
Contributor
Author
|
@dmchoi77 u are right. I have changed tests and the wildcard: - /\.(?:css|scss|sass|less|styl|stylus|svg|png|jpe?g|gif|webp|avif|ico|woff2?|ttf|eot|otf|mp4|webm)$/i
+ /\.(?:css|scss|sass|less|styl|stylus|svg|png|jpe?g|gif|webp|avif|ico|woff2?|ttf|eot|otf|mp4|webm)(?:[?#].*)?$/i |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Problem
When a shared dependency contains static
importstatements for asset files (SVG, PNG, CSS/SASS, fonts, etc.) in its bundled entry point, the Vite dependency optimizer generates a dep file that inlines those imports. During Module Federation's resolve hook processing, these asset import requests are incorrectly intercepted by theloadShareproxy and resolved back into the loadShare virtual module path.This creates a circular dependency chain:
The result is a runtime TDZ (Temporal Dead Zone) error:
Because the
loadSharemodule tries to re-enter itself before its owndefaultexport is ready.Root cause
The plugin has a guard in three resolve hooks that skips
.cssimports from being proxied throughloadShare:However, this guard only covers
.css. All other common web asset extensions — SVG, PNG, JPEG, GIF, WebP, AVIF, ICO, WOFF/WOFF2, TTF, EOT, OTF, MP4, WebM, SCSS, SASS, LESS, STYL — pass through the filter and get intercepted, triggering the circular dependency.The identical single-extension check exists at all three locations:
src/plugins/pluginProxySharedModule_preBuild.tsresolveIdhooksrc/index.ts(RolldownoptimizeDepsresolver)src/index.ts(esbuildoptimizeDepsresolver)Fix
Expanded the regex in all three locations from
/\.css$/to cover all common web asset extensions:This ensures that any import of an asset file extension bypasses the
loadShareproxy entirely. Vite's normal asset handling pipeline resolves and serves these files directly, breaking any potential circular dependency.File changes
src/plugins/pluginProxySharedModule_preBuild.ts:340— Vite pluginresolveIdhooksrc/index.ts:352— RolldownoptimizeDeps.rolldownOptions.pluginsresolversrc/index.ts:396— esbuildoptimizeDeps.esbuildOptions.pluginsresolverTests
src/plugins/__tests__/pluginProxySharedModule_preBuild.test.tsA new
describe('asset extension exclusion')block with 14 test cases verifying that asset imports matching a wildcard shared key (@ui-lib/) returnundefined(not proxied), plus a positive control verifying that non-asset imports under the same wildcard key ARE proxied:does not proxy 'ext' asset imports(×14)@ui-lib/assets/file.{svg,png,jpg,gif,webp,avif,ico,woff2,ttf,mp4,webm,scss,less}undefinedstill proxies non-asset imports that match a wildcard shared key@ui-lib/button{ id: '...' }Each test registers a
@ui-lib/wildcard shared key so thatfindSharedKeyForSourcematches, then verifies the asset extension regex returnsundefined(skip proxying). The positive control ensures the wildcard matching works for regular JS module imports.src/__tests__/index.test.tsRolldown resolver test (
proxies shared deps during Rolldown optimizeDeps resolution):esbuild resolver test (
does not proxy shared deps when esbuild resolves optimizeDeps entry points):Both verify that asset imports originating from a dep file path (the scenario that triggers the circular dependency) bypass the loadShare proxy.
Impact / Scope
@module-federation/vitewith a shared dependency whose bundled entry contains static imports of asset files (SVG icons, PNG images, fonts, videos, stylesheets, etc.). UI component libraries that bundle their own assets are the most affected..css. All proxied imports must be JavaScript modules with executable exports.loadSharebecause they are not JavaScript modules with shareable exports.optimizeDepsand runtime module loading.Reproduction
Prerequisites: A shared dependency whose bundled entry contains static asset imports.
Where
node_modules/x-data-spreadsheet/src/index.jscontains e.g.:npx vite buildThe error occurs because the dep optimizer creates
node_modules/.vite/deps/x-data-spreadsheet.jswhich inherits the static LESS imports. Each resolves through the loadShare proxy, creating a circular dependency:loadShare→dep→ LESS →loadShare.After the fix, asset file imports bypass the loadShare proxy entirely and are handled by Vite's normal asset pipeline.
Error also reproduced with my corporative ui libs, but i can't leave them here.