A Lighter, More Modular WordPress Playground: Understanding the php-wasm Package Split

PHPPHP PHP (recursive acronym for PHP: Hypertext Preprocessor) is a widely-used open source general-purpose scripting language that is especially suited for web development and can be embedded into HTML. https://www.php.net/manual/en/preface.php. WASM now supports individual packages for each PHP version from 7.2 through 8.5. All old code still works but if you want to save bandwidth, you can now use a specific PHP WASM version package.

The Architecture: Universal, Loaders, and Builds

@php-wasm/universal is the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. package that powers both Node.js and browser environments. Here’s how it fits:

  • @php-wasm/universal: This is the “brain.” It contains everything familiar to both Node.js and the browser, managing the filesystem, handling .ini entries, and defining the core PHP class.
  • @php-wasm/node / @php-wasm/web: These are the “loaders.” They handle the environment-specific setup (like loading the WASM file from disk in Node vs. fetching it in the browser) and pass it to the universal core.

The Challenge: Hitting the Ceiling

When you install @php-wasm/node, you get everything: the runtime tools plus WebAssembly binaries for every supported PHP version. As we expanded support from PHP 7.2 to 8.5, this bundle became so big that the WebAssembly binaries exceeded npm’s 100 MB size limit.

To solve this, we split the PHP versions from the “heavy lifting”:

  • The Tools: The main packages (@php-wasm/node and @php-wasm/web) still work as usual.
  • The Builds: We separated the binaries into dedicated packages like @php-wasm/node-8.4 or @php-wasm/web-8.5 for lightweight solutions.

With this split, you download only the PHP versions you need—saving bandwidth and disk space for your applications.

Seeing it in Action

This modularity produces consistent code across Node.js and browser environments.

Classic Way (via @php-wasm/web)

Here is how you initialize PHP for the Web using the classic structure:

npm install @php-wasm/web
import { PHP } from '@php-wasm/universal';
import { loadWebRuntime } from '@php-wasm/web';

const php = new PHP(await loadWebRuntime('8.4'));

const response = await php.runStream({ code: `<?php echo "Hello World";` });
console.log(await response.stdoutText);

This approach handles Xdebug, emscriptenOptions, and other advanced features automatically.

Version-Specific Way (via @php-wasm/web-8-4)

For maximum control and minimal dependencies, use the version-specific package directly:

npm install @php-wasm/web-8-4
import { PHP, loadPHPRuntime } from "@php-wasm/universal";
import { getPHPLoaderModule } from "@php-wasm/web-8-4";

const loaderModule = await getPHPLoaderModule();
const runtimeId = await loadPHPRuntime(loaderModule);
const php = new PHP(runtimeId);

const response = await php.runStream({ code: `<?php echo "Hello World";` });
console.log(await response.stdoutText);

This approach bypasses @php-wasm/web entirely, making it perfect for lightweight applications. However, if you need Xdebug or custom emscriptenOptions, you’ll need to configure them manually.

In both cases, @php-wasm/universal provides the standard PHP class that orchestrates execution, while the version-specific package provides a lighter bundle and lower disk usage.

Same Pattern for Node.js

The same approaches work for Node.js—just swap @php-wasm/web for @php-wasm/node:

import { PHP } from '@php-wasm/universal';
import { loadNodeRuntime } from '@php-wasm/node';

const php = new PHP(await loadNodeRuntime('8.4'));

Dependency & Installation Overhead

The most significant improvement is the reduction in node_modules size. The classic approach required installing every supported PHP version, whereas the version-specific approach is targeted.

MetricClassic Way (@php-wasm/web)Version-Specific Way (@php-wasm/web-8-4)Improvement
Packages Installed@php-wasm/web + 9 PHP runtimesOnly @php-wasm/web-8-4-9 packages
Disk Usage~530 MB~63 MB~88% Reduction

Note: The classic package includes runtimes for PHP 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, and 8.5.

Why This Matters

The modular architecture solves the NPM size limit and improves the codebase:

  1. Faster CI/CD: Pipelines download only the PHP versions they need.
  2. Lighter applications: Version-specific packages for a minimal footprint.
  3. Better tree-shaking: Modern bundlers like Vite and ESBuild can eliminate unused code.

Getting Started

Choose your approach based on your needs:

Classic (full features):

npm install @php-wasm/web

Version-specific (minimal footprint):

npm install @php-wasm/web-8-4

Check the PHP WASM documentation for detailed setup instructions. Tell us what you think of this new alternative for working with PHP WASM, and share your feedback in the #playground SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. channel.

Props to @akirk and @yannickdecat for reviewing the post.