打开浏览器改用 explorer.exe(shell 关联),找不到时才用 rundll32 (#29)

Windows 上先同步判断 explorer.exe 是否存在:存在就用 explorer.exe <url>,由已登录、未提权的 shell 按默认浏览器关联打开,从管理员控制台启动时浏览器不会跟着提权(Edge 不再弹「现有实例正在以提升的权限运行」);找不到 explorer.exe 才退回 rundll32 url.dll,FileProtocolHandler。不经过 cmd,URL 里的 & 不会被截断。macOS / Linux 不变。

打开浏览器的实现集中到 scripts/open-browser.mjs;scripts/launch.mjs 加 isMain() 守卫(与 tools/setup.mjs、tools/doctor.mjs 一致),被 import 时不会启动服务器。测试:test/open-browser.test.js。
This commit is contained in:
Lu Ke authored and GitHub committed 2026-10-03 23:05:06 +08:00
1 parent 0b73a39b12
commit 8b10625d3c
3 files changed
+207 -16

No files matched your search

+12 -16
View File
@@ -16,6 +16,8 @@ import { spawn, spawnSync } from 'node:child_process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import fs from 'node:fs';
// 打开浏览器只有一份实现(走 shell 关联 = 默认浏览器,且不会把浏览器拉成提权)
import { openBrowser as openInBrowser } from './open-browser.mjs';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const IS_WIN = process.platform === 'win32';
@@ -46,21 +48,7 @@ function parseArgs(argv) {
}
function openBrowser(url) {
try {
let cmd; let args;
if (IS_WIN) { cmd = 'rundll32'; args = ['url.dll,FileProtocolHandler', url]; }
else if (process.platform === 'darwin') { cmd = 'open'; args = [url]; }
else {
if (!process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) return false;
cmd = 'xdg-open'; args = [url];
}
const child = spawn(cmd, args, { stdio: 'ignore', detached: true, windowsHide: true });
child.on('error', () => {});
child.unref();
return true;
} catch {
return false;
}
return openInBrowser(url) !== null;
}
function printShare(port) {
@@ -132,4 +120,12 @@ async function main() {
return exited;
}
main().then((code) => { process.exitCode = code; }, (e) => { console.error(e?.stack || e); process.exitCode = 1; });
// Same convention as tools/setup.mjs: the helpers above are importable, but only running this file starts anything.
// Without the guard, importing launch.mjs would fall through to main() in the background and bind a port.
function isMain() {
try { return !!process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url)); } catch { return false; }
}
if (isMain()) {
main().then((code) => { process.exitCode = code; }, (e) => { console.error(e?.stack || e); process.exitCode = 1; });
}