Skip to content

Commit f5e9fca

Browse files
Use default browser when opening devtools (#9975)
* Use default browser * Create wise-pillows-brake.md * fix lint * Fix TypeScript errors in ProxyController for devtools proxy Co-Authored-By: [email protected] <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 9216d93 commit f5e9fca

File tree

5 files changed

+92
-71
lines changed

5 files changed

+92
-71
lines changed

.changeset/wise-pillows-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Use default browser when opening devtools using the `[d]` hotkey

packages/wrangler/src/api/startDevWorker/ProxyController.ts

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
33
import events from "node:events";
44
import path from "node:path";
55
import { LogLevel, Miniflare, Mutex, Response } from "miniflare";
6+
import dedent from "ts-dedent";
67
import inspectorProxyWorkerPath from "worker:startDevWorker/InspectorProxyWorker";
78
import proxyWorkerPath from "worker:startDevWorker/ProxyWorker";
89
import WebSocket from "ws";
@@ -103,7 +104,7 @@ export class ProxyController extends Controller<ProxyControllerEventMap> {
103104
// However, the proxy worker only makes outgoing requests to the user Worker Miniflare instance, which _should_ receive CF-Connecting-IP
104105
stripCfConnectingIp: false,
105106
serviceBindings: {
106-
PROXY_CONTROLLER: async (req): Promise<Response> => {
107+
PROXY_CONTROLLER: async (req: Request): Promise<Response> => {
107108
const message =
108109
(await req.json()) as ProxyWorkerOutgoingRequestBody;
109110

@@ -142,43 +143,76 @@ export class ProxyController extends Controller<ProxyControllerEventMap> {
142143
};
143144

144145
if (this.latestConfig.dev.inspector !== false && !inVscodeJsDebugTerminal) {
145-
proxyWorkerOptions.workers.push({
146-
name: "InspectorProxyWorker",
147-
compatibilityDate: "2023-12-18",
148-
compatibilityFlags: [
149-
"nodejs_compat",
150-
"increase_websocket_message_size",
151-
],
152-
modulesRoot: path.dirname(inspectorProxyWorkerPath),
153-
modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }],
154-
durableObjects: {
155-
DURABLE_OBJECT: {
156-
className: "InspectorProxyWorker",
157-
unsafePreventEviction: true,
146+
proxyWorkerOptions.workers.push(
147+
{
148+
name: "InspectorProxyWorker",
149+
compatibilityDate: "2023-12-18",
150+
compatibilityFlags: [
151+
"nodejs_compat",
152+
"increase_websocket_message_size",
153+
],
154+
modulesRoot: path.dirname(inspectorProxyWorkerPath),
155+
modules: [{ type: "ESModule", path: inspectorProxyWorkerPath }],
156+
durableObjects: {
157+
DURABLE_OBJECT: {
158+
className: "InspectorProxyWorker",
159+
unsafePreventEviction: true,
160+
},
158161
},
159-
},
160-
serviceBindings: {
161-
PROXY_CONTROLLER: async (req): Promise<Response> => {
162-
const body =
163-
(await req.json()) as InspectorProxyWorkerOutgoingRequestBody;
162+
serviceBindings: {
163+
PROXY_CONTROLLER: async (req: Request): Promise<Response> => {
164+
const body =
165+
(await req.json()) as InspectorProxyWorkerOutgoingRequestBody;
164166

165-
return this.onInspectorProxyWorkerRequest(body);
167+
return this.onInspectorProxyWorkerRequest(body);
168+
},
166169
},
170+
bindings: {
171+
PROXY_CONTROLLER_AUTH_SECRET: this.secret,
172+
},
173+
174+
unsafeDirectSockets: [
175+
{
176+
host: this.latestConfig.dev?.inspector?.hostname,
177+
port: this.latestConfig.dev?.inspector?.port ?? 0,
178+
},
179+
],
180+
// no need to use file-system, so don't
181+
cache: false,
182+
unsafeEphemeralDurableObjects: true,
167183
},
168-
bindings: {
169-
PROXY_CONTROLLER_AUTH_SECRET: this.secret,
170-
},
184+
{
185+
name: "DevtoolsProxyWorker",
186+
compatibilityDate: "2025-01-01",
187+
modules: [
188+
{
189+
type: "ESModule",
190+
contents: dedent/* javascript */ `
191+
export default {
192+
fetch(request) {
193+
const url = new URL(request.url);
194+
url.host = "devtools.devprod.cloudflare.dev"
195+
url.protocol = "https"
196+
url.port = 443
197+
return fetch(url.toString(), request)
198+
}
199+
}
200+
`,
201+
path: "index.js",
202+
},
203+
],
204+
unsafeDirectSockets: [
205+
{
206+
host: this.latestConfig.dev?.inspector?.hostname,
207+
port: 0,
208+
},
209+
],
171210

172-
unsafeDirectSockets: [
173-
{
174-
host: this.latestConfig.dev?.inspector?.hostname,
175-
port: this.latestConfig.dev?.inspector?.port ?? 0,
176-
},
177-
],
178-
// no need to use file-system, so don't
179-
cache: false,
180-
unsafeEphemeralDurableObjects: true,
181-
});
211+
// no need to use file-system, so don't
212+
cache: false,
213+
unsafeEphemeralDurableObjects: true,
214+
}
215+
);
182216
}
183217

184218
const proxyWorkerOptionsChanged = didMiniflareOptionsChange(
@@ -212,10 +246,13 @@ export class ProxyController extends Controller<ProxyControllerEventMap> {
212246
this.latestConfig.dev.inspector === false || inVscodeJsDebugTerminal
213247
? Promise.resolve(undefined)
214248
: proxyWorker.unsafeGetDirectURL("InspectorProxyWorker"),
249+
this.latestConfig.dev.inspector === false || inVscodeJsDebugTerminal
250+
? Promise.resolve(undefined)
251+
: proxyWorker.unsafeGetDirectURL("DevtoolsProxyWorker"),
215252
])
216-
.then(([url, inspectorUrl]) => {
253+
.then(([url, inspectorUrl, devtoolsUrl]) => {
217254
if (!inspectorUrl || inVscodeJsDebugTerminal) {
218-
return [url, undefined];
255+
return [url, undefined, undefined];
219256
}
220257
// Don't connect the inspector proxy worker until we have a valid ready Miniflare instance.
221258
// Otherwise, tearing down the ProxyController immediately after setting it up
@@ -224,11 +261,12 @@ export class ProxyController extends Controller<ProxyControllerEventMap> {
224261
return this.reconnectInspectorProxyWorker().then(() => [
225262
url,
226263
inspectorUrl,
264+
devtoolsUrl,
227265
]);
228266
})
229-
.then(([url, inspectorUrl]) => {
267+
.then(([url, inspectorUrl, devtoolsUrl]) => {
230268
assert(url);
231-
this.emitReadyEvent(proxyWorker, url, inspectorUrl);
269+
this.emitReadyEvent(proxyWorker, url, inspectorUrl, devtoolsUrl);
232270
})
233271
.catch((error) => {
234272
if (this._torndown) {
@@ -575,13 +613,15 @@ export class ProxyController extends Controller<ProxyControllerEventMap> {
575613
emitReadyEvent(
576614
proxyWorker: Miniflare,
577615
url: URL,
578-
inspectorUrl: URL | undefined
616+
inspectorUrl: URL | undefined,
617+
devtoolsUrl: URL | undefined
579618
) {
580619
const data: ReadyEvent = {
581620
type: "ready",
582621
proxyWorker,
583622
url,
584623
inspectorUrl,
624+
devtoolsUrl,
585625
};
586626

587627
this.emit("ready", data);

packages/wrangler/src/api/startDevWorker/events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export type ReadyEvent = {
8787
type: "ready";
8888
proxyWorker: Miniflare;
8989
url: URL;
90+
devtoolsUrl: URL | undefined;
9091
inspectorUrl: URL | undefined;
9192
};
9293

packages/wrangler/src/dev/hotkeys.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ export default function registerDevHotKeys(
2727
// Don't display this hotkey if we're in a VSCode debug session
2828
disabled: !!process.env.VSCODE_INSPECTOR_OPTIONS,
2929
handler: async () => {
30-
const { inspectorUrl } = await primaryDevEnv.proxy.ready.promise;
30+
const { inspectorUrl, devtoolsUrl } =
31+
await primaryDevEnv.proxy.ready.promise;
3132

32-
if (!inspectorUrl) {
33+
if (!inspectorUrl || !devtoolsUrl) {
3334
logger.warn("DevTools is not available while in a debug terminal");
3435
} else {
3536
// TODO: refactor this function to accept a whole URL (not just .port and assuming .hostname)
3637
await openInspector(
38+
devtoolsUrl,
3739
parseInt(inspectorUrl.port),
3840
primaryDevEnv.config.latestConfig?.name
3941
);

packages/wrangler/src/dev/inspect.ts

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { readFileSync } from "fs";
2-
import os from "node:os";
32
import { fileURLToPath, URL } from "node:url";
43
import path from "path";
54
import open from "open";
@@ -249,6 +248,7 @@ export function maybeHandleNetworkLoadResource(
249248
* Opens the chrome debugger
250249
*/
251250
export const openInspector = async (
251+
devtoolsUrl: URL,
252252
inspectorPort: number,
253253
worker: string | undefined
254254
) => {
@@ -259,37 +259,10 @@ export const openInspector = async (
259259
query.set("domain", worker);
260260
}
261261
query.set("debugger", "true");
262-
const url = `https://devtools.devprod.cloudflare.dev/js_app?${query.toString()}`;
263-
const errorMessage =
264-
"Failed to open inspector.\nInspector depends on having a Chromium-based browser installed, maybe you need to install one?";
262+
const url = new URL(`/js_app?${query.toString()}`, devtoolsUrl);
263+
const errorMessage = "Failed to open inspector.";
265264

266-
// see: https://github.com/sindresorhus/open/issues/177#issue-610016699
267-
let braveBrowser: string;
268-
switch (os.platform()) {
269-
case "darwin":
270-
case "win32":
271-
braveBrowser = "Brave";
272-
break;
273-
default:
274-
braveBrowser = "brave";
275-
}
276-
277-
const childProcess = await open(url, {
278-
app: [
279-
{
280-
name: open.apps.chrome,
281-
},
282-
{
283-
name: braveBrowser,
284-
},
285-
{
286-
name: open.apps.edge,
287-
},
288-
{
289-
name: open.apps.firefox,
290-
},
291-
],
292-
});
265+
const childProcess = await open(url.href);
293266
childProcess.on("error", () => {
294267
logger.warn(errorMessage);
295268
});

0 commit comments

Comments
 (0)