Skip to content

Conversation

@gavande1
Copy link

@gavande1 gavande1 commented Jan 7, 2026

🚧 WIP

Motivation for the change, related issues

After upgrading from @php-wasm/node v3.0.22 to v3.0.39, Jest tests that use loadNodeRuntime() directly fail with ESM-related errors.

The per-version packages introduced in #3062 contain JavaScript files that use ESM syntax (import.meta.url), which breaks when loaded in Jest's CommonJS sandbox.

Error:

TypeError: A dynamic import callback was invoked without --experimental-vm-modules

    at getPHPLoaderModule (node_modules/@php-wasm/node/index.cjs:54:7)

Or alternatively:

SyntaxError: Cannot use 'import.meta' outside a module

    /node_modules/@php-wasm/node-8-3/asyncify/php_8_3.js:5
    const require = createRequire(import.meta.url);
                                         ^^^^

This affects downstream projects (like WordPress Studio) that use @php-wasm/node directly in their Jest test suites.

Implementation details

This PR adds a test that verifies @php-wasm/node can be used directly in Jest without:

  • Requiring --experimental-vm-modules
  • Spawning a separate process via runCLI()

The test currently fails - it demonstrates the issue and will pass once a fix is implemented.

Root Cause

The per-version packages (@php-wasm/node-8-3, etc.) contain ESM files:

// @php-wasm/node-8-3/asyncify/php_8_3.js
import { createRequire } from 'module';
const require = createRequire(import.meta.url);  // ESM syntax

When @php-wasm/node/index.cjs dynamically imports these packages, Jest cannot handle the ESM dynamic imports in its CommonJS sandbox.

Related PRs

Testing Instructions (or ideally a Blueprint)

Run the test suite for commonjs-and-jest:

cd packages/playground/test-built-npm-packages/commonjs-and-jest
npm install
npm test

The new test php-wasm-node.spec.ts will fail with the error above, demonstrating the issue.

gavande1 and others added 7 commits January 7, 2026 22:07
Add a test that verifies @php-wasm/node can be used directly in Jest
without requiring --experimental-vm-modules or spawning a child process.

This test currently fails due to ESM syntax (import.meta.url) in the
per-version packages breaking in Jest's CommonJS sandbox.
@bgrgicak bgrgicak force-pushed the fix/jest-esm-compatibility-test branch from 074e47a to f765ae6 Compare January 9, 2026 11:39
@bgrgicak
Copy link
Collaborator

bgrgicak commented Jan 9, 2026

I've been exploring a fix for this issue, which checks if the environment supports dynamic imports and uses require otherwise, by using simple if checks to determine if Jest is running.

As mentioned in the PR description, the Jest VM doesn't allow dynamic imports by default; to make it work, Jest needs to run with a --experimental-vm-modules flag.

Dynamic imports work in both ESM and CommonJS, so from what I can see, this is a Jest-specific issue.

I don't think that we should address it in PHP-wasm by switching between import and require, and see two potential paths forward.

  • We could accept it as is and document that Jest will require the --experimental-vm-modules flat to work with PHP-wasm.
  • We could build a .cjs version of the PHP-wasm JS file, but these files are already 900+ KB, and adding separate cjs files would significantly increase the package size.

Looking at both options, my suggestion is to require the --experimental-vm-modules flag for Jest to work.

Is there a third option that I'm missing? Are there other places besides Jest where dynamic loading is an issue?

@adamziel @brandonpayton @mho22, what do you think?

@mho22
Copy link
Collaborator

mho22 commented Jan 10, 2026

@bgrgicak I fully agree with you.

I think we have another complex option that could make this work. Print separate banners in CJS and ESM during build. This works with ESBuild or Vite. A Vite plugin could be created to add banners for tests.

The last missing piece would be running the different packages locally, probably inside node-es-module-loader/loader.mts and we will maybe have a node-cjs-loader/loaders.cts that would add that part too for CJS mode ?

However, this is a lot more complicated process compared to add the --experimental-vm-modules flag in Jest.

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.

3 participants