Skip to content

Fix JSPI detection using runtime feature check - #2906

Merged
fredrikekelund merged 6 commits into
trunkfrom
fix-jspi-runtime-detection
Mar 26, 2026
Merged

Fix JSPI detection using runtime feature check#2906
fredrikekelund merged 6 commits into
trunkfrom
fix-jspi-runtime-detection

Conversation

@ivan-ottinger

@ivan-ottinger ivan-ottinger commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude Code helped to investigate, reproduce, and fix the bug. I have reviewed the code, iterated over it and confirmed it works as expected.

Proposed Changes

  • Replace semver.gte(process.version, '24.0.0') with a runtime check for WebAssembly.promising to detect JSPI availability. The version check assumed Node 24+ has JSPI enabled by default, but it still requires the --experimental-wasm-jspi flag. This caused "Redis extension requires JSPI" errors when running CLI commands directly without the flag.
  • Remove unused semver imports from run-wp-cli-command.ts and wordpress-server-child.ts.

Testing Instructions

  1. Build the CLI: npm run cli:build
  2. Run without the JSPI flag (should succeed without Redis/memcached errors):
    node apps/cli/dist/cli/main.js site set --wp=6.9.1 --path ~/Studio/<site>
    
  3. Run with the JSPI flag (should succeed with Redis/memcached enabled):
    node --experimental-wasm-jspi apps/cli/dist/cli/main.js site set --wp=6.9.1 --path ~/Studio/<site>
    
  4. Try to reproduce the issue with the current trunk (the process should fail with an error):
    node apps/cli/dist/cli/main.js site set --wp=6.9.1 --path ~/Studio/<site>
    

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?
Replace semver.gte(process.version, '24.0.0') with a runtime check for
WebAssembly.promising to detect JSPI availability. The version check
assumed Node 24+ has JSPI enabled by default, but it requires the
--experimental-wasm-jspi flag. This caused "Redis extension requires
JSPI" errors when running CLI commands directly without the flag.

Extract the check into a shared isJspiAvailable helper in
tools/common/lib/jspi.ts so there is a single source of truth.
@ivan-ottinger ivan-ottinger self-assigned this Mar 25, 2026
@ivan-ottinger
ivan-ottinger marked this pull request as ready for review March 25, 2026 15:54
@ivan-ottinger
ivan-ottinger requested review from a team and fredrikekelund March 25, 2026 15:54

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice improvement. I think we should change some implementation details, but approving now to unblock you, @ivan-ottinger.

Comment thread tools/common/lib/jspi.ts Outdated
Comment on lines +10 to +11
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isJspiAvailable = typeof ( WebAssembly as any ).promising === 'function';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isJspiAvailable = typeof ( WebAssembly as any ).promising === 'function';
export const IS_JSPI_AVAILABLE = 'Suspending' in WebAssembly;

This is how they test it in Playground, apparently. Good to get rid of the type assertion, too.

Also, I'd rename the const in all caps.

@fredrikekelund

Copy link
Copy Markdown
Contributor

I discovered an issue on this exact topic while smoke testing the new release: the bin wrapper script for the CLI didn't pass the --experimental-wasm-jspi flag to Node, which caused WP-CLI invocations to fail when the site wasn't started.

I took the opportunity of committing those changes to this PR, too.

@fredrikekelund
fredrikekelund merged commit 2198b21 into trunk Mar 26, 2026
8 of 10 checks passed
@fredrikekelund
fredrikekelund deleted the fix-jspi-runtime-detection branch March 26, 2026 10:50
fredrikekelund added a commit that referenced this pull request Mar 26, 2026
* Fix JSPI detection using runtime feature check instead of Node version

Replace semver.gte(process.version, '24.0.0') with a runtime check for
WebAssembly.promising to detect JSPI availability. The version check
assumed Node 24+ has JSPI enabled by default, but it requires the
--experimental-wasm-jspi flag. This caused "Redis extension requires
JSPI" errors when running CLI commands directly without the flag.

Extract the check into a shared isJspiAvailable helper in
tools/common/lib/jspi.ts so there is a single source of truth.

* Remove unverified claim about JSPI proposal stage from comment

* Fix linting

* Address review suggestions

* Pass `--experimental-wasm-jspi` to node in bin script

---------

Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>
@wpmobilebot

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing 449d6e7 vs trunk

app-size

Metric trunk 449d6e7 Diff Change
App Size (Mac) 1247.24 MB 1247.24 MB 0.01 MB ⚪ 0.0%

site-editor

Metric trunk 449d6e7 Diff Change
load 1889 ms 1902 ms +13 ms ⚪ 0.0%

