Skip to content

Fix Xdebug hang in packaged Electron apps#3125

Merged
mho22 merged 3 commits intoWordPress:trunkfrom
epeicher:stu-1183-site-with-xdebug-enabled-doesnt-start-when-using-built
Jan 26, 2026
Merged

Fix Xdebug hang in packaged Electron apps#3125
mho22 merged 3 commits intoWordPress:trunkfrom
epeicher:stu-1183-site-with-xdebug-enabled-doesnt-start-when-using-built

Conversation

@epeicher
Copy link
Copy Markdown
Contributor

@epeicher epeicher commented Jan 15, 2026

Related to STU-1183

Summary

  • Fixes a hang when Xdebug is enabled in packaged Electron applications (production mode)
  • Root cause: process.cwd() returns / in packaged Electron apps, and attempting to mount the entire root filesystem via NODEFS causes the runtime to hang
  • Solution: Skip NODEFS mount when cwd is /

Problem

When running WordPress Playground CLI with Xdebug enabled inside a packaged Electron app, the application would hang indefinitely during PHP runtime initialization. This only occurred in production builds, not in development mode.

Root Cause

The with-xdebug.ts file mounts process.cwd() using NODEFS to allow Xdebug to sync with the debugger. In packaged Electron apps, process.cwd() returns / (the root filesystem), and attempting to mount / via NODEFS hangs the runtime as it tries to access the entire filesystem.

Solution

Added a check to skip the NODEFS mount when cwd is /. This is safe because:

  1. The mount is primarily for debugging PHP files in the current working directory
  2. When cwd is /, there's no meaningful project directory to mount anyway
  3. Xdebug will still work for PHP files written to the virtual filesystem

Test plan

  • Test Xdebug functionality in development mode (should still work)
  • Test Xdebug functionality in packaged Electron app (should no longer hang)
  • Verify Xdebug can still debug PHP files in the virtual filesystem

Skip mounting process.cwd() when it equals '/' to prevent hanging.

In packaged Electron apps, process.cwd() returns '/' (root directory).
The previous code attempted to mount the entire root filesystem using
NODEFS, which caused the PHP runtime initialization to hang indefinitely.

This fix checks if cwd is '/' and skips the mount operation in that case,
allowing Xdebug to work properly in production Electron environments.
@epeicher epeicher force-pushed the stu-1183-site-with-xdebug-enabled-doesnt-start-when-using-built branch from 30e2b41 to adbfba2 Compare January 15, 2026 13:54
@adamziel
Copy link
Copy Markdown
Collaborator

While not mounting / makes sense and indicates an obvious problem, won't this create another problem where XDebug won't be see the project files? Which means breakpoints won't work? It sounds like we need a way of passing the PHP site path to withXdebug() so it can be used instead of process.cwd(). WDYT?

@epeicher
Copy link
Copy Markdown
Contributor Author

epeicher commented Jan 16, 2026

@adamziel that was my initial thought when looking at the changes, but I am able to debug with the packaged version of Studio and using npm start in Studio. According to Claude:

NODEFS mount is not needed because:

  1. WordPress is written to /wordpress/ in MEMFS
  2. Xdebug reports /wordpress/... paths
  3. IDE path mapping handles translation

So maybe we could remove phpRuntime.FS.mount?

EDIT: I have tested locally removing that mounting (commit 2fbf899) and debugging works fine for me using PHPStorm, I can add breakpoints and step through the code. Should I push the changes for review?

@epeicher epeicher force-pushed the stu-1183-site-with-xdebug-enabled-doesnt-start-when-using-built branch from 2fbf899 to 67ab9f4 Compare January 16, 2026 12:20
@adamziel
Copy link
Copy Markdown
Collaborator

adamziel commented Jan 16, 2026

This is weird! I remember we've tweaked this exact mount specifically to get the path mapping to work. Or was it the path mapping in the browser devtools and not in the IDE? 🤔 In which case we're missing a unit test to keep that part working. Let's get some input from @mho22 or @brandonpayton here.

@mho22
Copy link
Copy Markdown
Collaborator

mho22 commented Jan 26, 2026

@adam @epeicher Before Xdebug 3.5, path mapping didn't exist and absolute paths were used to make Xdebug step debugging find files, this means PHP.wasm virtual filesystem needs to mount the current working directory to create these absolute paths. That is why we run :

with-xdebug.ts on line 89 :

phpRuntime.FS.mkdirTree(process.cwd());
phpRuntime.FS.mount(
    phpRuntime.FS.filesystems['NODEFS'],
    { root: process.cwd() },
    process.cwd()
);
phpRuntime.FS.chdir(process.cwd());

But this could probably be replaced by IDEs path mappings and Xdebug 3.5 path mappings. I am currently working on an exploratory pull request.

In the meantime we could merge this since it won't break the previous behavior and avoid breaking the Electron one. But this doesn't mean Xdebug will work correctly in Electron without IDEs path mappings.

Edit: It seems a patch has been merged on Studio waiting for this issue to be fixed but we still can merge this one.

@mho22 mho22 merged commit 44dee5c into WordPress:trunk Jan 26, 2026
33 checks passed
@epeicher epeicher deleted the stu-1183-site-with-xdebug-enabled-doesnt-start-when-using-built branch January 26, 2026 12:32
@epeicher
Copy link
Copy Markdown
Contributor Author

Thanks for explanation and for merging this @mho22!

It seems a patch has been merged on Studio waiting for this issue to be fixed but we still can merge this one.

Yes, that's right, we merged a patch to this package to unblock the XDebug timeout for the release, but we plan to delete it after upgrading to this version.

adamziel added a commit that referenced this pull request Jan 28, 2026
## Summary

Follows up on #3125 in an attempt to finally resolve #3064.

#3125 introduced a `fetch("main.js")` to bust the Safari cache and load
that ES module after a page reload. That solution turned out to be,
unfortunately, flaky.

This PR retries to import `main.js` with a cache buster string,
similarly to `import("main.js?_ts=178961653")`. It seems to have worked
for me during testing. Fingers crossed it solves it once and for all!

## The Problem

As documented in #3215, Safari sometimes fails with "TypeError:
Importing a module script failed" when trying to import the main module
after a new deployment. The previous solution (fetch + page reload)
worked but was heavy-handed.

## Test plan

1. Open playground.wordpress.net in Safari on iOS
2. Plug it in to a Mac with a cable
3. Open devtools for that tab in Desktop Safari
4. Deploy this PR
5. Refresh the tab on iOS
7. Confirm the website reloaded correctly
8. If you also can see the "Failed to load main module" error in the
console, this fix works.
9. If you can't, we don't know if it fully works yet.
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