Skip to content

Commit

Permalink
chore: make entry.{client,server}.tsx and root.tsx optional
Browse files Browse the repository at this point in the history
Signed-off-by: Logan McAnsh <logan@mcan.sh>
  • Loading branch information
mcansh committed Nov 15, 2022
1 parent 95b7fd1 commit f531ea2
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
integration/helpers/deno-template
packages/remix-deno
templates/deno

packages/remix-dev/config/defaults
4 changes: 4 additions & 0 deletions packages/remix-dev/__tests__/readConfig-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ describe("readConfig", () => {
serverBuildPath: expect.any(String),
assetsBuildDirectory: expect.any(String),
relativeAssetsBuildDirectory: expect.any(String),
entryClientFilePath: expect.any(String),
entryServerFilePath: expect.any(String),
tsconfigPath: expect.any(String),
future: {
v2_meta: expect.any(Boolean),
Expand All @@ -34,7 +36,9 @@ describe("readConfig", () => {
"devServerBroadcastDelay": 0,
"devServerPort": Any<Number>,
"entryClientFile": "entry.client.tsx",
"entryClientFilePath": Any<String>,
"entryServerFile": "entry.server.tsx",
"entryServerFilePath": Any<String>,
"future": Object {
"v2_meta": Any<Boolean>,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/remix-dev/compiler/compileBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const createEsbuildConfig = (
options: CompileOptions
): esbuild.BuildOptions | esbuild.BuildIncremental => {
let entryPoints: esbuild.BuildOptions["entryPoints"] = {
"entry.client": path.resolve(config.appDirectory, config.entryClientFile),
"entry.client": config.entryClientFile,
};
for (let id of Object.keys(config.routes)) {
// All route entry points are virtual modules that will be loaded by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function serverEntryModulePlugin(config: RemixConfig): Plugin {
resolveDir: config.appDirectory,
loader: "js",
contents: `
import * as entryServer from ${JSON.stringify(`./${config.entryServerFile}`)};
import * as entryServer from ${JSON.stringify(config.entryServerFile)};
${Object.keys(config.routes)
.map((key, index) => {
let route = config.routes[key];
Expand Down
49 changes: 36 additions & 13 deletions packages/remix-dev/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,21 @@ export interface RemixConfig {
*/
entryClientFile: string;

/**
* The absolute path to the entry.client file.
*/
entryClientFilePath: string;

/**
* The path to the entry.server file, relative to `config.appDirectory`.
*/
entryServerFile: string;

/**
* The absolute path to the entry.server file.
*/
entryServerFilePath: string;

/**
* An object of all available routes, keyed by route id.
*/
Expand Down Expand Up @@ -353,15 +363,28 @@ export async function readConfig(
appConfig.cacheDirectory || ".cache"
);

let entryClientFile = findEntry(appDirectory, "entry.client");
if (!entryClientFile) {
throw new Error(`Missing "entry.client" file in ${appDirectory}`);
}
let defaultsDirectory = path.resolve(__dirname, "config", "defaults");
let defaultEntryClient = path.resolve(defaultsDirectory, "entry.client.tsx");
let defaultEntryServer = path.resolve(defaultsDirectory, "entry.server.tsx");

let entryServerFile = findEntry(appDirectory, "entry.server");
if (!entryServerFile) {
throw new Error(`Missing "entry.server" file in ${appDirectory}`);
}
let userEntryClientFile = findEntry(appDirectory, "entry.client");
let userEntryServerFile = findEntry(appDirectory, "entry.server");

let entryClientFile = userEntryClientFile
? userEntryClientFile
: "entry.client.tsx";

let entryServerFile = userEntryServerFile
? userEntryServerFile
: "entry.server.tsx";

let entryClientFilePath = userEntryClientFile
? path.resolve(appDirectory, userEntryClientFile)
: defaultEntryClient;

let entryServerFilePath = userEntryServerFile
? path.resolve(appDirectory, userEntryServerFile)
: defaultEntryServer;

let serverBuildPath = "build/index.js";
switch (serverBuildTarget) {
Expand Down Expand Up @@ -406,7 +429,7 @@ export async function readConfig(
Number(process.env.REMIX_DEV_SERVER_WS_PORT) ||
(await getPort({ port: Number(appConfig.devServerPort) || 8002 }));
// set env variable so un-bundled servers can use it
process.env.REMIX_DEV_SERVER_WS_PORT = `${devServerPort}`;
process.env.REMIX_DEV_SERVER_WS_PORT = String(devServerPort);
let devServerBroadcastDelay = appConfig.devServerBroadcastDelay || 0;

let defaultPublicPath = "/build/";
Expand All @@ -419,12 +442,10 @@ export async function readConfig(
let publicPath = addTrailingSlash(appConfig.publicPath || defaultPublicPath);

let rootRouteFile = findEntry(appDirectory, "root");
if (!rootRouteFile) {
throw new Error(`Missing "root" route file in ${appDirectory}`);
}
let defaultRootRouteFile = path.resolve(defaultsDirectory, "root.tsx");

let routes: RouteManifest = {
root: { path: "", id: "root", file: rootRouteFile },
root: { path: "", id: "root", file: rootRouteFile || defaultRootRouteFile },
};
if (fse.existsSync(path.resolve(appDirectory, "routes"))) {
let conventionalRoutes = defineConventionalRoutes(
Expand Down Expand Up @@ -488,7 +509,9 @@ export async function readConfig(
appDirectory,
cacheDirectory,
entryClientFile,
entryClientFilePath,
entryServerFile,
entryServerFilePath,
devServerPort,
devServerBroadcastDelay,
assetsBuildDirectory: absoluteAssetsBuildDirectory,
Expand Down
23 changes: 23 additions & 0 deletions packages/remix-dev/config/defaults/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as React from "react";
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

function hydrate() {
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
}

if (window.requestIdleCallback) {
window.requestIdleCallback(hydrate);
} else {
// Safari doesn't support requestIdleCallback
// https://caniuse.com/requestidlecallback
window.setTimeout(hydrate, 1);
}
112 changes: 112 additions & 0 deletions packages/remix-dev/config/defaults/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import * as React from "react";
import { PassThrough } from "stream";
import type { EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { renderToPipeableStream } from "react-dom/server";

const ABORT_DELAY = 5000;

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
);
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let didError = false;

const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} />,
{
onAllReady() {
const body = new PassThrough();

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

resolve(
new Response(body, {
headers: responseHeaders,
status: didError ? 500 : responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
didError = true;

console.error(error);
},
}
);

setTimeout(abort, ABORT_DELAY);
});
}

function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let didError = false;

const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} />,
{
onShellReady() {
const body = new PassThrough();

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

resolve(
new Response(body, {
headers: responseHeaders,
status: didError ? 500 : responseStatusCode,
})
);

pipe(body);
},
onShellError(err: unknown) {
reject(err);
},
onError(error: unknown) {
didError = true;

console.error(error);
},
}
);

setTimeout(abort, ABORT_DELAY);
});
}
33 changes: 33 additions & 0 deletions packages/remix-dev/config/defaults/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from "react";
import type { MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";

export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});

export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
4 changes: 2 additions & 2 deletions packages/remix-dev/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ module.exports = function rollup() {
{ src: `${sourceDir}/package.json`, dest: [outputDir, outputDist] },
{ src: `${sourceDir}/README.md`, dest: outputDir },
{
src: `${sourceDir}/compiler/shims`,
dest: [`${outputDir}/compiler`, `${outputDist}/compiler`],
src: `${sourceDir}/config/defaults`,
dest: [`${outputDir}/config`, `${outputDist}/config`],
},
],
}),
Expand Down

0 comments on commit f531ea2

Please sign in to comment.