site-startup

Metric trunk 449d6e7 Diff Change
siteCreation 8164 ms 8158 ms 6 ms ⚪ 0.0%
siteStartup 3928 ms 3938 ms +10 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@ivan-ottinger

Copy link
Copy Markdown
Contributor Author

Nice! Thanks for bringing in the additional changes and merging the PR, Fredrik.

fredrikekelund added a commit that referenced this pull request Mar 26, 2026
* [skip ci] Code freeze: Update translatable strings for 1.7.7

* [skip ci] Code freeze: Add draft release notes for 1.7.7

* Fix Prettier lint error in ipc-handlers import statement (#2893)

* Update Studio CLI settings toggle copy and layout (#2855)

* Update Studio CLI toggle copy and layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix unit tests to follow UI change

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>

* Studio: Borders don't have correct colors in dark mode (#2885)

* Add rule for buttons borders

* Improve comment

---------

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta1

* Update CLI version

* Preliminary release notes cleanup

* Fix: CLI doesn't generate site thumbnails (#2850)

* Consolidate thumbnail capture to shared CLI path

Create a single thumbnail capture path through captureSiteThumbnail() that is used by both the desktop UI (loadThemeDetails) and CLI events subscriber. This eliminates duplication and uses pendingCaptures deduplication to prevent concurrent BrowserWindow creation when the same site is captured by multiple paths simultaneously.

* remove comments

* Use sequential util with deduplicateKey for thumbnail capture

* Fix E2E copy-site test targeting wrong BrowserWindow

The thumbnail capture feature creates hidden BrowserWindows for
screenshots. The copy-site test used getAllWindows()[0] to send
the IPC event, which could target the screenshot window instead
of the main app window, causing the copy action to silently fail.
Use getFocusedWindow() with a visible-window fallback instead.

---------

Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>

* Disable Redis/memcached when JSPI is unavailable (#2900)

* Disable Redis and memcached PHP extensions when JSPI is unavailable

These extensions require JSPI (JavaScript Promise Integration), which is
only available in Node.js 24+. On Node <24, enabling them crashes the
WordPress server at startup. This conditionally disables them when JSPI
isn't available, matching the pattern in process-manager-daemon.ts.

Also bumps the minimum engine version to >=24.0.0 since the production
build strips asyncify binaries, making Node 24+ a de facto requirement.

* Revert engine version bump to >=22.0.0

* Sort sites by sortOrder when loading from IPC (#2902)

* Fix regressions around deleting preview sites (#2903)

* Support deleting all preview sites from CLI and app

* Update tests

* Fix

* Improve schemas and types

* Tweak

* Fix JSPI detection using runtime feature check (#2906)

* Fix JSPI detection using runtime feature check instead of Node version

Replace semver.gte(process.version, '24.0.0') with a runtime check for
WebAssembly.promising to detect JSPI availability. The version check
assumed Node 24+ has JSPI enabled by default, but it requires the
--experimental-wasm-jspi flag. This caused "Redis extension requires
JSPI" errors when running CLI commands directly without the flag.

Extract the check into a shared isJspiAvailable helper in
tools/common/lib/jspi.ts so there is a single source of truth.

* Remove unverified claim about JSPI proposal stage from comment

* Fix linting

* Address review suggestions

* Pass `--experimental-wasm-jspi` to node in bin script

---------

Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta2

* Minuscule CLI README tweak (#2917)

* Minuscule CLI README tweak

* Fix tests

* Address review comments

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json` (#2916)

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json`

* Fix tests

* Fix tests

* Fix tests

* Fix What's New current step icon color in dark mode (#2921)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update release notes for 1.7.7 (#2905)

* Update release notes for 1.7.7

* Address review suggestions

* Ensure that language packs are bundled in `wp-files` (#2922)

* Add phpMyAdmin to What's New dialog (#2920)

* Add phpMyAdmin to What's New dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve wording

* Force What's New for next version

* Update phpMyAdmin illustration with dot grid background

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>

* Refactor and clean up site deletion logic in app (#2915)

* Refactor site deletion in app

* Nit fix

* [skip ci] Bump version to 1.7.7-beta3

---------

Co-authored-by: Roberto Aranda <roberto.aranda@automattic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>
Co-authored-by: Gergely Csécsey <gergely.csecsey@automattic.com>
Co-authored-by: Ivan Ottinger <ivan.ottinger@automattic.com>
Co-authored-by: Bernardo Cotrim <bmmcotrim@gmail.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik@f26d.dev>
Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
Co-authored-by: Wojtek Naruniec <wojtek.naruniec@automattic.com>
fredrikekelund added a commit that referenced this pull request Mar 27, 2026
* [skip ci] Code freeze: Update translatable strings for 1.7.7

* [skip ci] Code freeze: Add draft release notes for 1.7.7

* Fix Prettier lint error in ipc-handlers import statement (#2893)

* Update Studio CLI settings toggle copy and layout (#2855)

* Update Studio CLI toggle copy and layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix unit tests to follow UI change

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>

* Studio: Borders don't have correct colors in dark mode (#2885)

* Add rule for buttons borders

* Improve comment

---------

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta1

* Update CLI version

* Preliminary release notes cleanup

* Fix: CLI doesn't generate site thumbnails (#2850)

* Consolidate thumbnail capture to shared CLI path

Create a single thumbnail capture path through captureSiteThumbnail() that is used by both the desktop UI (loadThemeDetails) and CLI events subscriber. This eliminates duplication and uses pendingCaptures deduplication to prevent concurrent BrowserWindow creation when the same site is captured by multiple paths simultaneously.

* remove comments

* Use sequential util with deduplicateKey for thumbnail capture

* Fix E2E copy-site test targeting wrong BrowserWindow

The thumbnail capture feature creates hidden BrowserWindows for
screenshots. The copy-site test used getAllWindows()[0] to send
the IPC event, which could target the screenshot window instead
of the main app window, causing the copy action to silently fail.
Use getFocusedWindow() with a visible-window fallback instead.

---------

Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>

* Disable Redis/memcached when JSPI is unavailable (#2900)

* Disable Redis and memcached PHP extensions when JSPI is unavailable

These extensions require JSPI (JavaScript Promise Integration), which is
only available in Node.js 24+. On Node <24, enabling them crashes the
WordPress server at startup. This conditionally disables them when JSPI
isn't available, matching the pattern in process-manager-daemon.ts.

Also bumps the minimum engine version to >=24.0.0 since the production
build strips asyncify binaries, making Node 24+ a de facto requirement.

* Revert engine version bump to >=22.0.0

* Sort sites by sortOrder when loading from IPC (#2902)

* Fix regressions around deleting preview sites (#2903)

* Support deleting all preview sites from CLI and app

* Update tests

* Fix

* Improve schemas and types

* Tweak

* Fix JSPI detection using runtime feature check (#2906)

* Fix JSPI detection using runtime feature check instead of Node version

Replace semver.gte(process.version, '24.0.0') with a runtime check for
WebAssembly.promising to detect JSPI availability. The version check
assumed Node 24+ has JSPI enabled by default, but it requires the
--experimental-wasm-jspi flag. This caused "Redis extension requires
JSPI" errors when running CLI commands directly without the flag.

Extract the check into a shared isJspiAvailable helper in
tools/common/lib/jspi.ts so there is a single source of truth.

* Remove unverified claim about JSPI proposal stage from comment

* Fix linting

* Address review suggestions

* Pass `--experimental-wasm-jspi` to node in bin script

---------

Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta2

* Minuscule CLI README tweak (#2917)

* Minuscule CLI README tweak

* Fix tests

* Address review comments

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json` (#2916)

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json`

* Fix tests

* Fix tests

* Fix tests

* Fix What's New current step icon color in dark mode (#2921)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update release notes for 1.7.7 (#2905)

* Update release notes for 1.7.7

* Address review suggestions

* Ensure that language packs are bundled in `wp-files` (#2922)

* Add phpMyAdmin to What's New dialog (#2920)

* Add phpMyAdmin to What's New dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve wording

* Force What's New for next version

* Update phpMyAdmin illustration with dot grid background

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>

* Refactor and clean up site deletion logic in app (#2915)

* Refactor site deletion in app

* Nit fix

* [skip ci] Bump version to 1.7.7-beta3

* Emit `deleted` site event when removing empty site (#2929)

* Bump CLI version

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7

* [skip ci] Bump CLI version to 1.7.7

---------

Co-authored-by: Roberto Aranda <roberto.aranda@automattic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>
Co-authored-by: Gergely Csécsey <gergely.csecsey@automattic.com>
Co-authored-by: Ivan Ottinger <ivan.ottinger@automattic.com>
Co-authored-by: Bernardo Cotrim <bmmcotrim@gmail.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik@f26d.dev>
Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
Co-authored-by: Wojtek Naruniec <wojtek.naruniec@automattic.com>
fredrikekelund added a commit that referenced this pull request Apr 2, 2026
* [skip ci] Code freeze: Update translatable strings for 1.7.7

* [skip ci] Code freeze: Add draft release notes for 1.7.7

* Fix Prettier lint error in ipc-handlers import statement (#2893)

* Update Studio CLI settings toggle copy and layout (#2855)

* Update Studio CLI toggle copy and layout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix unit tests to follow UI change

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>

* Studio: Borders don't have correct colors in dark mode (#2885)

* Add rule for buttons borders

* Improve comment

---------

Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta1

* Update CLI version

* Preliminary release notes cleanup

* Fix: CLI doesn't generate site thumbnails (#2850)

* Consolidate thumbnail capture to shared CLI path

Create a single thumbnail capture path through captureSiteThumbnail() that is used by both the desktop UI (loadThemeDetails) and CLI events subscriber. This eliminates duplication and uses pendingCaptures deduplication to prevent concurrent BrowserWindow creation when the same site is captured by multiple paths simultaneously.

* remove comments

* Use sequential util with deduplicateKey for thumbnail capture

* Fix E2E copy-site test targeting wrong BrowserWindow

The thumbnail capture feature creates hidden BrowserWindows for
screenshots. The copy-site test used getAllWindows()[0] to send
the IPC event, which could target the screenshot window instead
of the main app window, causing the copy action to silently fail.
Use getFocusedWindow() with a visible-window fallback instead.

---------

Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>

* Disable Redis/memcached when JSPI is unavailable (#2900)

* Disable Redis and memcached PHP extensions when JSPI is unavailable

These extensions require JSPI (JavaScript Promise Integration), which is
only available in Node.js 24+. On Node <24, enabling them crashes the
WordPress server at startup. This conditionally disables them when JSPI
isn't available, matching the pattern in process-manager-daemon.ts.

Also bumps the minimum engine version to >=24.0.0 since the production
build strips asyncify binaries, making Node 24+ a de facto requirement.

* Revert engine version bump to >=22.0.0

* Sort sites by sortOrder when loading from IPC (#2902)

* Fix regressions around deleting preview sites (#2903)

* Support deleting all preview sites from CLI and app

* Update tests

* Fix

* Improve schemas and types

* Tweak

* Fix JSPI detection using runtime feature check (#2906)

* Fix JSPI detection using runtime feature check instead of Node version

Replace semver.gte(process.version, '24.0.0') with a runtime check for
WebAssembly.promising to detect JSPI availability. The version check
assumed Node 24+ has JSPI enabled by default, but it requires the
--experimental-wasm-jspi flag. This caused "Redis extension requires
JSPI" errors when running CLI commands directly without the flag.

Extract the check into a shared isJspiAvailable helper in
tools/common/lib/jspi.ts so there is a single source of truth.

* Remove unverified claim about JSPI proposal stage from comment

* Fix linting

* Address review suggestions

* Pass `--experimental-wasm-jspi` to node in bin script

---------

Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7-beta2

* Minuscule CLI README tweak (#2917)

* Minuscule CLI README tweak

* Fix tests

* Address review comments

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json` (#2916)

* Rename `appdata-v1.json` to `appdata-v1.deprecated.json`

* Fix tests

* Fix tests

* Fix tests

* Fix What's New current step icon color in dark mode (#2921)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update release notes for 1.7.7 (#2905)

* Update release notes for 1.7.7

* Address review suggestions

* Ensure that language packs are bundled in `wp-files` (#2922)

* Add phpMyAdmin to What's New dialog (#2920)

* Add phpMyAdmin to What's New dialog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve wording

* Force What's New for next version

* Update phpMyAdmin illustration with dot grid background

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>

* Refactor and clean up site deletion logic in app (#2915)

* Refactor site deletion in app

* Nit fix

* [skip ci] Bump version to 1.7.7-beta3

* Emit `deleted` site event when removing empty site (#2929)

* Bump CLI version

* [skip ci] Update translations

* [skip ci] Bump version to 1.7.7

* [skip ci] Bump CLI version to 1.7.7

---------

Co-authored-by: Roberto Aranda <roberto.aranda@automattic.com>
Co-authored-by: Shaun Andrews <shaun@automattic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>
Co-authored-by: katinthehatsite <katerynakodonenko@gmail.com>
Co-authored-by: Kateryna Kodonenko <kateryna@automattic.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik.rombach.ekelund@automattic.com>
Co-authored-by: Gergely Csécsey <gergely.csecsey@automattic.com>
Co-authored-by: Ivan Ottinger <ivan.ottinger@automattic.com>
Co-authored-by: Bernardo Cotrim <bmmcotrim@gmail.com>
Co-authored-by: Fredrik Rombach Ekelund <fredrik@f26d.dev>
Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
Co-authored-by: Wojtek Naruniec <wojtek.naruniec@automattic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants