close
Skip to content

[PHP] Recompile PHP.wasm ASYNCIFY with MAIN_MODULE set to 2#3335

Merged
brandonpayton merged 6 commits intotrunkfrom
main-module-2-asyncify
Mar 10, 2026
Merged

[PHP] Recompile PHP.wasm ASYNCIFY with MAIN_MODULE set to 2#3335
brandonpayton merged 6 commits intotrunkfrom
main-module-2-asyncify

Conversation

@mho22
Copy link
Copy Markdown
Collaborator

@mho22 mho22 commented Mar 4, 2026

Motivation for the change, related issues

Following-up on : #3332

This pull request sets MAIN_MODULE=2 to PHP.wasm Node Asyncify and PHP.wasm Web Asyncify.

Implementation details

  1. Updated the php/Dockerfile script to enable MAIN_MODULE=2 by default.

  2. Ran the following commands

nx run php-wasm-compile-shared-intl:node:asyncify:all
nx run php-wasm-compile-shared-xdebug:asyncify:all
nx run php-wasm-node:recompile-php:asyncify:all

nx run php-wasm-compile-shared-intl:web:asyncify:all
nx run php-wasm-web:recompile-php:asyncify:all

Now the entire PHP.wasm builds are dead code eliminated. 🎉

Size Reduction

Metric Before After Saved
Total binary size 888 MB 766 MB 122 MB (13.7%)
.wasm files 680 MB 571 MB 109 MB (16%)
JS glue code 22.7 MB 8.2 MB 14.5 MB (63%)

Per-version .wasm reduction

PHP Version Before (avg) After (avg) Reduction
7.4 ~20 MB ~17 MB 17–19%
8.0 ~21 MB ~17 MB 17–19%
8.1 ~24 MB ~20 MB 15–17%
8.2 ~25 MB ~21 MB 15–17%
8.3 ~25 MB ~21 MB 15–17%
8.4 ~27 MB ~23 MB 14–16%
8.5 ~28 MB ~24 MB 14–15%

Web vs Node Build Comparison

Platform Before After Saved Reduction
Node builds 468.8 MB 402.2 MB 66.6 MB 14.2%
Web builds 419.4 MB 364.0 MB 55.4 MB 13.2%

Breakdown by file type

Platform .wasm saved JS glue saved .so delta
Node builds 59.4 MB (16.5%) 8.0 MB (62.4%) +0.7 MB
Web builds 49.6 MB (15.4%) 6.5 MB (65.4%) +0.7 MB

The slight .so increase (~0.7 MB per platform) is due to the rebuilt Intl extension now including additional symbols needed for MAIN_MODULE=2 compatibility.

Breakdown by variant

Build Before After Saved Reduction
Node Asyncify 241.6 MB 208.4 MB 33.2 MB 13.7%
Node JSPI 227.2 MB 193.8 MB 33.4 MB 14.7%
Web Asyncify 219.1 MB 191.7 MB 27.4 MB 12.5%
Web JSPI 200.3 MB 172.4 MB 28.0 MB 13.9%

JS glue code reduction

Build Before After Saved Reduction
Node Asyncify ~957 KB ~360 KB ~597 KB 62%
Node JSPI ~912 KB ~340 KB ~572 KB 63%
Web Asyncify ~735 KB ~263 KB ~472 KB 64%
Web JSPI ~716 KB ~236 KB ~480 KB 67%

Line Changes

PR JS Glue Lines Before JS Glue Lines After Net
#3332 (JSPI) 422,100 146,463 -275,637
#3335 (Asyncify) 439,850 160,694 -279,156
Combined 861,950 307,157 -554,793

Performance Implications

MAIN_MODULE=2 tells Emscripten to only export symbols actually needed for dynamic linking, rather than exporting everything. This yields:

  1. Smaller download size — 122 MB less across all builds means faster CI, faster clones, and faster deployments
  2. Faster WebAssembly instantiation — Smaller .wasm files take less time to compile and instantiate in the browser (compilation cost is roughly proportional to binary size)
  3. Lower memory usage — Fewer exported symbols means a smaller function table and less memory overhead at runtime
  4. Smaller JS glue code — 63% smaller JS files means faster parsing and less memory for the JavaScript engine

Testing Instructions (or ideally a Blueprint)

CI

@mho22 mho22 changed the title [PHP] Recompile PHP.wasm ASYNCIFY with MAIN_MODULE set to 2 [PHP] Recompile PHP.wasm ASYNCIFY with MAIN_MODULE set to 2 Mar 4, 2026
@mho22 mho22 marked this pull request as ready for review March 4, 2026 11:00
@mho22 mho22 requested review from a team, adamziel and brandonpayton March 4, 2026 11:00
Copy link
Copy Markdown
Member

