Skip to content

Fix @php-wasm/web icu.dat dynamic import path in dist bundle#3708

Merged
adamziel merged 2 commits into
trunkfrom
fix/php-wasm-web-icu-dat-path
May 30, 2026
Merged

Fix @php-wasm/web icu.dat dynamic import path in dist bundle#3708
adamziel merged 2 commits into
trunkfrom
fix/php-wasm-web-icu-dat-path

Conversation

@mho22
Copy link
Copy Markdown
Collaborator

@mho22 mho22 commented May 29, 2026

Summary

  • Rewrites the viteExternalDynamicImports transform in packages/php-wasm/web/vite.config.ts so the bundled index.js / index.cjs resolve icu.dat from ./shared/icu.dat next to the bundle.
  • Adds a test-built-npm-packages regression spec that walks every installed @php-wasm/* and @wp-playground/* package, extracts dynamic import("./...dat|so|wasm") specs from each index.js / index.cjs, and asserts they resolve to real files relative to the package directory.

Fixes the downstream Vite consumer error:

[plugin:vite:import-analysis] Failed to resolve import "../intl/shared/icu.dat"
from "node_modules/@php-wasm/web/index.js"

Why

PR #3566 ("Support custom PHP.wasm extensions") moved the dynamic import("icu.dat") from src/lib/extensions/intl/with-intl.ts (3 directories below src/) to src/lib/extensions/load-extensions.ts (2 directories below). The transform was hard-coded for the deeper location, so after the move Rollup's relative-path normalization leaves a leading ../intl/ segment in the output. The published bundle ends up with import("../intl/shared/icu.dat"), which resolves to node_modules/@php-wasm/intl/shared/icu.dat — a path that does not exist.

The regression test exists so any future relocation of a dynamic-asset import in the WASM packages can't ship to npm unnoticed.

Changes by commit

  • [Tests] Verify dynamic asset imports resolve in built npm packages — adds assets.spec.ts to both the ESM (node:test) and CommonJS (Jest) projects under packages/playground/test-built-npm-packages/. Wires the ESM spec into run-tests.ts; Jest auto-discovers via testMatch. On its own this commit fails CI against current trunk, which is the intended demonstration.
  • Fix dynamic icu.dat import path in @php-wasm/web bundle (to follow) — rewrites the viteExternalDynamicImports transform to derive a ./shared/<file> output regardless of source-file depth under src/. Turns the new regression test green.

Test plan

  • Locally: spec fails against the broken (trunk) @php-wasm/web bundle — import("../intl/shared/icu.dat") -> .../@php-wasm/intl/shared/icu.dat does not exist.
  • Locally: spec passes against the rebuilt @php-wasm/web bundle after the transform fix.
  • CI test-built-npm-packages ES Modules and CommonJS jobs fail on the tests-only commit; turn green after the vite-fix commit lands.
  • Reproduce the downstream Vite consumer's original build against @php-wasm/web from this branch's HEAD and confirm it no longer errors.

Walks every installed @php-wasm/* and @wp-playground/* package under
node_modules, extracts dynamic import("./...dat|so|wasm") specs from
index.js and index.cjs, and asserts each resolves to an existing file
relative to the package directory. Catches the class of regression where
a Vite/Rollup transform emits an out-of-tree path (e.g. icu.dat ending
up under @php-wasm/intl/ instead of @php-wasm/web/shared/).

Mirrored across the ESM (node:test) and CommonJS (Jest) test projects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mho22 mho22 requested review from a team, ashfame and Copilot May 29, 2026 11:50
@mho22 mho22 marked this pull request as draft May 29, 2026 11:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes the icu.dat dynamic-import path in the @php-wasm/web published bundle (which broke after PR #3566 moved the import one directory up) and adds regression tests that verify dynamic asset imports in built npm packages resolve to real files.

Changes:

  • Add assets.spec.ts regression tests for ESM (node:test) and CommonJS (Jest) that scan built bundles for import("…dat|so|wasm") and assert the paths exist.
  • Wire the new ESM spec into run-tests.ts.
  • (Forthcoming commit) Rewrite the viteExternalDynamicImports transform in packages/php-wasm/web/vite.config.ts to emit ./shared/<file> regardless of source depth.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
packages/playground/test-built-npm-packages/es-modules-and-vitest/tests/assets.spec.ts New ESM regression test scanning installed packages' bundles for dynamic asset imports.
packages/playground/test-built-npm-packages/es-modules-and-vitest/run-tests.ts Registers the new assets.spec.ts with the ESM test runner.
packages/playground/test-built-npm-packages/commonjs-and-jest/tests/assets.spec.ts CommonJS/Jest equivalent of the ESM regression test.
Comments suppressed due to low confidence (1)

packages/playground/test-built-npm-packages/commonjs-and-jest/tests/assets.spec.ts:1

  • This toEqual pattern compares three identical fields just to surface diagnostic context on failure. A simpler and clearer alternative is expect(fs.existsSync(resolved)).toBe(true) paired with a message via Jest's third arg pattern or a custom message string — or use the ESM file's assert.ok(..., message) approach for parity between the two specs. The current form is unnecessarily verbose and obscures the actual assertion.
const path = require('path');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,61 @@
const path = require('path');
Comment on lines +35 to +37
describe('Built package dynamic asset imports', () => {
getInstalledPackages().forEach((pkg) => {
it(`${pkg.name} dynamic asset imports resolve to files in dist`, () => {
Comment on lines +31 to +33
describe('Built package dynamic asset imports', () => {
getInstalledPackages().forEach((pkg) => {
it(`${pkg.name} dynamic asset imports resolve to files in dist`, () => {
Comment on lines +12 to +17
const importRegex = new RegExp(
`import\\(\\s*["']((?:\\./|\\.\\./)[^"']+\\.(?:${assetExtensions.join(
'|'
)}))["']\\s*\\)`,
'g'
);
@mho22 mho22 removed the request for review from ashfame May 29, 2026 11:51
After PR #3566 moved the icu.dat dynamic import from src/lib/extensions/
intl/with-intl.ts (depth 3) to src/lib/extensions/load-extensions.ts
(depth 2), the viteExternalDynamicImports transform's hard-coded
'../../../' prefix produced 'import("../intl/shared/icu.dat")' in the
dist bundle — a path that resolves outside the package to a non-existent
@php-wasm/intl/shared/icu.dat. Downstream Vite consumers failed with
"Failed to resolve import" against that path.

Derive the output as './shared/<file>' from the specifier's tail so the
transform stays correct regardless of where the import statement lives
under src/. The companion regression test in
test-built-npm-packages/{es-modules-and-vitest,commonjs-and-jest}/tests/
assets.spec.ts now passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@adamziel adamziel marked this pull request as ready for review May 30, 2026 08:17
@adamziel adamziel merged commit 952678d into trunk May 30, 2026
55 checks passed
@adamziel adamziel deleted the fix/php-wasm-web-icu-dat-path branch May 30, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants