Skip to content

Fix virtual loader resolution under enhanced-resolve >= 5.21 - #77

Merged
titouanmathis merged 2 commits into
mainfrom
fix/virtual-loader-exports-resolution
Aug 10, 2026
Merged

Fix virtual loader resolution under enhanced-resolve >= 5.21#77
titouanmathis merged 2 commits into
mainfrom
fix/virtual-loader-exports-resolution

Conversation

@titouanmathis

Copy link
Copy Markdown
Contributor

Problem

Consumer builds on webpack 5.109+ (enhanced-resolve 5.24.5) fail with:

Module not found: Error: Package path ./html-loader.js is exported from package .../@studiometa/playground, but no valid target file was found (see exports field ...)

(and the same for style-loader.js and script-loader.js).

Root cause

PlaygroundLoadersPlugin registers the three virtual loader modules with webpack-virtual-modules using keys relative to the compiler context:

node_modules/@studiometa/playground/<name>-loader.js

webpack-virtual-modules joins each relative key against compiler.context (the consumer app's build context), so the virtual files land under <consumer-context>/node_modules/@studiometa/playground/.

But config.ts imports the bare specifiers @studiometa/playground/<name>-loader.js. Webpack resolves those through the package's "./*": "./*" exports entry to the package's real resolved root — a different path than where the virtual files were written.

This used to work only by accident: enhanced-resolve <= 5.20 fell back to legacy resolution when an exports target was matched but missing on disk. enhanced-resolve >= 5.21 (webpack/enhanced-resolve#399, #400) changed that matched-but-missing case into a hard error. After webpack bumped to 5.109.x, the fallback disappeared and the loaders no longer resolve.

Fix

Write the virtual loaders at the package's actual resolved on-disk root (absolute path via createRequire(import.meta.url).resolve('@studiometa/playground/package.json')) instead of a path relative to the compiler context, so the exports-field target resolves to a real (virtual) file.

Validation

  • npm run build:esbuild and npm run build:types succeed, types check clean.
  • oxlint reports 0 warnings / 0 errors on the changed file.
  • Full vitest suite: 153 tests pass.
  • Validated end to end against a consumer build: patched the resolved logic into @studiometa/ui's playground play:build (webpack 5.109.x / enhanced-resolve 5.24.5) and the build that previously errored now completes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HKLcgvaDcjK9ohA3fg7Ssq

titouanmathis and others added 2 commits August 10, 2026 10:29
The virtual HTML/style/script loader modules were registered with keys
relative to the webpack compiler context, landing under the consumer
app's node_modules. But config.ts imports them through the bare
`@studiometa/playground/<name>-loader.js` specifiers, which webpack
resolves via the package's `"./*": "./*"` exports entry to the
package's real on-disk root — a different path.

This only worked while enhanced-resolve <= 5.20 fell back to legacy
resolution for a matched-but-missing exports target. enhanced-resolve
>= 5.21 (webpack/enhanced-resolve#399) makes that a hard error, so
consumer builds on webpack 5.109+ failed with "Package path
./html-loader.js is exported from package ... but no valid target file
was found".

Write the virtual files at the package's resolved root so the
exports-field target exists on disk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HKLcgvaDcjK9ohA3fg7Ssq
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HKLcgvaDcjK9ohA3fg7Ssq
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploying studiometa-playground with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7bf8fbd
Status: ✅  Deploy successful!
Preview URL: https://8d575384.studiometa-playground.pages.dev
Branch Preview URL: https://fix-virtual-loader-exports-r.studiometa-playground.pages.dev

View logs

@github-actions

Copy link
Copy Markdown

Size Change: +87 B (+0.16%)

Total Size: 54.2 kB

📦 View Changed
Filename Size Change
packages/playground/dist/lib/plugins/PlaygroundLoadersPlugin.js 511 B +87 B (+20.52%) 🚨
ℹ️ View Unchanged
Filename Size
packages/playground-preview/dist/element.js 10 kB
packages/playground-preview/dist/index.js 10 kB
packages/playground/dist/front/css/app.css 4.26 kB
packages/playground/dist/front/js/app.js 139 B
packages/playground/dist/front/js/components/Editor.js 929 B
packages/playground/dist/front/js/components/Editors.js 265 B
packages/playground/dist/front/js/components/EditorVisibility.js 343 B
packages/playground/dist/front/js/components/HeaderSwitcher.js 436 B
packages/playground/dist/front/js/components/HtmlEditor.js 748 B
packages/playground/dist/front/js/components/Iframe.js 1.74 kB
packages/playground/dist/front/js/components/IframeReloader.js 182 B
packages/playground/dist/front/js/components/LayoutReactive.js 616 B
packages/playground/dist/front/js/components/LayoutSwitcher.js 341 B
packages/playground/dist/front/js/components/Playground.js 1.14 kB
packages/playground/dist/front/js/components/Resizable.js 992 B
packages/playground/dist/front/js/components/ResizableCursor.js 298 B
packages/playground/dist/front/js/components/ResizableSync.js 512 B
packages/playground/dist/front/js/components/ScriptEditor.js 520 B
packages/playground/dist/front/js/components/StyleEditor.js 247 B
packages/playground/dist/front/js/components/Switcher.js 334 B
packages/playground/dist/front/js/components/ThemeSwitcher.js 456 B
packages/playground/dist/front/js/create-playground.js 196 B
packages/playground/dist/front/js/loaders/html.js 124 B
packages/playground/dist/front/js/loaders/script.js 124 B
packages/playground/dist/front/js/loaders/style.js 124 B
packages/playground/dist/front/js/store/config.js 468 B
packages/playground/dist/front/js/store/content.js 400 B
packages/playground/dist/front/js/store/header.js 573 B
packages/playground/dist/front/js/store/index.js 109 B
packages/playground/dist/front/js/store/layout.js 606 B
packages/playground/dist/front/js/store/theme.js 516 B
packages/playground/dist/front/js/utils/js/index.js 436 B
packages/playground/dist/front/js/utils/monaco.js 844 B
packages/playground/dist/front/js/utils/patch-iframe-url.js 362 B
packages/playground/dist/front/js/utils/resolve-import-map-urls.js 246 B
packages/playground/dist/front/js/utils/storage/AbstractStorageProvider.js 138 B
packages/playground/dist/front/js/utils/storage/FallbackStorageProvider.js 266 B
packages/playground/dist/front/js/utils/storage/index.js 479 B
packages/playground/dist/front/js/utils/storage/LocalStorageProvider.js 254 B
packages/playground/dist/front/js/utils/storage/MemoryStorageProvider.js 206 B
packages/playground/dist/front/js/utils/storage/MultiStorageProvider.js 307 B
packages/playground/dist/front/js/utils/storage/StorageProviderInterface.js 73 B
packages/playground/dist/front/js/utils/storage/SyncedStorageProvider.js 292 B
packages/playground/dist/front/js/utils/storage/URLStorageProvider.js 365 B
packages/playground/dist/front/js/utils/storage/WatchableStore.js 307 B
packages/playground/dist/front/js/utils/storage/ZipStorageProvider.js 271 B
packages/playground/dist/front/js/utils/twig/index.js 435 B
packages/playground/dist/index.js 154 B
packages/playground/dist/lib/plugins/PlaygroundDependenciesPlugin.js 4.36 kB
packages/playground/dist/lib/presets/html-webpack-script-type-module.js 288 B
packages/playground/dist/lib/presets/playground.js 1.07 kB
packages/playground/dist/lib/presets/production-build.js 261 B
packages/playground/dist/lib/tailwind-config.js 509 B
packages/playground/dist/lib/utils/resolve-dependencies.js 3.04 kB
packages/playground/dist/lib/utils/resolve-public-path.js 283 B
packages/playground/dist/lib/utils/zip.js 310 B
packages/playground/dist/preset.js 190 B
packages/playground/dist/tailwind.js 113 B

compressed-size-action

@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 34.06%. Comparing base (68fe658) to head (7bf8fbd).

Files with missing lines Patch % Lines
...yground/src/lib/plugins/PlaygroundLoadersPlugin.ts 0.00% 3 Missing ⚠️

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #77      +/-   ##
==========================================
- Coverage   34.12%   34.06%   -0.07%     
==========================================
  Files          55       55              
  Lines        1131     1133       +2     
  Branches      231      231              
==========================================
  Hits          386      386              
- Misses        717      719       +2     
  Partials       28       28              
Flag Coverage Δ
playground 34.06% <0.00%> (-0.07%) ⬇️
playground-preview 34.06% <0.00%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@titouanmathis
titouanmathis merged commit 82f3679 into main Aug 10, 2026
7 of 8 checks passed
@titouanmathis
titouanmathis deleted the fix/virtual-loader-exports-resolution branch August 10, 2026 09:19
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.

1 participant