@brandonpayton brandonpayton left a comment

Choose a reason for hiding this comment

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

@mho22, this looks good. Thank you!

How cool is this, especially for php-wasm/web download sizes?

Image Image

@brandonpayton brandonpayton merged commit 68e7ecc into trunk Mar 10, 2026
42 checks passed
@brandonpayton brandonpayton deleted the main-module-2-asyncify branch March 10, 2026 20:06
@mho22
Copy link
Copy Markdown
Collaborator Author

mho22 commented Mar 11, 2026

@brandonpayton Well, not as light as Node builds but, still :

Capture d’écran 2026-03-11 à 09 17 32

Now the entire PHP.wasm builds are dead code eliminated. 🎉

Size Reduction

Metric Before After Saved
Total binary size 888 MB 766 MB 122 MB (13.7%)
.wasm files 680 MB 571 MB 109 MB (16%)
JS glue code 22.7 MB 8.2 MB 14.5 MB (63%)

Per-version .wasm reduction

PHP Version Before (avg) After (avg) Reduction
7.4 ~20 MB ~17 MB 17–19%
8.0 ~21 MB ~17 MB 17–19%
8.1 ~24 MB ~20 MB 15–17%
8.2 ~25 MB ~21 MB 15–17%
8.3 ~25 MB ~21 MB 15–17%
8.4 ~27 MB ~23 MB 14–16%
8.5 ~28 MB ~24 MB 14–15%

Web vs Node Build Comparison

Platform Before After Saved Reduction
Node builds 468.8 MB 402.2 MB 66.6 MB 14.2%
Web builds 419.4 MB 364.0 MB 55.4 MB 13.2%

Breakdown by file type

Platform .wasm saved JS glue saved .so delta
Node builds 59.4 MB (16.5%) 8.0 MB (62.4%) +0.7 MB
Web builds 49.6 MB (15.4%) 6.5 MB (65.4%) +0.7 MB

The slight .so increase (~0.7 MB per platform) is due to the rebuilt Intl extension now including additional symbols needed for MAIN_MODULE=2 compatibility.

Breakdown by variant

Build Before After Saved Reduction
Node Asyncify 241.6 MB 208.4 MB 33.2 MB 13.7%
Node JSPI 227.2 MB 193.8 MB 33.4 MB 14.7%
Web Asyncify 219.1 MB 191.7 MB 27.4 MB 12.5%
Web JSPI 200.3 MB 172.4 MB 28.0 MB 13.9%

JS glue code reduction

Build Before After Saved Reduction
Node Asyncify ~957 KB ~360 KB ~597 KB 62%
Node JSPI ~912 KB ~340 KB ~572 KB 63%
Web Asyncify ~735 KB ~263 KB ~472 KB 64%
Web JSPI ~716 KB ~236 KB ~480 KB 67%

Line Changes

PR JS Glue Lines Before JS Glue Lines After Net
#3332 (JSPI) 422,100 146,463 -275,637
#3335 (Asyncify) 439,850 160,694 -279,156
Combined 861,950 307,157 -554,793

Performance Implications

MAIN_MODULE=2 tells Emscripten to only export symbols actually needed for dynamic linking, rather than exporting everything. This yields:

  1. Smaller download size — 122 MB less across all builds means faster CI, faster clones, and faster deployments
  2. Faster WebAssembly instantiation — Smaller .wasm files take less time to compile and instantiate in the browser (compilation cost is roughly proportional to binary size)
  3. Lower memory usage — Fewer exported symbols means a smaller function table and less memory overhead at runtime
  4. Smaller JS glue code — 63% smaller JS files means faster parsing and less memory for the JavaScript engine

It would be interesting to benchmark the runtime impact, particularly WebAssembly instantiation time, time-to-first-PHP-response, and memory usage, to quantify the performance gains beyond file size.

@adamziel
Copy link
Copy Markdown
Collaborator

This is amazing ❤️ Thank you so much @mho22! @fellyph – let's highlight the smaller download sizes somewhere, could be with a few other recent updates.

@fellyph
Copy link
Copy Markdown
Collaborator

fellyph commented Mar 11, 2026

@adamziel I have posted about it https://make.wordpress.org/playground/2026/03/11/how-wordpress-playground-cut-php-wasm-binary-sizes-by-122-mb/

@brandonpayton
Copy link
Copy Markdown
Member

@brandonpayton Well, not as light as Node builds but, still :
Now the entire PHP.wasm builds are dead code eliminated. 🎉

This is great, @mho22! Thank you!

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.

4 participants