From 61669e55cedee90ac2168a363de348cdb5d90e30 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 17:30:39 -0400 Subject: [PATCH 1/8] test(hmr): do not assume stderr will be empty --- integration/hmr-log-test.ts | 14 ++++++++++---- integration/hmr-test.ts | 17 +++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/integration/hmr-log-test.ts b/integration/hmr-log-test.ts index 1a9fe3af396..7bc63b98d88 100644 --- a/integration/hmr-log-test.ts +++ b/integration/hmr-log-test.ts @@ -470,7 +470,7 @@ whatsup await page.getByText("Hello, planet").waitFor({ timeout: HMR_TIMEOUT_MS }); await page.waitForLoadState("networkidle"); - expect(devStderr()).toBe(""); + let stderr = devStderr(); let withSyntaxError = ` import { useLoaderData } from "@remix-run/react"; export function shouldRevalidate(args) { @@ -486,9 +486,15 @@ whatsup } `; fs.writeFileSync(indexPath, withSyntaxError); - await wait(() => devStderr().includes('Expected ";" but found "efault"'), { - timeoutMs: HMR_TIMEOUT_MS, - }); + await wait( + () => + devStderr() + .replace(stderr, "") + .includes('Expected ";" but found "efault"'), + { + timeoutMs: HMR_TIMEOUT_MS, + } + ); let withFix = ` import { useLoaderData } from "@remix-run/react"; diff --git a/integration/hmr-test.ts b/integration/hmr-test.ts index 6f6b63fd291..8001597d5cf 100644 --- a/integration/hmr-test.ts +++ b/integration/hmr-test.ts @@ -69,14 +69,13 @@ let fixture = (options: { const app = express(); app.use(express.static("public", { immutable: true, maxAge: "1y" })); - const MODE = process.env.NODE_ENV; const BUILD_DIR = path.join(process.cwd(), "build"); app.all( "*", createRequestHandler({ build: require(BUILD_DIR), - mode: MODE, + mode: process.env.NODE_ENV, }) ); @@ -469,7 +468,7 @@ whatsup await page.getByText("Hello, planet").waitFor({ timeout: HMR_TIMEOUT_MS }); await page.waitForLoadState("networkidle"); - expect(devStderr()).toBe(""); + let stderr = devStderr(); let withSyntaxError = ` import { useLoaderData } from "@remix-run/react"; export function shouldRevalidate(args) { @@ -485,9 +484,15 @@ whatsup } `; fs.writeFileSync(indexPath, withSyntaxError); - await wait(() => devStderr().includes('Expected ";" but found "efault"'), { - timeoutMs: HMR_TIMEOUT_MS, - }); + await wait( + () => + devStderr() + .replace(stderr, "") + .includes('Expected ";" but found "efault"'), + { + timeoutMs: HMR_TIMEOUT_MS, + } + ); let withFix = ` import { useLoaderData } from "@remix-run/react"; From 43adafb86f1b34ec60ee241ba6df540c17f03b95 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 17:31:15 -0400 Subject: [PATCH 2/8] fix(dev): stringify existing NODE_ENV for clarity --- packages/remix-dev/cli/commands.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/remix-dev/cli/commands.ts b/packages/remix-dev/cli/commands.ts index 200a7a81dc6..450a11b20b0 100644 --- a/packages/remix-dev/cli/commands.ts +++ b/packages/remix-dev/cli/commands.ts @@ -229,7 +229,9 @@ export async function dev( ) { if (process.env.NODE_ENV && process.env.NODE_ENV !== "development") { console.warn( - `Forcing NODE_ENV to be 'development'. Was: ${process.env.NODE_ENV}` + `Forcing NODE_ENV to be 'development'. Was: ${JSON.stringify( + process.env.NODE_ENV + )}` ); } process.env.NODE_ENV = "development"; From c22c934b36f17e4be9a8ae21deadb96f6fb0ec28 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 15:08:13 -0400 Subject: [PATCH 3/8] feat(dev): use the same port for dev ready messages and websocket --- integration/hmr-log-test.ts | 10 +--- integration/hmr-test.ts | 10 +--- packages/remix-dev/__tests__/cli-test.ts | 1 - packages/remix-dev/cli/commands.ts | 16 +----- packages/remix-dev/cli/run.ts | 6 -- packages/remix-dev/config.ts | 1 - .../remix-dev/devServer_unstable/index.ts | 57 ++++++++++--------- .../remix-dev/devServer_unstable/socket.ts | 5 +- 8 files changed, 39 insertions(+), 67 deletions(-) diff --git a/integration/hmr-log-test.ts b/integration/hmr-log-test.ts index 7bc63b98d88..7fad0c380c7 100644 --- a/integration/hmr-log-test.ts +++ b/integration/hmr-log-test.ts @@ -9,11 +9,7 @@ import { createFixtureProject, css, js, json } from "./helpers/create-fixture"; test.setTimeout(120_000); -let fixture = (options: { - appServerPort: number; - httpPort: number; - webSocketPort: number; -}) => ({ +let fixture = (options: { appServerPort: number; httpPort: number }) => ({ files: { "remix.config.js": js` module.exports = { @@ -22,7 +18,6 @@ let fixture = (options: { future: { unstable_dev: { httpPort: ${options.httpPort}, - webSocketPort: ${options.webSocketPort}, }, v2_routeConvention: true, v2_errorBoundary: true, @@ -252,9 +247,8 @@ test("HMR", async ({ page }) => { let portRange = makeRange(4080, 4099); let appServerPort = await getPort({ port: portRange }); let httpPort = await getPort({ port: portRange }); - let webSocketPort = await getPort({ port: portRange }); let projectDir = await createFixtureProject( - fixture({ appServerPort, httpPort, webSocketPort }) + fixture({ appServerPort, httpPort }) ); // spin up dev server diff --git a/integration/hmr-test.ts b/integration/hmr-test.ts index 8001597d5cf..d2ad2e0b32a 100644 --- a/integration/hmr-test.ts +++ b/integration/hmr-test.ts @@ -9,11 +9,7 @@ import { createFixtureProject, css, js, json } from "./helpers/create-fixture"; test.setTimeout(120_000); -let fixture = (options: { - appServerPort: number; - httpPort: number; - webSocketPort: number; -}) => ({ +let fixture = (options: { appServerPort: number; httpPort: number }) => ({ files: { "remix.config.js": js` module.exports = { @@ -22,7 +18,6 @@ let fixture = (options: { future: { unstable_dev: { httpPort: ${options.httpPort}, - webSocketPort: ${options.webSocketPort}, }, v2_routeConvention: true, v2_errorBoundary: true, @@ -250,9 +245,8 @@ test("HMR", async ({ page }) => { let portRange = makeRange(3080, 3099); let appServerPort = await getPort({ port: portRange }); let httpPort = await getPort({ port: portRange }); - let webSocketPort = await getPort({ port: portRange }); let projectDir = await createFixtureProject( - fixture({ appServerPort, httpPort, webSocketPort }) + fixture({ appServerPort, httpPort }) ); // spin up dev server diff --git a/packages/remix-dev/__tests__/cli-test.ts b/packages/remix-dev/__tests__/cli-test.ts index 0ce72093343..d0b6dc5302e 100644 --- a/packages/remix-dev/__tests__/cli-test.ts +++ b/packages/remix-dev/__tests__/cli-test.ts @@ -122,7 +122,6 @@ describe("remix CLI", () => { --http-host HTTP(S) host for the dev server. Default: localhost --http-port HTTP(S) port for the dev server. Default: any open port --no-restart Do not restart the app server when rebuilds occur. - --websocket-port WebSocket port for the dev server. Default: any open port \`init\` Options: --no-delete Skip deleting the \`remix.init\` script \`routes\` Options: diff --git a/packages/remix-dev/cli/commands.ts b/packages/remix-dev/cli/commands.ts index 450a11b20b0..1623224aacb 100644 --- a/packages/remix-dev/cli/commands.ts +++ b/packages/remix-dev/cli/commands.ts @@ -183,7 +183,7 @@ export async function build( host: dev.httpHost, port: dev.httpPort, }; - options.devWebSocketPort = dev.webSocketPort; + options.devWebSocketPort = dev.httpPort; } fse.emptyDirSync(config.assetsBuildDirectory); @@ -224,7 +224,6 @@ export async function dev( httpHost?: string; httpPort?: number; restart?: boolean; - websocketPort?: number; } = {} ) { if (process.env.NODE_ENV && process.env.NODE_ENV !== "development") { @@ -477,7 +476,6 @@ type DevBuildFlags = { httpScheme: string; httpHost: string; httpPort: number; - webSocketPort: number; }; let resolveDevBuild = async ( config: RemixConfig, @@ -501,17 +499,11 @@ let resolveDevBuild = async ( flags.httpPort ?? (dev === true ? undefined : dev.httpPort) ?? (await findPort()); - // prettier-ignore - let webSocketPort = - flags.webSocketPort ?? - (dev === true ? undefined : dev.webSocketPort) ?? - (await findPort()); return { httpScheme, httpHost, httpPort, - webSocketPort, }; }; @@ -526,10 +518,7 @@ let resolveDevServe = async ( let dev = config.future.unstable_dev; if (dev === false) throw Error("Cannot resolve dev options"); - let { httpScheme, httpHost, httpPort, webSocketPort } = await resolveDevBuild( - config, - flags - ); + let { httpScheme, httpHost, httpPort } = await resolveDevBuild(config, flags); // prettier-ignore let command = @@ -563,7 +552,6 @@ let resolveDevServe = async ( httpScheme, httpHost, httpPort, - webSocketPort, restart, }; }; diff --git a/packages/remix-dev/cli/run.ts b/packages/remix-dev/cli/run.ts index 524b1bdc844..72958b13491 100644 --- a/packages/remix-dev/cli/run.ts +++ b/packages/remix-dev/cli/run.ts @@ -48,7 +48,6 @@ ${colors.logoBlue("R")} ${colors.logoGreen("E")} ${colors.logoYellow( --http-host HTTP(S) host for the dev server. Default: localhost --http-port HTTP(S) port for the dev server. Default: any open port --no-restart Do not restart the app server when rebuilds occur. - --websocket-port WebSocket port for the dev server. Default: any open port \`init\` Options: --no-delete Skip deleting the \`remix.init\` script \`routes\` Options: @@ -188,7 +187,6 @@ export async function run(argv: string[] = process.argv.slice(2)) { "--http-host": String, "--http-port": Number, "--no-restart": Boolean, - "--websocket-port": Number, }, { argv, @@ -225,10 +223,6 @@ export async function run(argv: string[] = process.argv.slice(2)) { flags.httpPort = flags["http-port"]; delete flags["http-port"]; } - if (flags["websocket-port"]) { - flags.webSocketPort = flags["websocket-port"]; - delete flags["websocket-port"]; - } if (args["--no-delete"]) { flags.delete = false; diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index ed90d95a1f9..e7927672354 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -43,7 +43,6 @@ type Dev = { httpScheme?: string; httpHost?: string; httpPort?: number; - webSocketPort?: number; restart?: boolean; publicDirectory?: string; }; diff --git a/packages/remix-dev/devServer_unstable/index.ts b/packages/remix-dev/devServer_unstable/index.ts index e4492d350a9..d8b114f01e4 100644 --- a/packages/remix-dev/devServer_unstable/index.ts +++ b/packages/remix-dev/devServer_unstable/index.ts @@ -1,5 +1,6 @@ import * as path from "node:path"; import * as stream from "node:stream"; +import * as http from "node:http"; import fs from "fs-extra"; import prettyMs from "pretty-ms"; import execa from "execa"; @@ -44,18 +45,10 @@ export let serve = async ( httpScheme: string; httpHost: string; httpPort: number; - webSocketPort: number; restart: boolean; } ) => { await loadEnv(initialConfig.rootDirectory); - let websocket = Socket.serve({ port: options.webSocketPort }); - let httpOrigin: Origin = { - scheme: options.httpScheme, - host: options.httpHost, - port: options.httpPort, - }; - let state: { appServer?: execa.ExecaChildProcess; manifest?: Manifest; @@ -65,6 +58,30 @@ export let serve = async ( prevLoaderHashes?: Record; } = {}; + let app = express() + // handle `broadcastDevReady` messages + .use(express.json()) + .post("/ping", (req, res) => { + let { buildHash } = req.body; + if (typeof buildHash !== "string") { + console.warn(`Unrecognized payload: ${req.body}`); + res.sendStatus(400); + } + if (buildHash === state.manifest?.version) { + state.appReady?.ok(); + } + res.sendStatus(200); + }); + + let server = http.createServer(app); + let websocket = Socket.serve(server); + + let httpOrigin: Origin = { + scheme: options.httpScheme, + host: options.httpHost, + port: options.httpPort, + }; + let bin = await detectBin(); let startAppServer = (command: string) => { console.log(`> ${command}`); @@ -119,7 +136,7 @@ export let serve = async ( sourcemap: true, onWarning: warnOnce, devHttpOrigin: httpOrigin, - devWebSocketPort: options.webSocketPort, + devWebSocketPort: options.httpPort, }, }, { @@ -198,28 +215,14 @@ export let serve = async ( } ); - let httpServer = express() - // handle `broadcastDevReady` messages - .use(express.json()) - .post("/ping", (req, res) => { - let { buildHash } = req.body; - if (typeof buildHash !== "string") { - console.warn(`Unrecognized payload: ${req.body}`); - res.sendStatus(400); - } - if (buildHash === state.manifest?.version) { - state.appReady?.ok(); - } - res.sendStatus(200); - }) - .listen(httpOrigin.port, () => { - console.log("Remix dev server ready"); - }); + server.listen(httpOrigin.port, () => { + console.log("Remix dev server ready"); + }); return new Promise(() => {}).finally(async () => { await kill(state.appServer); websocket.close(); - httpServer.close(); + server.close(); await dispose(); }); }; diff --git a/packages/remix-dev/devServer_unstable/socket.ts b/packages/remix-dev/devServer_unstable/socket.ts index 83ea95fb5ca..a66ca95a0db 100644 --- a/packages/remix-dev/devServer_unstable/socket.ts +++ b/packages/remix-dev/devServer_unstable/socket.ts @@ -1,4 +1,5 @@ import WebSocket from "ws"; +import type { Server as HTTPServer } from "http"; import { type Manifest } from "../manifest"; import type * as HMR from "./hmr"; @@ -14,8 +15,8 @@ type Message = type Broadcast = (message: Message) => void; -export let serve = (options: { port: number }) => { - let wss = new WebSocket.Server({ port: options.port }); +export let serve = (server: HTTPServer) => { + let wss = new WebSocket.Server({ server }); let broadcast: Broadcast = (message) => { wss.clients.forEach((client) => { From 8ce187c8efccf42b721ab1bba6cf06a7d3dbef2e Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 17:37:27 -0400 Subject: [PATCH 4/8] refactor(dev): remove vestigial publicDirectory option --- packages/remix-dev/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index e7927672354..4e22c9d701d 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -44,7 +44,6 @@ type Dev = { httpHost?: string; httpPort?: number; restart?: boolean; - publicDirectory?: string; }; interface FutureConfig { From f987ed7a27c05c9ccab471bf47f1146fe7308b49 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 21:37:07 -0400 Subject: [PATCH 5/8] refactor(dev): rename scheme, host, port options `httpScheme`/`--http-scheme` -> `scheme`/`--scheme` `httpHost`/`--http-host` -> `host`/`--host` `httpPort`/`--http-port` -> `port`/`--port` --- integration/hmr-log-test.ts | 16 +++-- integration/hmr-test.ts | 16 +++-- packages/remix-dev/__tests__/cli-test.ts | 6 +- packages/remix-dev/cli/commands.ts | 63 +++++++++---------- packages/remix-dev/cli/run.ts | 28 +++------ packages/remix-dev/config.ts | 8 +-- .../remix-dev/devServer_unstable/index.ts | 22 +++---- 7 files changed, 66 insertions(+), 93 deletions(-) diff --git a/integration/hmr-log-test.ts b/integration/hmr-log-test.ts index 7fad0c380c7..54ab8b6c01a 100644 --- a/integration/hmr-log-test.ts +++ b/integration/hmr-log-test.ts @@ -9,7 +9,7 @@ import { createFixtureProject, css, js, json } from "./helpers/create-fixture"; test.setTimeout(120_000); -let fixture = (options: { appServerPort: number; httpPort: number }) => ({ +let fixture = (options: { appPort: number; devPort: number }) => ({ files: { "remix.config.js": js` module.exports = { @@ -17,7 +17,7 @@ let fixture = (options: { appServerPort: number; httpPort: number }) => ({ tailwind: true, future: { unstable_dev: { - httpPort: ${options.httpPort}, + port: ${options.devPort}, }, v2_routeConvention: true, v2_errorBoundary: true, @@ -75,7 +75,7 @@ let fixture = (options: { appServerPort: number; httpPort: number }) => ({ }) ); - let port = ${options.appServerPort}; + let port = ${options.appPort}; app.listen(port, () => { let build = require(BUILD_DIR); console.log('✅ app ready: http://localhost:' + port); @@ -245,11 +245,9 @@ test("HMR", async ({ page }) => { }); let portRange = makeRange(4080, 4099); - let appServerPort = await getPort({ port: portRange }); - let httpPort = await getPort({ port: portRange }); - let projectDir = await createFixtureProject( - fixture({ appServerPort, httpPort }) - ); + let appPort = await getPort({ port: portRange }); + let devPort = await getPort({ port: portRange }); + let projectDir = await createFixtureProject(fixture({ appPort, devPort })); // spin up dev server let dev = execa("npm", ["run", "dev"], { cwd: projectDir }); @@ -264,7 +262,7 @@ test("HMR", async ({ page }) => { { timeoutMs: 10_000 } ); - await page.goto(`http://localhost:${appServerPort}`, { + await page.goto(`http://localhost:${appPort}`, { waitUntil: "networkidle", }); diff --git a/integration/hmr-test.ts b/integration/hmr-test.ts index d2ad2e0b32a..45aa771ec01 100644 --- a/integration/hmr-test.ts +++ b/integration/hmr-test.ts @@ -9,7 +9,7 @@ import { createFixtureProject, css, js, json } from "./helpers/create-fixture"; test.setTimeout(120_000); -let fixture = (options: { appServerPort: number; httpPort: number }) => ({ +let fixture = (options: { appPort: number; devPort: number }) => ({ files: { "remix.config.js": js` module.exports = { @@ -17,7 +17,7 @@ let fixture = (options: { appServerPort: number; httpPort: number }) => ({ tailwind: true, future: { unstable_dev: { - httpPort: ${options.httpPort}, + port: ${options.devPort}, }, v2_routeConvention: true, v2_errorBoundary: true, @@ -74,7 +74,7 @@ let fixture = (options: { appServerPort: number; httpPort: number }) => ({ }) ); - let port = ${options.appServerPort}; + let port = ${options.appPort}; app.listen(port, () => { let build = require(BUILD_DIR); console.log('✅ app ready: http://localhost:' + port); @@ -243,11 +243,9 @@ test("HMR", async ({ page }) => { }); let portRange = makeRange(3080, 3099); - let appServerPort = await getPort({ port: portRange }); - let httpPort = await getPort({ port: portRange }); - let projectDir = await createFixtureProject( - fixture({ appServerPort, httpPort }) - ); + let appPort = await getPort({ port: portRange }); + let devPort = await getPort({ port: portRange }); + let projectDir = await createFixtureProject(fixture({ appPort, devPort })); // spin up dev server let dev = execa("npm", ["run", "dev"], { cwd: projectDir }); @@ -262,7 +260,7 @@ test("HMR", async ({ page }) => { { timeoutMs: 10_000 } ); - await page.goto(`http://localhost:${appServerPort}`, { + await page.goto(`http://localhost:${appPort}`, { waitUntil: "networkidle", }); diff --git a/packages/remix-dev/__tests__/cli-test.ts b/packages/remix-dev/__tests__/cli-test.ts index d0b6dc5302e..5e14cc52a1a 100644 --- a/packages/remix-dev/__tests__/cli-test.ts +++ b/packages/remix-dev/__tests__/cli-test.ts @@ -118,9 +118,9 @@ describe("remix CLI", () => { [unstable_dev] --command, -c Command used to run your app server - --http-scheme HTTP(S) scheme for the dev server. Default: http - --http-host HTTP(S) host for the dev server. Default: localhost - --http-port HTTP(S) port for the dev server. Default: any open port + --scheme Scheme for the dev server. Default: http + --host Host for the dev server. Default: localhost + --port Port for the dev server. Default: any open port --no-restart Do not restart the app server when rebuilds occur. \`init\` Options: --no-delete Skip deleting the \`remix.init\` script diff --git a/packages/remix-dev/cli/commands.ts b/packages/remix-dev/cli/commands.ts index 1623224aacb..4a22802da54 100644 --- a/packages/remix-dev/cli/commands.ts +++ b/packages/remix-dev/cli/commands.ts @@ -177,13 +177,9 @@ export async function build( onWarning: warnOnce, }; if (mode === "development" && config.future.unstable_dev) { - let dev = await resolveDevBuild(config); - options.devHttpOrigin = { - scheme: dev.httpScheme, - host: dev.httpHost, - port: dev.httpPort, - }; - options.devWebSocketPort = dev.httpPort; + let origin = await resolveDevOrigin(config); + options.devHttpOrigin = origin; + options.devWebSocketPort = origin.port; // TODO: ? } fse.emptyDirSync(config.assetsBuildDirectory); @@ -216,13 +212,12 @@ export async function dev( remixRoot: string, flags: { debug?: boolean; - port?: number; // TODO: remove for v2 // unstable_dev command?: string; - httpScheme?: string; - httpHost?: string; - httpPort?: number; + scheme?: string; + host?: string; + port?: number; restart?: boolean; } = {} ) { @@ -472,42 +467,42 @@ let parseMode = ( let findPort = async () => getPort({ port: makeRange(3001, 3100) }); -type DevBuildFlags = { - httpScheme: string; - httpHost: string; - httpPort: number; +type DevOrigin = { + scheme: string; + host: string; + port: number; }; -let resolveDevBuild = async ( +let resolveDevOrigin = async ( config: RemixConfig, - flags: Partial = {} -): Promise => { + flags: Partial = {} +): Promise => { let dev = config.future.unstable_dev; if (dev === false) throw Error("This should never happen"); // prettier-ignore - let httpScheme = - flags.httpScheme ?? - (dev === true ? undefined : dev.httpScheme) ?? + let scheme = + flags.scheme ?? + (dev === true ? undefined : dev.scheme) ?? "http"; // prettier-ignore - let httpHost = - flags.httpHost ?? - (dev === true ? undefined : dev.httpHost) ?? + let host = + flags.host ?? + (dev === true ? undefined : dev.host) ?? "localhost"; // prettier-ignore - let httpPort = - flags.httpPort ?? - (dev === true ? undefined : dev.httpPort) ?? + let port = + flags.port ?? + (dev === true ? undefined : dev.port) ?? (await findPort()); return { - httpScheme, - httpHost, - httpPort, + scheme, + host, + port, }; }; -type DevServeFlags = DevBuildFlags & { +type DevServeFlags = DevOrigin & { command: string; restart: boolean; }; @@ -518,7 +513,7 @@ let resolveDevServe = async ( let dev = config.future.unstable_dev; if (dev === false) throw Error("Cannot resolve dev options"); - let { httpScheme, httpHost, httpPort } = await resolveDevBuild(config, flags); + let origin = await resolveDevOrigin(config, flags); // prettier-ignore let command = @@ -549,9 +544,7 @@ let resolveDevServe = async ( return { command, - httpScheme, - httpHost, - httpPort, + ...origin, restart, }; }; diff --git a/packages/remix-dev/cli/run.ts b/packages/remix-dev/cli/run.ts index 72958b13491..f1d8bcde78f 100644 --- a/packages/remix-dev/cli/run.ts +++ b/packages/remix-dev/cli/run.ts @@ -44,9 +44,9 @@ ${colors.logoBlue("R")} ${colors.logoGreen("E")} ${colors.logoYellow( [unstable_dev] --command, -c Command used to run your app server - --http-scheme HTTP(S) scheme for the dev server. Default: http - --http-host HTTP(S) host for the dev server. Default: localhost - --http-port HTTP(S) port for the dev server. Default: any open port + --scheme Scheme for the dev server. Default: http + --host Host for the dev server. Default: localhost + --port Port for the dev server. Default: any open port --no-restart Do not restart the app server when rebuilds occur. \`init\` Options: --no-delete Skip deleting the \`remix.init\` script @@ -169,8 +169,6 @@ export async function run(argv: string[] = process.argv.slice(2)) { "--interactive": Boolean, "--no-interactive": Boolean, "--json": Boolean, - "--port": Number, - "-p": "--port", "--remix-version": String, "--sourcemap": Boolean, "--template": String, @@ -183,9 +181,10 @@ export async function run(argv: string[] = process.argv.slice(2)) { // dev server "--command": String, "-c": "--command", - "--http-scheme": String, - "--http-host": String, - "--http-port": Number, + "--scheme": String, + "--host": String, + "--port": Number, + "-p": "--port", "--no-restart": Boolean, }, { @@ -211,19 +210,6 @@ export async function run(argv: string[] = process.argv.slice(2)) { return; } - if (flags["http-scheme"]) { - flags.httpScheme = flags["http-scheme"]; - delete flags["http-scheme"]; - } - if (flags["http-host"]) { - flags.httpHost = flags["http-host"]; - delete flags["http-host"]; - } - if (flags["http-port"]) { - flags.httpPort = flags["http-port"]; - delete flags["http-port"]; - } - if (args["--no-delete"]) { flags.delete = false; } diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index 4e22c9d701d..e431e14d919 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -37,12 +37,10 @@ export type ServerModuleFormat = "esm" | "cjs"; export type ServerPlatform = "node" | "neutral"; type Dev = { - port?: number; // TODO: remove in v2 - command?: string; - httpScheme?: string; - httpHost?: string; - httpPort?: number; + scheme?: string; + host?: string; + port?: number; restart?: boolean; }; diff --git a/packages/remix-dev/devServer_unstable/index.ts b/packages/remix-dev/devServer_unstable/index.ts index d8b114f01e4..79a43d33bbc 100644 --- a/packages/remix-dev/devServer_unstable/index.ts +++ b/packages/remix-dev/devServer_unstable/index.ts @@ -42,9 +42,9 @@ export let serve = async ( initialConfig: RemixConfig, options: { command: string; - httpScheme: string; - httpHost: string; - httpPort: number; + scheme: string; + host: string; + port: number; restart: boolean; } ) => { @@ -76,10 +76,10 @@ export let serve = async ( let server = http.createServer(app); let websocket = Socket.serve(server); - let httpOrigin: Origin = { - scheme: options.httpScheme, - host: options.httpHost, - port: options.httpPort, + let origin: Origin = { + scheme: options.scheme, + host: options.host, + port: options.port, }; let bin = await detectBin(); @@ -91,7 +91,7 @@ export let serve = async ( NODE_ENV: "development", PATH: bin + (process.platform === "win32" ? ";" : ":") + process.env.PATH, - REMIX_DEV_HTTP_ORIGIN: stringifyOrigin(httpOrigin), + REMIX_DEV_HTTP_ORIGIN: stringifyOrigin(origin), }, // https://github.com/sindresorhus/execa/issues/433 windowsHide: false, @@ -135,8 +135,8 @@ export let serve = async ( mode: "development", sourcemap: true, onWarning: warnOnce, - devHttpOrigin: httpOrigin, - devWebSocketPort: options.httpPort, + devHttpOrigin: origin, + devWebSocketPort: origin.port, }, }, { @@ -215,7 +215,7 @@ export let serve = async ( } ); - server.listen(httpOrigin.port, () => { + server.listen(origin.port, () => { console.log("Remix dev server ready"); }); From d11a354727e073568fed09c9eb681c7094d473b9 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 22:01:03 -0400 Subject: [PATCH 6/8] fix(dev): dev server port priority 1. prop 2. `unstable_dev` `--port` flag 3. `unstable_dev.port` config option 4. REMIX_DEV_SERVER_WS_PORT env var (TODO: remove in v2) 5. default: 8002 (TODO: remove in v2) --- packages/remix-dev/cli/commands.ts | 1 - packages/remix-dev/compiler/options.ts | 1 - packages/remix-dev/compiler/server/plugins/entry.ts | 4 ++-- packages/remix-dev/devServer_unstable/index.ts | 1 - packages/remix-react/__tests__/components-test.tsx | 6 +++--- packages/remix-react/browser.tsx | 2 +- packages/remix-react/components.tsx | 8 ++++---- packages/remix-react/entry.ts | 2 +- packages/remix-server-runtime/build.ts | 2 +- packages/remix-server-runtime/serverHandoff.ts | 2 +- 10 files changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/remix-dev/cli/commands.ts b/packages/remix-dev/cli/commands.ts index 4a22802da54..4f20012ebcd 100644 --- a/packages/remix-dev/cli/commands.ts +++ b/packages/remix-dev/cli/commands.ts @@ -179,7 +179,6 @@ export async function build( if (mode === "development" && config.future.unstable_dev) { let origin = await resolveDevOrigin(config); options.devHttpOrigin = origin; - options.devWebSocketPort = origin.port; // TODO: ? } fse.emptyDirSync(config.assetsBuildDirectory); diff --git a/packages/remix-dev/compiler/options.ts b/packages/remix-dev/compiler/options.ts index 165b89cbab0..9dc6538ee50 100644 --- a/packages/remix-dev/compiler/options.ts +++ b/packages/remix-dev/compiler/options.ts @@ -11,5 +11,4 @@ export type Options = { host: string; port: number; }; - devWebSocketPort?: number; }; diff --git a/packages/remix-dev/compiler/server/plugins/entry.ts b/packages/remix-dev/compiler/server/plugins/entry.ts index 3d64193e3b4..56ca8324180 100644 --- a/packages/remix-dev/compiler/server/plugins/entry.ts +++ b/packages/remix-dev/compiler/server/plugins/entry.ts @@ -51,9 +51,9 @@ ${Object.keys(config.routes) export const publicPath = ${JSON.stringify(config.publicPath)}; export const entry = { module: entryServer }; ${ - options.devWebSocketPort + options.devHttpOrigin ? `export const dev = ${JSON.stringify({ - websocketPort: options.devWebSocketPort, + port: options.devHttpOrigin.port, })}` : "" } diff --git a/packages/remix-dev/devServer_unstable/index.ts b/packages/remix-dev/devServer_unstable/index.ts index 79a43d33bbc..c46db0cb503 100644 --- a/packages/remix-dev/devServer_unstable/index.ts +++ b/packages/remix-dev/devServer_unstable/index.ts @@ -136,7 +136,6 @@ export let serve = async ( sourcemap: true, onWarning: warnOnce, devHttpOrigin: origin, - devWebSocketPort: origin.port, }, }, { diff --git a/packages/remix-react/__tests__/components-test.tsx b/packages/remix-react/__tests__/components-test.tsx index b088805a445..6cb621925b1 100644 --- a/packages/remix-react/__tests__/components-test.tsx +++ b/packages/remix-react/__tests__/components-test.tsx @@ -47,14 +47,14 @@ describe("", () => { LiveReload = require("../components").LiveReload; let { container } = render(); expect(container.querySelector("script")).toHaveTextContent( - "let port = (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.websocketPort) || 8002;" + "let port = undefined || (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.port) || 8002;" ); }); it("can set the port explicitly", () => { let { container } = render(); expect(container.querySelector("script")).toHaveTextContent( - "let port = (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.websocketPort) || 4321;" + "let port = 4321 || (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.port) || 8002;" ); }); @@ -62,7 +62,7 @@ describe("", () => { process.env.REMIX_DEV_SERVER_WS_PORT = "1234"; let { container } = render(); expect(container.querySelector("script")).toHaveTextContent( - "let port = (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.websocketPort) || 1234;" + "let port = undefined || (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.port) || 1234;" ); }); diff --git a/packages/remix-react/browser.tsx b/packages/remix-react/browser.tsx index c81a6ed80fc..821731a3dad 100644 --- a/packages/remix-react/browser.tsx +++ b/packages/remix-react/browser.tsx @@ -24,7 +24,7 @@ declare global { // The number of active deferred keys rendered on the server a?: number; dev?: { - websocketPort?: number; + port?: number; hmrRuntime?: string; }; }; diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx index cd5fbf8e8a9..661447f5c53 100644 --- a/packages/remix-react/components.tsx +++ b/packages/remix-react/components.tsx @@ -1714,7 +1714,7 @@ export const LiveReload = ? () => null : function LiveReload({ // TODO: remove REMIX_DEV_SERVER_WS_PORT in v2 - port = Number(process.env.REMIX_DEV_SERVER_WS_PORT || 8002), + port, timeoutMs = 1000, nonce = undefined, }: { @@ -1732,9 +1732,9 @@ export const LiveReload = function remixLiveReloadConnect(config) { let protocol = location.protocol === "https:" ? "wss:" : "ws:"; let host = location.hostname; - let port = (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.websocketPort) || ${String( - port - )}; + let port = ${port} || (window.__remixContext && window.__remixContext.dev && window.__remixContext.dev.port) || ${Number( + process.env.REMIX_DEV_SERVER_WS_PORT || 8002 + )}; let socketPath = protocol + "//" + host + ":" + port + "/socket"; let ws = new WebSocket(socketPath); ws.onmessage = async (message) => { diff --git a/packages/remix-react/entry.ts b/packages/remix-react/entry.ts index d2a2ab2f269..cfef8123a4d 100644 --- a/packages/remix-react/entry.ts +++ b/packages/remix-react/entry.ts @@ -10,7 +10,7 @@ export interface RemixContextObject { serverHandoffString?: string; future: FutureConfig; abortDelay?: number; - dev?: { websocketPort: number }; + dev?: { port: number }; } // Additional React-Router information needed at runtime, but not hydrated diff --git a/packages/remix-server-runtime/build.ts b/packages/remix-server-runtime/build.ts index 4e1b831b1f2..dfa5e281054 100644 --- a/packages/remix-server-runtime/build.ts +++ b/packages/remix-server-runtime/build.ts @@ -15,7 +15,7 @@ export interface ServerBuild { publicPath: string; assetsBuildDirectory: string; future: FutureConfig; - dev?: { websocketPort: number }; + dev?: { port: number }; } export interface HandleDocumentRequestFunction { diff --git a/packages/remix-server-runtime/serverHandoff.ts b/packages/remix-server-runtime/serverHandoff.ts index edc4d4b3055..0ea04f24493 100644 --- a/packages/remix-server-runtime/serverHandoff.ts +++ b/packages/remix-server-runtime/serverHandoff.ts @@ -20,7 +20,7 @@ export function createServerHandoffString(serverHandoff: { // we'd end up including duplicate info state: ValidateShape; future: FutureConfig; - dev?: { websocketPort: number }; + dev?: { port: number }; }): string { // Uses faster alternative of jsesc to escape data returned from the loaders. // This string is inserted directly into the HTML in the `` element. From 720b9b0c931ba5442bb83272bcf9bd69b8b5989c Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 22:21:03 -0400 Subject: [PATCH 7/8] refactor(dev): rename devHttpOrigin -> devOrigin --- packages/remix-dev/cli/commands.ts | 2 +- packages/remix-dev/compiler/options.ts | 2 +- packages/remix-dev/compiler/server/compiler.ts | 2 +- packages/remix-dev/compiler/server/plugins/entry.ts | 4 ++-- packages/remix-dev/devServer_unstable/index.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/remix-dev/cli/commands.ts b/packages/remix-dev/cli/commands.ts index 4f20012ebcd..95bec84c03e 100644 --- a/packages/remix-dev/cli/commands.ts +++ b/packages/remix-dev/cli/commands.ts @@ -178,7 +178,7 @@ export async function build( }; if (mode === "development" && config.future.unstable_dev) { let origin = await resolveDevOrigin(config); - options.devHttpOrigin = origin; + options.devOrigin = origin; } fse.emptyDirSync(config.assetsBuildDirectory); diff --git a/packages/remix-dev/compiler/options.ts b/packages/remix-dev/compiler/options.ts index 9dc6538ee50..d128116d7de 100644 --- a/packages/remix-dev/compiler/options.ts +++ b/packages/remix-dev/compiler/options.ts @@ -6,7 +6,7 @@ export type Options = { onWarning?: (message: string, key: string) => void; // TODO: required in v2 - devHttpOrigin?: { + devOrigin?: { scheme: string; host: string; port: number; diff --git a/packages/remix-dev/compiler/server/compiler.ts b/packages/remix-dev/compiler/server/compiler.ts index 3dd99e80ffe..47af4230248 100644 --- a/packages/remix-dev/compiler/server/compiler.ts +++ b/packages/remix-dev/compiler/server/compiler.ts @@ -103,7 +103,7 @@ const createEsbuildConfig = ( ctx.config.devServerPort ), "process.env.REMIX_DEV_HTTP_ORIGIN": JSON.stringify( - ctx.options.devHttpOrigin ?? "" // TODO: remove nullish check in v2 + ctx.options.devOrigin ?? "" // TODO: remove nullish check in v2 ), }, jsx: "automatic", diff --git a/packages/remix-dev/compiler/server/plugins/entry.ts b/packages/remix-dev/compiler/server/plugins/entry.ts index 56ca8324180..4966dd3ad93 100644 --- a/packages/remix-dev/compiler/server/plugins/entry.ts +++ b/packages/remix-dev/compiler/server/plugins/entry.ts @@ -51,9 +51,9 @@ ${Object.keys(config.routes) export const publicPath = ${JSON.stringify(config.publicPath)}; export const entry = { module: entryServer }; ${ - options.devHttpOrigin + options.devOrigin ? `export const dev = ${JSON.stringify({ - port: options.devHttpOrigin.port, + port: options.devOrigin.port, })}` : "" } diff --git a/packages/remix-dev/devServer_unstable/index.ts b/packages/remix-dev/devServer_unstable/index.ts index c46db0cb503..01c29d8b71e 100644 --- a/packages/remix-dev/devServer_unstable/index.ts +++ b/packages/remix-dev/devServer_unstable/index.ts @@ -135,7 +135,7 @@ export let serve = async ( mode: "development", sourcemap: true, onWarning: warnOnce, - devHttpOrigin: origin, + devOrigin: origin, }, }, { From 94b1dae44bfb61d1b83e18a5f2cd47084cb6a1cb Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Wed, 24 May 2023 22:21:09 -0400 Subject: [PATCH 8/8] chore(dev): add changeset for new dev server options --- .changeset/wicked-pandas-give.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .changeset/wicked-pandas-give.md diff --git a/.changeset/wicked-pandas-give.md b/.changeset/wicked-pandas-give.md new file mode 100644 index 00000000000..0a998218e57 --- /dev/null +++ b/.changeset/wicked-pandas-give.md @@ -0,0 +1,23 @@ +--- +"@remix-run/dev": minor +"@remix-run/react": minor +"@remix-run/server-runtime": minor +--- + +Reuse dev server port for WebSocket (Live Reload,HMR,HDR) + +As a result the `webSocketPort`/`--websocket-port` option has been obsoleted. +Additionally, scheme/host/port options for the dev server have been renamed. + +Available options are: + +| Option | flag | config | default | +| -------------- | ------------------ | ---------------- | --------------------------------- | +| Command | `-c` / `--command` | `command` | `remix-serve ` | +| Scheme | `--scheme` | `scheme` | `http` | +| Host | `--host` | `host` | `localhost` | +| Port | `--port` | `port` | Dynamically chosen open port | +| No restart | `--no-restart` | `restart: false` | `restart: true` | + +Note that scheme/host/port options are for the _dev server_, not your app server. +You probably don't need to use scheme/host/port option if you aren't configuring networking (e.g. for Docker or SSL).