@netlify/remix-edge-adapter
Version:
Remix Adapter for Netlify Edge Functions
129 lines (122 loc) • 3.96 kB
JavaScript
import {
__commonJS,
__toESM
} from "./chunk-UJCSKKID.mjs";
// src/common/globals.ts
var require_globals = __commonJS({
"src/common/globals.ts"() {
"use strict";
globalThis.process ||= { env: Netlify.env.toObject() };
}
});
// src/index.ts
var import_globals = __toESM(require_globals());
// src/common/server.ts
import { createRequestHandler as createRemixRequestHandler } from "@netlify/remix-runtime";
function createRequestHandler({
build,
mode,
getLoadContext
}) {
const remixHandler = createRemixRequestHandler(build, mode);
const assetPath = build.assets.url.split("/").slice(0, -1).join("/");
return async (request, context) => {
const { pathname } = new URL(request.url);
if (pathname.startsWith(`${assetPath}/`)) {
return;
}
try {
const loadContext = await (getLoadContext == null ? void 0 : getLoadContext(request, context)) || context;
const response = await remixHandler(request, loadContext);
response.headers.set("x-nf-runtime", "Edge");
if (response.status === 404) {
const originResponse = await loadContext.next({
sendConditionalRequest: true
});
if (originResponse && (originResponse == null ? void 0 : originResponse.status) !== 404) {
return originResponse;
}
}
return response;
} catch (error) {
console.error(error);
return new Response("Internal Error", { status: 500 });
}
};
}
// src/classic-compiler/defaultRemixConfig.ts
var config = {
server: "./server.ts",
ignoredRouteFiles: ["**/.*"],
serverBuildPath: ".netlify/edge-functions/server.js",
serverConditions: ["deno", "worker"],
serverDependenciesToBundle: "all",
serverMainFields: ["module", "main"],
serverModuleFormat: "esm",
serverPlatform: "neutral"
};
// src/common/entry.server.tsx
import { RemixServer } from "@remix-run/react";
import { isbot } from "isbot";
import * as ReactDOMServer from "react-dom/server";
import { jsx } from "react/jsx-runtime";
async function handleRequest(request, responseStatusCode, responseHeaders, remixContext, _loadContext) {
let isStreamClosing = false;
const abortController = new AbortController();
request.signal.addEventListener("abort", () => {
if (!isStreamClosing) {
abortController.abort(request.signal.reason);
}
});
const body = await ReactDOMServer.renderToReadableStream(/* @__PURE__ */ jsx(RemixServer, { context: remixContext, url: request.url }), {
signal: abortController.signal,
onError(error) {
console.error(error);
responseStatusCode = 500;
}
});
const transformedBody = body.pipeThrough(
new TransformStream({
flush() {
isStreamClosing = true;
}
})
);
if (isbot(request.headers.get("user-agent") || "")) {
await body.allReady;
}
responseHeaders.set("Content-Type", "text/html");
return new Response(transformedBody, {
headers: responseHeaders,
status: responseStatusCode
});
}
// src/vite/hydrogen.ts
var executionContext = {
/**
* Hydrogen expects a `waitUntil` function like the one in the workerd runtime:
* https://developers.cloudflare.com/workers/runtime-apis/context/#waituntil.
* Netlify Edge Functions don't have such a function, but Deno Deploy isolates make a best-effort
* attempt to wait for the event loop to drain, so just awaiting the promise here is equivalent.
*/
async waitUntil(p) {
await p;
}
};
var getEnv = () => {
if (globalThis.Netlify) {
return globalThis.Netlify.env.toObject();
}
return process.env;
};
var createHydrogenAppLoadContext = async (request, netlifyContext, createAppLoadContext) => {
const env = getEnv();
const userHydrogenContext = await createAppLoadContext(request, env, executionContext);
return Object.assign(netlifyContext, userHydrogenContext);
};
export {
config,
createHydrogenAppLoadContext,
createRequestHandler,
handleRequest
};