UNPKG

@netlify/remix-edge-adapter

Version:

Remix Adapter for Netlify Edge Functions

284 lines (278 loc) 9.82 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/vite/plugin.ts var plugin_exports = {}; __export(plugin_exports, { netlifyPlugin: () => netlifyPlugin }); module.exports = __toCommonJS(plugin_exports); var import_node_adapter = require("@remix-run/dev/dist/vite/node-adapter.js"); var import_promises = require("fs/promises"); var import_node_path = require("path"); var import_posix = require("path/posix"); var import_node_module = require("module"); // package.json var name = "@netlify/remix-edge-adapter"; var version = "3.4.3"; // src/vite/plugin.ts var NETLIFY_EDGE_FUNCTIONS_DIR = ".netlify/edge-functions"; var EDGE_FUNCTION_FILENAME = "remix-server.mjs"; var EDGE_FUNCTION_HANDLER_CHUNK = "server"; var EDGE_FUNCTION_HANDLER_MODULE_ID = "virtual:netlify-server"; var RESOLVED_EDGE_FUNCTION_HANDLER_MODULE_ID = `\0${EDGE_FUNCTION_HANDLER_MODULE_ID}`; var toPosixPath = (path) => path.split(import_node_path.sep).join(import_posix.sep); var notImplemented = () => { throw new Error(` This is a fake Netlify context object for local dev. It is not supported here, but it will work with \`netlify serve\` and in a production build. To fix this, add it as custom context in your \`createAppLoadContext\` conditionally in dev. `); }; var getFakeNetlifyContext = (url) => ({ url: new URL(url), requestId: "fake-netlify-request-id-for-dev", next: async () => new Response("", { status: 404 }), geo: { city: "Mock City", country: { code: "MC", name: "Mock Country" }, subdivision: { code: "MS", name: "Mock Subdivision" }, longitude: 0, latitude: 0, timezone: "UTC" }, get cookies() { return notImplemented(); }, get deploy() { return notImplemented(); }, get ip() { return notImplemented(); }, get json() { return notImplemented(); }, get log() { return notImplemented(); }, get params() { return notImplemented(); }, get rewrite() { return notImplemented(); }, get site() { return notImplemented(); }, get account() { return notImplemented(); }, get server() { return notImplemented(); } }); var EDGE_FUNCTION_HANDLER = ( /* js */ ` import { createRequestHandler } from "@netlify/remix-edge-adapter"; import * as build from "virtual:remix/server-build"; export default createRequestHandler({ build, getLoadContext: async (_req, ctx) => ctx, }); ` ); function generateEdgeFunction(handlerPath, exclude = []) { return ( /* js */ ` export { default } from "${handlerPath}"; export const config = { name: "Remix server handler", generator: "${name}@${version}", cache: "manual", path: "/*", excludedPath: ${JSON.stringify(exclude)}, };` ); } var ALLOWED_USER_EDGE_FUNCTION_HANDLER_FILENAMES = [ "server.ts", "server.mts", "server.cts", "server.mjs", "server.cjs", "server.js" ]; var findUserEdgeFunctionHandlerFile = async (root) => { for (const filename of ALLOWED_USER_EDGE_FUNCTION_HANDLER_FILENAMES) { try { await (0, import_promises.access)((0, import_node_path.join)(root, filename)); return filename; } catch { } } throw new Error( "Your Hydrogen site must include a `server.ts` (or js/mjs/cjs/mts/cts) file at the root to deploy to Netlify. See https://github.com/netlify/hydrogen-template." ); }; var getEdgeFunctionHandlerModuleId = async (root, isHydrogenSite) => { if (!isHydrogenSite) return EDGE_FUNCTION_HANDLER_MODULE_ID; return findUserEdgeFunctionHandlerFile(root); }; function netlifyPlugin() { let resolvedConfig; let currentCommand; let isSsr; let isHydrogenSite; return { name: "vite-plugin-remix-netlify-edge", config(config, { command, isSsrBuild }) { currentCommand = command; isSsr = isSsrBuild; if (command === "build") { if (isSsrBuild) { config.ssr = { ...config.ssr, target: "webworker", // Only externalize Node builtins noExternal: /^(?!node:).*$/ }; } } }, configResolved: { order: "pre", async handler(config) { var _a, _b; resolvedConfig = config; isHydrogenSite = resolvedConfig.plugins.find((plugin) => plugin.name === "hydrogen:main") != null; if (currentCommand === "build" && isSsr) { if (typeof ((_b = (_a = config.build) == null ? void 0 : _a.rollupOptions) == null ? void 0 : _b.input) === "string") { const edgeFunctionHandlerModuleId = await getEdgeFunctionHandlerModuleId( resolvedConfig.root, isHydrogenSite ); config.build.rollupOptions.input = { [EDGE_FUNCTION_HANDLER_CHUNK]: edgeFunctionHandlerModuleId, index: config.build.rollupOptions.input }; if (config.build.rollupOptions.output && !Array.isArray(config.build.rollupOptions.output)) { config.build.rollupOptions.output.entryFileNames = () => "[name].js"; } } } else if (isHydrogenSite && currentCommand === "serve") { config.build.ssr = await findUserEdgeFunctionHandlerFile(resolvedConfig.root); } } }, resolveId: { order: "pre", async handler(source, importer, options) { if (source === "virtual:netlify-server-entry") { if (currentCommand === "build" && options.ssr) { return this.resolve("@netlify/remix-edge-adapter/entry.server", importer, { ...options, skipSelf: true }); } else { return this.resolve("@remix-run/dev/dist/config/defaults/entry.server.node", importer, { ...options, skipSelf: true }); } } if (source === EDGE_FUNCTION_HANDLER_MODULE_ID) { return RESOLVED_EDGE_FUNCTION_HANDLER_MODULE_ID; } if (isSsr && (0, import_node_module.isBuiltin)(source)) { return { // Deno needs Node builtins to be prefixed id: source.startsWith("node:") ? source : `node:${source}`, external: true, moduleSideEffects: false }; } return null; } }, // See https://vitejs.dev/guide/api-plugin#virtual-modules-convention. load(id) { if (id === RESOLVED_EDGE_FUNCTION_HANDLER_MODULE_ID) { return EDGE_FUNCTION_HANDLER; } }, configureServer: { order: "pre", handler(viteDevServer) { return () => { if (isHydrogenSite && !viteDevServer.config.server.middlewareMode) { viteDevServer.middlewares.use(async (nodeReq, nodeRes, next) => { try { const edgeFunctionHandlerModuleId = await findUserEdgeFunctionHandlerFile(resolvedConfig.root); let build = await viteDevServer.ssrLoadModule(edgeFunctionHandlerModuleId); const handleRequest = build.default; let req = (0, import_node_adapter.fromNodeRequest)(nodeReq, nodeRes); const res = await handleRequest(req, getFakeNetlifyContext(req.url)); if (res instanceof Response) return await (0, import_node_adapter.toNodeRequest)(res, nodeRes); if (res instanceof URL) { next(new Error("URLs are not supported in dev server middleware")); return; } next(); } catch (error) { next(error); } }); } }; } }, // See https://rollupjs.org/plugin-development/#writebundle. async writeBundle() { if (currentCommand === "build" && isSsr) { const exclude = ["/.netlify/*"]; try { const clientDirectory = (0, import_node_path.join)(resolvedConfig.build.outDir, "..", "client"); const entries = await (0, import_promises.readdir)(clientDirectory, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory()) { exclude.push(`/${entry.name}/*`); } else if (entry.isFile()) { exclude.push(`/${entry.name}`); } } } catch { } const edgeFunctionsDirectory = (0, import_node_path.join)(resolvedConfig.root, NETLIFY_EDGE_FUNCTIONS_DIR); await (0, import_promises.mkdir)(edgeFunctionsDirectory, { recursive: true }); const handlerPath = (0, import_node_path.join)(resolvedConfig.build.outDir, `${EDGE_FUNCTION_HANDLER_CHUNK}.js`); const relativeHandlerPath = toPosixPath((0, import_node_path.relative)(edgeFunctionsDirectory, handlerPath)); await (0, import_promises.writeFile)( (0, import_node_path.join)(edgeFunctionsDirectory, EDGE_FUNCTION_FILENAME), generateEdgeFunction(relativeHandlerPath, exclude) ); } } }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { netlifyPlugin });