hunk.code_window: ## JavaScript Runtimes
   Remix can be deployed to any JavaScript runtime like Node.js, Shopify Oxygen, Cloudflare Workers/Pages, Fastly Functions, Deno, Bun, etc.
   Each runtime has varying support for the standard Web APIs that Remix is built on, so Remix runtime package is required to polyfill any missing features of the runtime. These polyfills include web standard APIs like Request, Response, crypto, and more. This allows you to use the same APIs on the server as in the browser.
   The following runtimes packages are available:
  
hunk.labels: keep keep keep replace keep keep keep keep keep
hunk.after_edit: Remix can be deployed to any JavaScript runtime like Node.js, Shopify Oxygen, Cloudflare Workers/Pages, Fastly Compute, Deno, Bun, etc.
  
hunk.file_path: docs/discussion/runtimes.md
hunk.type: replace
file: import { createRequestHandler } from "@remix-run/express";
  import { installGlobals } from "@remix-run/node";
  import compression from "compression";
  import express from "express";
  import morgan from "morgan";
  
  installGlobals();
  
  const viteDevServer =
    process.env.NODE_ENV === "production"
      ? undefined
      : await import("vite").then((vite) =>
          vite.createServer({
            server: { middlewareMode: true },
          })
        );
  
  const remixHandler = createRequestHandler({
    build: viteDevServer
      ? () => viteDevServer.ssrLoadModule("virtual:remix/server-build")
      : await import("./build/server/index.js"),
  });
  
  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");
  
  // handle asset requests
  if (viteDevServer) {
    app.use(viteDevServer.middlewares);
  } else {
    // Vite fingerprints its assets so we can cache forever.
    app.use(
      "/assets",
      express.static("build/client/assets", { 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("build/client", { maxAge: "1h" }));
  
  app.use(morgan("tiny"));
  
  // handle SSR requests
  app.all("*", remixHandler);
  
  const port = process.env.PORT || 3000;
  app.listen(port, () =>
    console.log(`Express server listening at http://localhost:${port}`)
  );
  