Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 738a7f2

Browse files
committed
Add --open/-O option to auto-open browser on startup, closes #121
1 parent ae057b1 commit 738a7f2

File tree

10 files changed

+162
-6
lines changed

10 files changed

+162
-6
lines changed

package-lock.json

Lines changed: 88 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/http-server/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { HTTPPlugin, RequestMeta } from "./plugin";
2323
export * from "./helpers";
2424
export * from "./plugin";
2525

26+
export const DEFAULT_PORT = 8787;
27+
2628
export type HTTPPluginSignatures = CorePluginSignatures & {
2729
HTTPPlugin: typeof HTTPPlugin;
2830
};
@@ -405,7 +407,7 @@ export async function startServer<Plugins extends HTTPPluginSignatures>(
405407
): Promise<http.Server | https.Server> {
406408
const server = await createServer(mf, options);
407409
const plugins = await mf.getPlugins();
408-
const { httpsEnabled, host, port = 8787 } = plugins.HTTPPlugin;
410+
const { httpsEnabled, host, port = DEFAULT_PORT } = plugins.HTTPPlugin;
409411
return new Promise((resolve) => {
410412
server.listen(port, host, () => {
411413
const log = mf.log;

packages/http-server/src/plugin.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export interface RequestMeta {
8585
export interface HTTPOptions {
8686
host?: string;
8787
port?: number;
88+
open?: boolean | string;
8889

8990
https?: boolean | string;
9091
httpsKey?: string;
@@ -127,6 +128,14 @@ export class HTTPPlugin extends Plugin<HTTPOptions> implements HTTPOptions {
127128
})
128129
port?: number;
129130

131+
@Option({
132+
type: OptionType.BOOLEAN_STRING,
133+
alias: "O",
134+
description: "Automatically open browser to URL",
135+
fromWrangler: ({ miniflare }) => miniflare?.open,
136+
})
137+
open?: boolean | string;
138+
130139
@Option({
131140
type: OptionType.BOOLEAN_STRING,
132141
description: "Enable self-signed HTTPS (with optional cert path)",

packages/http-server/test/plugin.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ test("HTTPPlugin: parses options from argv", (t) => {
3131
"127.0.0.1",
3232
"--port",
3333
"3000",
34+
"--open",
3435
"--https",
3536
"--https-key",
3637
"key.pem",
@@ -48,6 +49,7 @@ test("HTTPPlugin: parses options from argv", (t) => {
4849
t.deepEqual(options, {
4950
host: "127.0.0.1",
5051
port: 3000,
52+
open: true,
5153
https: true,
5254
httpsKeyPath: "key.pem",
5355
httpsCertPath: "cert.pem",
@@ -62,6 +64,8 @@ test("HTTPPlugin: parses options from argv", (t) => {
6264
"127.0.0.1",
6365
"-p",
6466
"3000",
67+
"-O",
68+
"https://localhost:8787",
6569
"--https",
6670
"./cert",
6771
"--cf-fetch",
@@ -70,6 +74,7 @@ test("HTTPPlugin: parses options from argv", (t) => {
7074
t.deepEqual(options, {
7175
host: "127.0.0.1",
7276
port: 3000,
77+
open: "https://localhost:8787",
7378
https: "./cert",
7479
cfFetch: "./cf.json",
7580
});
@@ -79,6 +84,7 @@ test("HTTPPlugin: parses options from wrangler config", (t) => {
7984
miniflare: {
8085
host: "127.0.0.1",
8186
port: 3000,
87+
open: true,
8288
https: true,
8389
cf_fetch: false,
8490
live_reload: true,
@@ -87,6 +93,7 @@ test("HTTPPlugin: parses options from wrangler config", (t) => {
8793
t.like(options, {
8894
host: "127.0.0.1",
8995
port: 3000,
96+
open: true,
9097
https: true,
9198
cfFetch: false,
9299
liveReload: true,
@@ -120,6 +127,7 @@ test("HTTPPlugin: logs options", (t) => {
120127
let logs = logPluginOptions(HTTPPlugin, {
121128
host: "127.0.0.1",
122129
port: 3000,
130+
open: true,
123131
https: true,
124132
httpsKey: "key",
125133
httpsKeyPath: "key.pem",
@@ -137,6 +145,7 @@ test("HTTPPlugin: logs options", (t) => {
137145
t.deepEqual(logs, [
138146
"Host: 127.0.0.1",
139147
"Port: 3000",
148+
"Open: true",
140149
"HTTPS: true",
141150
"HTTPS Key: key.pem",
142151
"HTTPS Cert: cert.pem",

packages/miniflare/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ goals:
3131
[122 third-party packages](http://npm.anvaka.com/#/view/2d/miniflare) with a
3232
total install size of `88.3MB`. Miniflare 2 reduces this to **23 packages and
3333
`6.2MB`** 🤯.
34-
3.**Correct:** Miniflare 2 more accurately replicates the quirks and thrown
34+
3.**Accurate:** Miniflare 2 more accurately replicates the quirks and thrown
3535
errors of the real Workers runtime, so you'll know before you deploy if
3636
things are going to break.
3737

packages/miniflare/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@
6868
},
6969
"devDependencies": {
7070
"@miniflare/shared-test": "2.0.0-rc.3",
71-
"@types/source-map-support": "^0.5.4"
71+
"@types/source-map-support": "^0.5.4",
72+
"open": "^8.4.0"
7273
},
7374
"peerDependencies": {
7475
"@miniflare/storage-redis": "2.0.0-rc.3",

packages/miniflare/src/api.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import {
1515
DurableObjectsPlugin,
1616
} from "@miniflare/durable-objects";
1717
import { HTMLRewriterPlugin } from "@miniflare/html-rewriter";
18-
import { HTTPPlugin, createServer, startServer } from "@miniflare/http-server";
18+
import {
19+
DEFAULT_PORT,
20+
HTTPPlugin,
21+
createServer,
22+
startServer,
23+
} from "@miniflare/http-server";
1924
import { KVNamespace, KVPlugin } from "@miniflare/kv";
2025
import { VMScriptRunner } from "@miniflare/runner-vm";
2126
import {
@@ -134,4 +139,17 @@ export class Miniflare extends MiniflareCore<Plugins> {
134139
startScheduler(): Promise<CronScheduler<Plugins>> {
135140
return startScheduler(this);
136141
}
142+
143+
async getOpenURL(): Promise<string | undefined> {
144+
const {
145+
open,
146+
httpsEnabled,
147+
host = "localhost",
148+
port = DEFAULT_PORT,
149+
} = (await this.getPlugins()).HTTPPlugin;
150+
if (!open) return;
151+
if (typeof open === "string") return open;
152+
const protocol = httpsEnabled ? "https" : "http";
153+
return `${protocol}://${host}:${port}/`;
154+
}
137155
}

packages/miniflare/src/cli.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "path";
44
import type { Options } from "@miniflare/shared";
55
import { red } from "kleur/colors";
66
import type { MiniflareOptions } from "miniflare";
7+
import open from "open";
78
import { updateCheck } from "./updater";
89

910
function suppressWarnings() {
@@ -97,6 +98,14 @@ async function main() {
9798
return;
9899
}
99100

101+
// Open browser if requested
102+
const openURL = await mf.getOpenURL();
103+
try {
104+
if (openURL) await open(openURL);
105+
} catch (e: any) {
106+
mf.log.warn("Unable to open browser: " + e.stack);
107+
}
108+
100109
// TODO: check how this works with next tag
101110
const plugins = await mf.getPlugins();
102111
// Check for updates, ignoring errors (it's not that important)

packages/miniflare/test/api.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { AddressInfo } from "net";
22
import { Log, LogLevel } from "@miniflare/shared";
3-
import { interceptConsoleLogs } from "@miniflare/shared-test";
3+
import { interceptConsoleLogs, useTmp } from "@miniflare/shared-test";
44
import test from "ava";
55
import { Miniflare, VariedStorageFactory } from "miniflare";
66
import { fetch } from "undici";
@@ -173,3 +173,23 @@ test.serial("Miniflare: startScheduler: starts CRON scheduler", async (t) => {
173173
};
174174
await mf.startScheduler();
175175
});
176+
test("Miniflare: getOpenURL: returns URL to open browser at", async (t) => {
177+
// Check returns undefined if open disabled
178+
const mf = new Miniflare({ script: "//" });
179+
t.is(await mf.getOpenURL(), undefined);
180+
await mf.setOptions({ open: false });
181+
t.is(await mf.getOpenURL(), undefined);
182+
183+
// Check returns custom string URL
184+
await mf.setOptions({ open: "https://some.other.website/" });
185+
t.is(await mf.getOpenURL(), "https://some.other.website/");
186+
187+
// Check returns http URL with default host and port
188+
await mf.setOptions({ open: true });
189+
t.is(await mf.getOpenURL(), "http://localhost:8787/");
190+
191+
// Check returns https URL with custom host and port
192+
const tmp = await useTmp(t);
193+
await mf.setOptions({ open: true, https: tmp, host: "test.mf", port: 3000 });
194+
t.is(await mf.getOpenURL(), "https://test.mf:3000/");
195+
});

packages/shared/src/wrangler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export interface WranglerEnvironmentConfig {
4646
env_path?: string;
4747
host?: string;
4848
port?: number;
49+
open?: boolean | string;
4950
cf_fetch?: boolean | string;
5051
https?:
5152
| boolean

0 commit comments

Comments
 (0)