Last active
October 6, 2023 21:14
-
-
Save jacob-ebey/a137da89aaeef829a526fd74fea5c9da to your computer and use it in GitHub Desktop.
remix cjs server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require("node:fs"); | |
const { createRequestHandler } = require("@remix-run/express"); | |
const { broadcastDevReady, installGlobals } = require("@remix-run/node"); | |
const compression = require("compression"); | |
const express = require("express"); | |
const morgan = require("morgan"); | |
const sourceMapSupport = require("source-map-support"); | |
sourceMapSupport.install(); | |
installGlobals(); | |
const BUILD_PATH = require.resolve("./build/index.js"); | |
start(); | |
async function start() { | |
/** @typedef {import('@remix-run/node').ServerBuild} ServerBuild */ | |
const initialBuild = await reimportServer(); | |
const remixHandler = | |
process.env.NODE_ENV === "development" | |
? await createDevRequestHandler(initialBuild) | |
: createRequestHandler({ | |
build: initialBuild, | |
mode: initialBuild.mode, | |
}); | |
const app = express(); | |
app.use(compression()); | |
// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header | |
app.disable("x-powered-by"); | |
// Remix fingerprints its assets so we can cache forever. | |
app.use( | |
"/build", | |
express.static("public/build", { immutable: true, maxAge: "1y" }) | |
); | |
// Everything else (like favicon.ico) is cached for an hour. You may want to be | |
// more aggressive with this caching. | |
app.use(express.static("public", { maxAge: "1h" })); | |
app.use(morgan("tiny")); | |
app.all("*", remixHandler); | |
const port = process.env.PORT || 3000; | |
app.listen(port, async () => { | |
console.log(`Express server listening on port ${port}`); | |
if (process.env.NODE_ENV === "development") { | |
broadcastDevReady(initialBuild); | |
} | |
}); | |
} | |
var lastUpdated = null; | |
/** | |
* @returns {Promise<ServerBuild>} | |
*/ | |
async function reimportServer() { | |
const stat = fs.statSync(BUILD_PATH); | |
if (lastUpdated !== stat.mtimeMs) { | |
// bust the require cache | |
delete require.cache[BUILD_PATH]; | |
} | |
return require(BUILD_PATH); | |
} | |
/** | |
* @param {ServerBuild} initialBuild | |
* @returns {Promise<import('@remix-run/express').RequestHandler>} | |
*/ | |
async function createDevRequestHandler(initialBuild) { | |
let build = initialBuild; | |
async function handleServerUpdate() { | |
// 1. re-import the server build | |
build = await reimportServer(); | |
// 2. tell Remix that this app server is now up-to-date and ready | |
broadcastDevReady(build); | |
} | |
const chokidar = await import("chokidar"); | |
chokidar | |
.watch(BUILD_PATH, { ignoreInitial: true }) | |
.on("add", handleServerUpdate) | |
.on("change", handleServerUpdate); | |
// wrap request handler to make sure its recreated with the latest build for every request | |
return async (req, res, next) => { | |
try { | |
return createRequestHandler({ | |
build, | |
mode: "development", | |
})(req, res, next); | |
} catch (error) { | |
next(error); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment