Skip to content

Commit

Permalink
fix: update shared build utils to preserve dynamic imports for CLIs
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-ebey authored and MichaelDeBoey committed Aug 15, 2023
1 parent da2d9fb commit 58ff078
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 44 deletions.
2 changes: 1 addition & 1 deletion integration/bug-report-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ test("[description of what you expect it to do]", async ({ page }) => {
// If you need to test interactivity use the `app`
await app.goto("/");
await app.clickLink("/burgers");
expect(await app.getHtml()).toMatch("cheeseburger");
await page.waitForSelector("text=cheeseburger");

// If you're not sure what's going on, you can "poke" the app, it'll
// automatically open up in your browser for 20 seconds, so be quick!
Expand Down
60 changes: 59 additions & 1 deletion integration/helpers/create-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import getPort from "get-port";
import dedent from "dedent";
import stripIndent from "strip-indent";
import serializeJavaScript from "serialize-javascript";
import { sync as spawnSync } from "cross-spawn";
import { sync as spawnSync, spawn } from "cross-spawn";
import type { JsonObject } from "type-fest";
import type { AppConfig } from "@remix-run/dev";

Expand All @@ -27,6 +27,7 @@ export interface FixtureInit {
files?: { [filename: string]: string };
template?: "cf-template" | "deno-template" | "node-template";
config?: Partial<AppConfig>;
useRemixServe?: boolean;
}

export type Fixture = Awaited<ReturnType<typeof createFixture>>;
Expand Down Expand Up @@ -97,6 +98,7 @@ export async function createFixture(init: FixtureInit, mode?: ServerMode) {
requestData,
postDocument,
getBrowserAsset,
useRemixServe: init.useRemixServe,
};
}

Expand All @@ -105,6 +107,62 @@ export async function createAppFixture(fixture: Fixture, mode?: ServerMode) {
port: number;
stop: VoidFunction;
}> => {
if (fixture.useRemixServe) {
return new Promise(async (accept, reject) => {
let port = await getPort();

let nodebin = process.argv[0];
let serveProcess = spawn(
nodebin,
["node_modules/@remix-run/serve/dist/cli.js", "build/index.js"],
{
env: {
NODE_ENV: mode || "production",
PORT: port.toFixed(0),
},
cwd: fixture.projectDir,
stdio: "pipe",
}
);
// Wait for `started at http://localhost:${port}` to be printed
// and extract the port from it.
let started = false;
let stdout = "";
let rejectTimeout = setTimeout(() => {
reject(new Error("Timed out waiting for remix-serve to start"));
}, 20000);
serveProcess.stdout.on("data", (chunk) => {
if (started) return;
let newChunk = chunk.toString();
stdout += newChunk;
let match: RegExpMatchArray | null = stdout.match(
/started at http:\/\/localhost:(\d+)\s/
);
if (match) {
clearTimeout(rejectTimeout);
started = true;
let parsedPort = parseInt(match[1], 10);

if (port !== parsedPort) {
reject(
new Error(
`Expected remix-serve to start on port ${port}, but it started on port ${parsedPort}`
)
);
return;
}

accept({
stop: () => {
serveProcess.kill();
},
port,
});
}
});
});
}

return new Promise(async (accept) => {
let port = await getPort();
let app = express();
Expand Down
70 changes: 70 additions & 0 deletions integration/remix-serve-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { test, expect } from "@playwright/test";

import { PlaywrightFixture } from "./helpers/playwright-fixture.js";
import type { Fixture, AppFixture } from "./helpers/create-fixture.js";
import {
createAppFixture,
createFixture,
js,
} from "./helpers/create-fixture.js";

let fixture: Fixture;
let appFixture: AppFixture;

test.beforeEach(async ({ context }) => {
await context.route(/_data/, async (route) => {
await new Promise((resolve) => setTimeout(resolve, 50));
route.continue();
});
});

test.beforeAll(async () => {
fixture = await createFixture({
useRemixServe: true,
files: {
"app/routes/_index.tsx": js`
import { json } from "@remix-run/node";
import { useLoaderData, Link } from "@remix-run/react";
export function loader() {
return json("pizza");
}
export default function Index() {
let data = useLoaderData();
return (
<div>
{data}
<Link to="/burgers">Other Route</Link>
</div>
)
}
`,

"app/routes/burgers.tsx": js`
export default function Index() {
return <div>cheeseburger</div>;
}
`,
},
});

// This creates an interactive app using playwright.
appFixture = await createAppFixture(fixture);
});

test.afterAll(() => {
appFixture.close();
});

test("should start and perform client side navigation", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
// You can test any request your app might get using `fixture`.
let response = await fixture.requestDocument("/");
expect(await response.text()).toMatch("pizza");

// If you need to test interactivity use the `app`
await app.goto("/");
await app.clickLink("/burgers");
await page.waitForSelector("text=cheeseburger");
});
89 changes: 47 additions & 42 deletions packages/remix-serve/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,54 @@ import { createApp } from "./index";
sourceMapSupport.install();
installGlobals();

let port = process.env.PORT ? Number(process.env.PORT) : 3000;
if (Number.isNaN(port)) port = 3000;
run();

let buildPathArg = process.argv[2];
async function run() {
let port = process.env.PORT ? Number(process.env.PORT) : 3000;
if (Number.isNaN(port)) port = 3000;

if (!buildPathArg) {
console.error(`
Usage: remix-serve <build-dir>`);
process.exit(1);
}
let buildPathArg = process.argv[2];

let buildPath = path.resolve(process.cwd(), buildPathArg);
let build = require(buildPath);

let onListen = () => {
let address =
process.env.HOST ||
Object.values(os.networkInterfaces())
.flat()
.find((ip) => String(ip?.family).includes("4") && !ip?.internal)?.address;

if (!address) {
console.log(`Remix App Server started at http://localhost:${port}`);
} else {
console.log(
`Remix App Server started at http://localhost:${port} (http://${address}:${port})`
);
}
if (process.env.NODE_ENV === "development") {
void broadcastDevReady(build);
if (!buildPathArg) {
console.error(`
Usage: remix-serve <build-dir>`);
process.exit(1);
}
};

let app = createApp(
buildPath,
process.env.NODE_ENV,
build.publicPath,
build.assetsBuildDirectory
);
let server = process.env.HOST
? app.listen(port, process.env.HOST, onListen)
: app.listen(port, onListen);

["SIGTERM", "SIGINT"].forEach((signal) => {
process.once(signal, () => server?.close(console.error));
});

let buildPath = path.resolve(process.cwd(), buildPathArg);
let build = await import(buildPath);

let onListen = () => {
let address =
process.env.HOST ||
Object.values(os.networkInterfaces())
.flat()
.find((ip) => String(ip?.family).includes("4") && !ip?.internal)
?.address;

if (!address) {
console.log(`Remix App Server started at http://localhost:${port}`);
} else {
console.log(
`Remix App Server started at http://localhost:${port} (http://${address}:${port})`
);
}
if (process.env.NODE_ENV === "development") {
void broadcastDevReady(build);
}
};

let app = createApp(
buildPath,
process.env.NODE_ENV,
build.publicPath,
build.assetsBuildDirectory
);
let server = process.env.HOST
? app.listen(port, process.env.HOST, onListen)
: app.listen(port, onListen);

["SIGTERM", "SIGINT"].forEach((signal) => {
process.once(signal, () => server?.close(console.error));
});
}
9 changes: 9 additions & 0 deletions rollup.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ function getCliConfig({ packageName, version }) {
extensions: [".ts"],
}),
nodeResolve({ extensions: [".ts"] }),
{
name: "dynamic-import-polyfill",
renderDynamicImport() {
return {
left: "import(",
right: ")",
};
},
},
copyPublishFiles(packageName),
copyToPlaygrounds(),
],
Expand Down

0 comments on commit 58ff078

Please sign in to comment.