Skip to content

Commit

Permalink
feat: optional entry.{client,server} for react 17
Browse files Browse the repository at this point in the history
Signed-off-by: Logan McAnsh <[email protected]>
  • Loading branch information
mcansh committed Mar 6, 2023
1 parent 712732f commit 22447e8
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 38 deletions.
76 changes: 74 additions & 2 deletions integration/server-entry-test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { test, expect } from "@playwright/test";

import { createFixture, js } from "./helpers/create-fixture";
import { createFixture, js, json } from "./helpers/create-fixture";
import type { Fixture } from "./helpers/create-fixture";
import { selectHtml } from "./helpers/playwright-fixture";

test.describe("Server Entry", () => {
test.describe("Custom Server Entry", () => {
let fixture: Fixture;

let DATA_HEADER_NAME = "X-Macaroni-Salad";
Expand Down Expand Up @@ -40,3 +41,74 @@ test.describe("Server Entry", () => {
expect(response.headers.get(DATA_HEADER_NAME)).toBe(DATA_HEADER_VALUE);
});
});

test.describe("Default Server Entry", () => {
let fixture: Fixture;

test.beforeAll(async () => {
fixture = await createFixture({
files: {
"app/routes/index.jsx": js`
export default function () {
return <p>Hello World</p>
}
`,
},
});
});

test("renders", async () => {
let response = await fixture.requestDocument("/");
expect(selectHtml(await response.text(), "p")).toBe("<p>Hello World</p>");
});
});

test.describe("Default Server Entry (React 17)", () => {
let fixture: Fixture;

test.beforeAll(async () => {
fixture = await createFixture({
files: {
"app/routes/index.jsx": js`
export default function () {
return <p>Hello World</p>
}
`,
"package.json": json({
name: "remix-template-remix",
private: true,
sideEffects: false,
scripts: {
build:
"node ../../../build/node_modules/@remix-run/dev/dist/cli.js build",
dev: "node ../../../build/node_modules/@remix-run/dev/dist/cli.js dev",
start:
"node ../../../build/node_modules/@remix-run/serve/dist/cli.js build",
},
dependencies: {
"@remix-run/node": "0.0.0-local-version",
"@remix-run/react": "0.0.0-local-version",
"@remix-run/serve": "0.0.0-local-version",
isbot: "0.0.0-local-version",
react: "17.0.2",
"react-dom": "17.0.2",
},
devDependencies: {
"@remix-run/dev": "0.0.0-local-version",
"@types/react": "0.0.0-local-version",
"@types/react-dom": "0.0.0-local-version",
typescript: "0.0.0-local-version",
},
engines: {
node: ">=14",
},
}),
},
});
});

test("renders", async () => {
let response = await fixture.requestDocument("/");
expect(selectHtml(await response.text(), "p")).toBe("<p>Hello World</p>");
});
});
89 changes: 53 additions & 36 deletions packages/remix-dev/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { pathToFileURL } from "node:url";
import fse from "fs-extra";
import getPort from "get-port";
import NPMCliPackageJson from "@npmcli/package-json";
import { gte } from "semver";

import type { RouteManifest, DefineRoutesFunction } from "./config/routes";
import { defineRoutes } from "./config/routes";
Expand Down Expand Up @@ -460,6 +461,49 @@ export async function readConfig(
let pkgJson = await NPMCliPackageJson.load(remixRoot);
let deps = pkgJson.content.dependencies ?? {};

let reactVersion = gte(deps.react, "18.0.0") ? "18" : "17";
if (!reactVersion) {
let react = ["react", "react-dom"];
let list = conjunctionListFormat(react);
throw new Error(
`Could not determine React version. Please install the following packages: ${list}`
);
}

let serverRuntime = deps["@remix-run/deno"]
? "deno"
: deps["@remix-run/cloudflare"]
? "cloudflare"
: deps["@remix-run/node"]
? "node"
: undefined;

if (!serverRuntime) {
let serverRuntimes = [
"@remix-run/deno",
"@remix-run/cloudflare",
"@remix-run/node",
];
let formattedList = disjunctionListFormat.format(serverRuntimes);
throw new Error(
`Could not determine server runtime. Please install one of the following: ${formattedList}`
);
}

let clientRuntime = deps["@remix-run/react"] ? "react" : undefined;

if (!clientRuntime) {
throw new Error(
`Could not determine runtime. Please install the following: @remix-run/react`
);
}

if (userEntryClientFile) {
entryClientFile = userEntryClientFile;
} else {
entryClientFile = `entry.client.${clientRuntime}-${reactVersion}.tsx`;
}

if (userEntryServerFile) {
entryServerFile = userEntryServerFile;
} else {
Expand All @@ -485,41 +529,7 @@ export async function readConfig(
});
}

let serverRuntime = deps["@remix-run/deno"]
? "deno"
: deps["@remix-run/cloudflare"]
? "cloudflare"
: deps["@remix-run/node"]
? "node"
: undefined;

if (!serverRuntime) {
let serverRuntimes = [
"@remix-run/deno",
"@remix-run/cloudflare",
"@remix-run/node",
];
let formattedList = listFormat.format(serverRuntimes);
throw new Error(
`Could not determine server runtime. Please install one of the following: ${formattedList}`
);
}

entryServerFile = `entry.server.${serverRuntime}.tsx`;
}

if (userEntryClientFile) {
entryClientFile = userEntryClientFile;
} else {
let clientRuntime = deps["@remix-run/react"] ? "react" : undefined;

if (!clientRuntime) {
throw new Error(
`Could not determine runtime. Please install the following: @remix-run/react`
);
}

entryClientFile = `entry.client.${clientRuntime}.tsx`;
entryServerFile = `${serverRuntime}/entry.server.${clientRuntime}-${reactVersion}.tsx`;
}

let entryClientFilePath = userEntryClientFile
Expand Down Expand Up @@ -726,11 +736,18 @@ const resolveServerBuildPath = (

// @ts-expect-error available in node 12+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat#browser_compatibility
let listFormat = new Intl.ListFormat("en", {
let conjunctionListFormat = new Intl.ListFormat("en", {
style: "long",
type: "conjunction",
});

// @ts-expect-error available in node 12+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat#browser_compatibility
let disjunctionListFormat = new Intl.ListFormat("en", {
style: "long",
type: "disjunction",
});

export let serverBuildTargetWarning = `⚠️ DEPRECATED: The "serverBuildTarget" config option is deprecated. Use a combination of "publicPath", "serverBuildPath", "serverConditions", "serverDependenciesToBundle", "serverMainFields", "serverMinify", "serverModuleFormat" and/or "serverPlatform" instead.`;

export let flatRoutesWarning = `⚠️ DEPRECATED: The old nested folders route convention has been deprecated in favor of "flat routes". Please enable the new routing convention via the \`future.v2_routeConvention\` flag in your \`remix.config.js\` file. For more information, please see https://remix.run/docs/en/main/file-conventions/route-files-v2.`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { EntryContext } from "@remix-run/cloudflare";
import { renderToString } from "react-dom/server";
import { RemixServer } from "@remix-run/react";

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
let markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);

responseHeaders.set("Content-Type", "text/html");

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
21 changes: 21 additions & 0 deletions packages/remix-dev/config/defaults/deno/entry.server.react-17.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { EntryContext } from "@remix-run/deno";
import { renderToString } from "react-dom/server";
import { RemixServer } from "@remix-run/react";

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
let markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);

responseHeaders.set("Content-Type", "text/html");

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
4 changes: 4 additions & 0 deletions packages/remix-dev/config/defaults/entry.client.react-17.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { RemixBrowser } from "@remix-run/react";
import { hydrate } from "react-dom";

hydrate(<RemixBrowser />, document);
21 changes: 21 additions & 0 deletions packages/remix-dev/config/defaults/node/entry.server.react-17.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { EntryContext } from "@remix-run/node";
import { renderToString } from "react-dom/server";
import { RemixServer } from "@remix-run/react";

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
let markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);

responseHeaders.set("Content-Type", "text/html");

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}

0 comments on commit 22447e8

Please sign in to comment.