From a4b61640fcc6c24ce38ce1b289c9e9d2381c15c9 Mon Sep 17 00:00:00 2001 From: Josh Faigan Date: Thu, 5 Feb 2026 14:16:01 -0500 Subject: [PATCH] Fix issue where profile URL's were not opening on Windows WSL --- .../theme/src/cli/services/profile.test.ts | 32 ++++++++++++++++++- packages/theme/src/cli/services/profile.ts | 18 +++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/theme/src/cli/services/profile.test.ts b/packages/theme/src/cli/services/profile.test.ts index fdf86ce1af1..7af13d073bb 100644 --- a/packages/theme/src/cli/services/profile.test.ts +++ b/packages/theme/src/cli/services/profile.test.ts @@ -2,7 +2,7 @@ import {profile} from './profile.js' import {render} from '../utilities/theme-environment/storefront-renderer.js' import {ensureAuthenticatedStorefront} from '@shopify/cli-kit/node/session' import {openURL} from '@shopify/cli-kit/node/system' -import {vi, describe, expect, beforeEach, test} from 'vitest' +import {vi, describe, expect, beforeEach, afterEach, test} from 'vitest' import {outputResult} from '@shopify/cli-kit/node/output' import {AbortError} from '@shopify/cli-kit/node/error' import {readFile} from 'fs/promises' @@ -121,4 +121,34 @@ describe('profile', () => { ), ) }) + + describe('WSL path conversion', () => { + afterEach(() => { + vi.unstubAllEnvs() + }) + + test('converts paths to WSL format when WSL_DISTRO_NAME is set', async () => { + // Given + vi.stubEnv('WSL_DISTRO_NAME', 'Ubuntu') + vi.mocked(openURL).mockResolvedValue(true) + + // When + await profile(mockAdminSession, themeId, urlPath, false, undefined, undefined) + + // Then + expect(openURL).toHaveBeenCalledWith(expect.stringMatching(/^file:\/\/\/\/wsl\$\/Ubuntu.*\.html$/)) + }) + + test('does not convert paths when WSL_DISTRO_NAME is not set', async () => { + // Given + vi.stubEnv('WSL_DISTRO_NAME', '') + vi.mocked(openURL).mockResolvedValue(true) + + // When + await profile(mockAdminSession, themeId, urlPath, false, undefined, undefined) + + // Then + expect(openURL).toHaveBeenCalledWith(expect.stringMatching(/^file:\/\/.*\.html$/)) + }) + }) }) diff --git a/packages/theme/src/cli/services/profile.ts b/packages/theme/src/cli/services/profile.ts index 5aa13179c8a..7df4a8c3f16 100644 --- a/packages/theme/src/cli/services/profile.ts +++ b/packages/theme/src/cli/services/profile.ts @@ -57,6 +57,12 @@ export async function profile( async function openProfile(profileJson: string) { // Adapted from https://github.com/jlfwong/speedscope/blob/146477a8508a6d2da697cb0ea0a426ba81b3e8dc/bin/cli.js#L63 + + // on Windows Subsystem for Linux, we need to prefix file paths with the + // WSL distro name to get them to open in the browser. + const distroName = process.env.WSL_DISTRO_NAME + const wslPrefix = distroName ? `//wsl$/${distroName}` : '' + let urlToOpen = await resolveAssetPath('speedscope', 'index.html') outputDebug(`[Theme Profile] Resolved URL to open: ${urlToOpen}`) @@ -65,20 +71,26 @@ async function openProfile(profileJson: string) { const jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(sourceBase64)})` const filePrefix = `speedscope-${Number(new Date())}-${process.pid}` - const jsPath = joinPath(tempDirectory(), `${filePrefix}.js`) + let jsPath = joinPath(tempDirectory(), `${filePrefix}.js`) outputDebug(`[Theme Profile] writing JS file to: ${jsPath}`) await writeFile(jsPath, jsSource) outputDebug(`[Theme Profile] JS file created successfully: ${jsPath}`) - urlToOpen += `#localProfilePath=${jsPath}` + + urlToOpen = `${wslPrefix}${urlToOpen}` + jsPath = `${wslPrefix}${jsPath}` // For some silly reason, the OS X open command ignores any query parameters or hash parameters // passed as part of the URL. To get around this weird issue, we'll create a local HTML file // that just redirects. - const htmlPath = joinPath(tempDirectory(), `${filePrefix}.html`) + urlToOpen += `#localProfilePath=${jsPath}` + + let htmlPath = joinPath(tempDirectory(), `${filePrefix}.html`) outputDebug(`[Theme Profile] writing HTML file to: ${htmlPath}`) await writeFile(htmlPath, ``) outputDebug(`[Theme Profile] HTML file created successfully: ${htmlPath}`) + htmlPath = `${wslPrefix}${htmlPath}` + urlToOpen = `file://${htmlPath}` outputDebug(`[Theme Profile] Opening URL: ${urlToOpen}`) const opened = await openURL(urlToOpen)