Skip to content

Commit 8a8ec85

Browse files
committed
perf(devframe): replace open with a native spawn helper
All three call sites (adapters/dev.ts, recipes/common-rpc-functions.ts, plugins/assets's reveal-in-folder) pass a bare string target and never use open()'s options - the npm open package is inlined via tsdown onlyBundle with its full is-wsl/wsl-utils/run-applescript/ powershell-utils/default-browser* dependency tree, producing a ~19 KB dist chunk for functionality a ~30-line spawn helper covers: darwin 'open', win32 'cmd /c start', linux 'xdg-open', with WSL detection (/proc/version) preferring wslview and falling back to invoking cmd.exe directly. Drops the unused wait option along with the open dependency (and its now-unreferenced transitive shims from tsdown's onlyBundle list) - deliberate, narrow surface break; the utils/open subpath export is unchanged. Verified the new implementation fails gracefully (ENOENT, caught by the existing call-site try/catches) on a plain Linux container with none of open, xdg-open, or wslview installed.
1 parent 549ab4a commit 8a8ec85

7 files changed

Lines changed: 54 additions & 39 deletions

File tree

packages/devframe/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@
111111
"mlly": "catalog:build",
112112
"obug": "catalog:deps",
113113
"ohash": "catalog:deps",
114-
"open": "catalog:deps",
115114
"p-limit": "catalog:deps",
116115
"perfect-debounce": "catalog:deps",
117116
"structured-clone-es": "catalog:deps",
Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,59 @@
1-
import openImpl from 'open'
1+
import { spawn } from 'node:child_process'
2+
import fs from 'node:fs'
3+
import process from 'node:process'
24

3-
export interface OpenOptions {
4-
/**
5-
* Resolve only after the launched app exits.
6-
*
7-
* @default false
8-
*/
9-
wait?: boolean
5+
/**
6+
* Launches `command` detached from the current process and resolves once
7+
* the OS has accepted the spawn (not once the launched app exits) — the
8+
* same "fire and forget" behavior `open`'s default (`wait: false`) gave us.
9+
*/
10+
function spawnDetached(command: string, args: string[]): Promise<void> {
11+
return new Promise((resolve, reject) => {
12+
const child = spawn(command, args, { detached: true, stdio: 'ignore', windowsHide: true })
13+
child.once('error', reject)
14+
child.once('spawn', () => {
15+
child.unref()
16+
resolve()
17+
})
18+
})
19+
}
20+
21+
function isWsl(): boolean {
22+
if (process.platform !== 'linux')
23+
return false
24+
try {
25+
return fs.readFileSync('/proc/version', 'utf-8').toLowerCase().includes('microsoft')
26+
}
27+
catch {
28+
return false
29+
}
1030
}
1131

1232
/**
1333
* Open a URL, file, or other target in its default OS handler
1434
* (browser for URLs, Finder/Explorer for paths, etc.).
1535
*/
16-
export async function open(target: string, options?: OpenOptions): Promise<void> {
17-
await openImpl(target, options)
36+
export async function open(target: string): Promise<void> {
37+
if (process.platform === 'darwin')
38+
return spawnDetached('open', [target])
39+
40+
if (process.platform === 'win32') {
41+
// `start` is a cmd.exe builtin; the empty title argument keeps `target`
42+
// from being mistaken for a window title when it's itself quoted.
43+
return spawnDetached('cmd', ['/c', 'start', '""', target])
44+
}
45+
46+
if (isWsl()) {
47+
// `wslview` (from wslu) hands the target to the Windows shell the same
48+
// way an interactive user would; fall back to invoking `cmd.exe`
49+
// directly on WSL distros that don't have wslu installed.
50+
try {
51+
return await spawnDetached('wslview', [target])
52+
}
53+
catch {
54+
return spawnDetached('cmd.exe', ['/c', 'start', '""', target])
55+
}
56+
}
57+
58+
return spawnDetached('xdg-open', [target])
1859
}

packages/devframe/tsdown.config.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,20 @@ const deps = {
3636
},
3737
onlyBundle: [
3838
'acorn',
39-
'bundle-name',
40-
'default-browser',
41-
'default-browser-id',
42-
'define-lazy-prop',
4339
'get-port-please',
4440
'immer',
45-
'is-docker',
46-
'is-in-ssh',
47-
'is-inside-container',
48-
'is-wsl',
4941
'launch-editor',
5042
'mlly',
5143
'obug',
5244
'ohash',
53-
'open',
5445
'p-limit',
5546
'perfect-debounce',
5647
'picocolors',
57-
'powershell-utils',
58-
'run-applescript',
5948
'shell-quote',
6049
'structured-clone-es',
6150
'tinyexec',
6251
'ua-parser-modern',
6352
'whenexpr',
64-
'wsl-utils',
6553
'yocto-queue',
6654
],
6755
}

pnpm-lock.yaml

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ catalogs:
9595
nostics: ^1.2.0
9696
obug: ^2.1.4
9797
ohash: ^2.0.11
98-
open: ^11.0.0
9998
p-limit: ^7.3.1
10099
parse5: ^8.0.1
101100
pathe: ^2.0.3
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
/**
22
* Generated by tsnapi — public API snapshot of `devframe/utils/open`
33
*/
4-
// #region Interfaces
5-
export interface OpenOptions {
6-
wait?: boolean;
7-
}
8-
// #endregion
9-
104
// #region Functions
11-
export declare function open(_: string, _?: OpenOptions): Promise<void>;
5+
export declare function open(_: string): Promise<void>;
126
// #endregion
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Generated by tsnapi — public API snapshot of `devframe/utils/open`
33
*/
4-
// #region Other
5-
export { open }
4+
// #region Functions
5+
export async function open(_) {}
66
// #endregion

0 commit comments

Comments
 (0)