Skip to content

Conversation

@Seismix
Copy link

@Seismix Seismix commented Jan 27, 2026

Overview

This PR adds support for launching browsers in WSL environments with GUI capabilities (e.g. WSLg).

Changes:

  • Updated WSL runner logic to detect GUI availability and use native browser launching when available
  • Added browser installation checks with helpful error messages when browsers are not found
  • Added tests for WSL scenarios:
    • X11 and Wayland environments
    • WSL without GUI (shows manual install warning)
    • Non-WSL environments (no behavior change)
    • Missing browser installations (helpful error messages)

Manual Testing

Prerequisites:

  • WSL2 with GUI support (WSLg on Windows 11, or X11/Wayland server with DISPLAY/WAYLAND_DISPLAY set)
  • Firefox or Chrome installed in WSL

Test steps:

  1. Follow the setup instructions in CONTRIBUTING.md
  2. Start the demo extension: cd packages/wxt-demo && pnpm dev:firefox (or pnpm dev for Chrome)
  3. Verify browser opens automatically with extension loaded

Expected results:

  • Browser should open automatically in WSL with GUI
  • Extension should load correctly
  • No "Cannot open browser" warnings

Related Issue

This PR closes #1931

@netlify
Copy link

netlify bot commented Jan 27, 2026

Deploy Preview for creative-fairy-df92c4 failed.

Name Link
🔨 Latest commit 038015e
🔍 Latest deploy log https://app.netlify.com/projects/creative-fairy-df92c4/deploys/6978ac2ccd9f800008fd4c8c

The lockfile accidentally bumped tsdown from 0.18.1 to 0.18.4, which
doesn't properly transpile the `using` keyword, causing build failures.
@Seismix Seismix marked this pull request as draft January 29, 2026 07:29
@Seismix
Copy link
Author

Seismix commented Jan 29, 2026

packages/runner/src/install.ts uses the using keyword (Explicit Resource Management):

using bidi = await createBidiConnection(debuggerUrl);

During development these build failures weren't happening because of a Node version mismatch between my env and the CI env.
CI runs Node 22 which doesn't support this without the --js-explicit-resource-management flag. Node 24 has it enabled by default, which is why it worked locally for me.

As far as I can tell, previous builds had @wxt-dev/runner cached. My changes to browser-paths.ts invalidated that cache, so now it actually tries to rebuild and fails.

Can I get input on this? I marked the PR as draft in the meantime.

@PatrykKuniczak
Copy link
Collaborator

@Seismix Let's rebase in the near future because we'll have changes aroud runner in #2079
This can help you or you'll need to change your approach.

Anyway node 24 should be supported by us, because it was the newest LTS version.
If you need to use v24, feel free to open PR, where you change necessary version from 18 to 24, here:

wxt/package.json

Lines 4 to 6 in 1fe0730

"engines": {
"node": ">=18.20.3"
},

I hope @aklinker1 won't have any arguments to block this change, but we'll see 😆

@aklinker1
Copy link
Member

aklinker1 commented Feb 9, 2026

This has gone way beyond the amount of work I thought was required based off the issue discussion...

Let's pause for a second, does web-ext support WSL? If so, just remove this if-statement:

if (isWsl()) return createWslRunner();

If not, add support for WSL over there: https://github.com/mozilla/web-ext

WXT relies on web-ext to open the browser, seems like this work should go there, not in WXT.

Ignore the @wxt-dev/runner package for now, it's not ready for use.

@Seismix
Copy link
Author

Seismix commented Feb 9, 2026

You're right @aklinker1 , web-ext does partially support WSL. After testing on WSL2 + WSLg:

  • Firefox: Works out of the box via web-ext. wxt dev -b firefox launches Firefox and installs the extension with no issues.
  • Chrome: web-ext run -t chromium by itself does launch Chrome and load the extension, but it still creates a malformed UNC profile path (\\wsl.localhost\...) due to chrome-launcher. There's no web-ext flag to prevent this. The conversion happens unconditionally inside chrome-launcher. When used through WXT's programmatic API (web-ext-run), this causes an ECONNRESET crash on the CDP pipe.

The work on the wsl-runner branch was trying to work around the following bugs. But it makes more sense to fix them at the source.

Investigation

There are two upstream bugs at play:

  1. chrome-launcher unconditionally converts --user-data-dir to a Windows UNC path (\\wsl.localhost\...) when it detects WSL:
    https://github.com/GoogleChrome/chrome-launcher/blob/fe7654fbfd1ed651be9d576b6b46592b70e5b693/src/chrome-launcher.ts#L198
    Even when Chrome is running as a native Linux process under WSLg. This causes Chrome's remote debugging pipe to reset. Known upstream:
  1. web-ext-run doesn't attach an error handler to the outgoing CDP pipe https://github.com/aklinker1/web-ext-run/blob/master/src/extension-runners/chromium.js#L67, compared with the incoming pipe which has error handling at https://github.com/aklinker1/web-ext-run/blob/master/src/extension-runners/chromium.js#L57. When the pipe resets, it becomes an unhandled 'error' event that crashes the Node.js process.

Possible solutions

  1. Minimal: Remove the WSL runner, warn for Chromium: Delete the old WSL runner (which was a no-op for all browsers anyway), let Firefox go through web-ext normally, and show a warning + manual fallback for Chromium in WSL until the upstream bugs are fixed. Possibly drop the is-wsl dependency (use an inline /proc/version check instead).

  2. Patch dependencies via pnpm: Apply pnpm patch to both chrome-launcher (skip toWin32Path() when a GUI display is available) and web-ext-run (add error handler on the outgoing CDP pipe). This would make Chrome work in WSL immediately without waiting for upstream fixes:

    possible chrome-launcher fix:

    const hasDisplay = process.env.DISPLAY || process.env.WAYLAND_DISPLAY;
    flags.push(
      `--user-data-dir=${isWsl && !hasDisplay ? toWin32Path(this.userDataDir) : this.userDataDir}`,
    );

    possible web-ext-run fix:

    outgoing.on('error', error => {
      log.error(error);
      this.#finalizeDisconnect();
    });
    outgoing.on('close', () => this.#finalizeDisconnect());
  3. Fix upstream + option 1 as interim: Submit PRs to chrome-launcher and web-ext-run, use option 1 in WXT as a temporary measure, and remove the WSL check entirely once the upstream fixes land.

  4. Combinations?

Branches

I've created branches for demonstration purposes:

What next

How should I move forward?

@aklinker1
Copy link
Member

I like option 3 - interim solution + upstream support.

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.

WSL runner should check DISPLAY env var before refusing to open browser (WSLg support)

3 participants