Skip to content

Commit

Permalink
feat(dev): reuse dev server port for websocket (#6476)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed May 25, 2023
1 parent d04a11e commit a1301ed
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 176 deletions.
23 changes: 23 additions & 0 deletions .changeset/wicked-pandas-give.md
Original file line number Diff line number Diff line change
@@ -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 <server build path>` |
| 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).
36 changes: 17 additions & 19 deletions integration/hmr-log-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ 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: { appPort: number; devPort: number }) => ({
files: {
"remix.config.js": js`
module.exports = {
serverModuleFormat: "cjs",
tailwind: true,
future: {
unstable_dev: {
httpPort: ${options.httpPort},
webSocketPort: ${options.webSocketPort},
port: ${options.devPort},
},
v2_routeConvention: true,
v2_errorBoundary: true,
Expand Down Expand Up @@ -80,7 +75,7 @@ let fixture = (options: {
})
);
let port = ${options.appServerPort};
let port = ${options.appPort};
app.listen(port, () => {
let build = require(BUILD_DIR);
console.log('✅ app ready: http://localhost:' + port);
Expand Down Expand Up @@ -250,12 +245,9 @@ 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 })
);
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 });
Expand All @@ -270,7 +262,7 @@ test("HMR", async ({ page }) => {
{ timeoutMs: 10_000 }
);

await page.goto(`http://localhost:${appServerPort}`, {
await page.goto(`http://localhost:${appPort}`, {
waitUntil: "networkidle",
});

Expand Down Expand Up @@ -470,7 +462,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) {
Expand All @@ -486,9 +478,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";
Expand Down
39 changes: 18 additions & 21 deletions integration/hmr-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ 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: { appPort: number; devPort: number }) => ({
files: {
"remix.config.js": js`
module.exports = {
serverModuleFormat: "cjs",
tailwind: true,
future: {
unstable_dev: {
httpPort: ${options.httpPort},
webSocketPort: ${options.webSocketPort},
port: ${options.devPort},
},
v2_routeConvention: true,
v2_errorBoundary: true,
Expand Down Expand Up @@ -69,18 +64,17 @@ 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,
})
);
let port = ${options.appServerPort};
let port = ${options.appPort};
app.listen(port, () => {
let build = require(BUILD_DIR);
console.log('✅ app ready: http://localhost:' + port);
Expand Down Expand Up @@ -249,12 +243,9 @@ 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 })
);
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 });
Expand All @@ -269,7 +260,7 @@ test("HMR", async ({ page }) => {
{ timeoutMs: 10_000 }
);

await page.goto(`http://localhost:${appServerPort}`, {
await page.goto(`http://localhost:${appPort}`, {
waitUntil: "networkidle",
});

Expand Down Expand Up @@ -469,7 +460,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) {
Expand All @@ -485,9 +476,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";
Expand Down
7 changes: 3 additions & 4 deletions packages/remix-dev/__tests__/cli-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,10 @@ 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.
--websocket-port WebSocket port for the dev server. Default: any open port
\`init\` Options:
--no-delete Skip deleting the \`remix.init\` script
\`routes\` Options:
Expand Down
78 changes: 30 additions & 48 deletions packages/remix-dev/cli/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,8 @@ 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.webSocketPort;
let origin = await resolveDevOrigin(config);
options.devOrigin = origin;
}

fse.emptyDirSync(config.assetsBuildDirectory);
Expand Down Expand Up @@ -216,20 +211,20 @@ 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;
websocketPort?: number;
} = {}
) {
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";
Expand Down Expand Up @@ -471,49 +466,42 @@ let parseMode = (

let findPort = async () => getPort({ port: makeRange(3001, 3100) });

type DevBuildFlags = {
httpScheme: string;
httpHost: string;
httpPort: number;
webSocketPort: number;
type DevOrigin = {
scheme: string;
host: string;
port: number;
};
let resolveDevBuild = async (
let resolveDevOrigin = async (
config: RemixConfig,
flags: Partial<DevBuildFlags> = {}
): Promise<DevBuildFlags> => {
flags: Partial<DevOrigin> = {}
): Promise<DevOrigin> => {
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) ??
(await findPort());
// prettier-ignore
let webSocketPort =
flags.webSocketPort ??
(dev === true ? undefined : dev.webSocketPort) ??
let port =
flags.port ??
(dev === true ? undefined : dev.port) ??
(await findPort());

return {
httpScheme,
httpHost,
httpPort,
webSocketPort,
scheme,
host,
port,
};
};

type DevServeFlags = DevBuildFlags & {
type DevServeFlags = DevOrigin & {
command: string;
restart: boolean;
};
Expand All @@ -524,10 +512,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 origin = await resolveDevOrigin(config, flags);

// prettier-ignore
let command =
Expand Down Expand Up @@ -558,10 +543,7 @@ let resolveDevServe = async (

return {
command,
httpScheme,
httpHost,
httpPort,
webSocketPort,
...origin,
restart,
};
};
Loading

0 comments on commit a1301ed

Please sign in to comment.