Skip to content

Commit

Permalink
feat: fix and allow configuring cache control (#326)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcansh authored Apr 25, 2024
1 parent beab50e commit a7fcb6d
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 52 deletions.
13 changes: 13 additions & 0 deletions .changeset/cold-turtles-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@mcansh/remix-fastify": patch
"basic-example-template": patch
---

allows you to customize the cache control for both the files in the build directory as well as your public directory if you need to. using `pretty-cache-header` under the hood so things like `1y` or `30 days` will work

```js
await app.register(remixFastify, {
assetCacheControl: {},
defaultCacheControl: {},
});
```
5 changes: 5 additions & 0 deletions .changeset/fifty-lemons-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@mcansh/remix-fastify": patch
---

fix cache control so that build assets are immutable and cached for 1 year instead of everything being cached for 1 hour
3 changes: 2 additions & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dev": "remix dev --manual -c \"node --watch-path ./server.js --enable-source-maps ./server.js\"",
"lint": "eslint --ignore-path .gitignore --no-error-on-unmatched-pattern --cache --cache-location node_modules/.cache/eslint --fix .",
"format": "prettier --ignore-path .gitignore --ignore-unknown --cache --cache-location node_modules/.cache/prettiercache --write .",
"start": "node --enable-source-maps ./server.js",
"start": "cross-env NODE_ENV=production node --enable-source-maps ./server.js",
"typecheck": "tsc"
},
"dependencies": {
Expand All @@ -17,6 +17,7 @@
"@remix-run/css-bundle": "*",
"@remix-run/node": "*",
"@remix-run/react": "*",
"cross-env": "^7.0.3",
"fastify": "^4.26.2",
"isbot": "^5.1.4",
"react": "^18.2.0",
Expand Down
58 changes: 42 additions & 16 deletions examples/basic/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,56 @@ if (process.env.NODE_ENV === "development") {

let app = fastify();

let PUBLIC_DIR = path.join(__dirname, "public");
let BUILD_DIR = path.join(PUBLIC_DIR, "build");

let ASSET_CACHE_CONTROL = "public, max-age=31536000, immutable";
let DEFAULT_CACHE_CONTROL = "public, max-age=3600";

function setHeaders(res, filepath) {
let isAsset = filepath.startsWith(BUILD_DIR);
res.setHeader(
"cache-control",
isAsset ? ASSET_CACHE_CONTROL : DEFAULT_CACHE_CONTROL,
);
}

if (process.env.NODE_ENV === "production") {
await app.register(fastifyStatic, {
root: PUBLIC_DIR,
prefix: "/",
wildcard: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
serveDotFiles: true,
lastModified: true,
setHeaders,
});
} else
await app.register(fastifyStatic, {
root: BUILD_DIR,
prefix: "/build",
wildcard: true,
decorateReply: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
serveDotFiles: true,
lastModified: true,
setHeaders,
});

await app.register(fastifyStatic, {
root: path.join(__dirname, "public"),
root: PUBLIC_DIR,
prefix: "/",
wildcard: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
maxAge: "1h",
serveDotFiles: true,
lastModified: true,
});

await app.register(fastifyStatic, {
root: path.join(__dirname, "public", "build"),
prefix: "/build",
wildcard: true,
decorateReply: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
maxAge: "1y",
immutable: true,
serveDotFiles: true,
lastModified: true,
setHeaders,
});

app.register(async function (childServer) {
Expand Down
3 changes: 2 additions & 1 deletion packages/remix-fastify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
"@fastify/middie": "^8.3.0",
"@fastify/static": "^7.0.3",
"@remix-run/router": "^1.16.0",
"fastify-plugin": "^4.5.1"
"fastify-plugin": "^4.5.1",
"pretty-cache-header": "^1.0.0"
},
"devDependencies": {
"@remix-run/node": "^2.9.0",
Expand Down
75 changes: 41 additions & 34 deletions packages/remix-fastify/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from "node:path";
import fp from "fastify-plugin";
import type { ViteDevServer } from "vite";
import fastifyStatic from "@fastify/static";
import { cacheHeader } from "pretty-cache-header";

import { createRequestHandler } from "./server";
import type { HttpServer, GetLoadContextFunction } from "./server";
Expand All @@ -28,6 +29,20 @@ export type RemixFastifyOptions = {
*/
getLoadContext?: GetLoadContextFunction<HttpServer>;
mode?: string;
/**
* The cache control options to use for build assets in production.
* uses `pretty-cache-header` under the hood.
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
* @default { public: true, maxAge: '1 year', immutable: true }
*/
assetCacheControl?: Parameters<typeof cacheHeader>[0];
/**
* The cache control options to use for other assets in production.
* uses `pretty-cache-header` under the hood.
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
* @default { public: true, maxAge: '1 hour' }
*/
defaultCacheControl?: Parameters<typeof cacheHeader>[0];
};

export let remixFastify = fp<RemixFastifyOptions>(
Expand All @@ -38,6 +53,8 @@ export let remixFastify = fp<RemixFastifyOptions>(
buildDirectory = "build",
getLoadContext,
mode = process.env.NODE_ENV,
assetCacheControl = { public: true, maxAge: "1 year", immutable: true },
defaultCacheControl = { public: true, maxAge: "1 hour" },
},
) => {
let cwd = process.env.REMIX_ROOT ?? process.cwd();
Expand All @@ -52,48 +69,38 @@ export let remixFastify = fp<RemixFastifyOptions>(

let resolvedBuildDirectory = path.resolve(cwd, buildDirectory);

let serverBuildPath = path.join(
resolvedBuildDirectory,
"server",
"index.js",
);
let SERVER_BUILD = path.join(resolvedBuildDirectory, "server", "index.js");

// handle asset requests
if (vite) {
let middie = await import("@fastify/middie").then((mod) => mod.default);
await fastify.register(middie);
fastify.use(vite.middlewares);
} else {
await Promise.all([
fastify.register(fastifyStatic, {
root: path.join(resolvedBuildDirectory, "client", "assets"),
prefix: "/assets",
wildcard: true,
cacheControl: true,
dotfiles: "allow",
etag: true,
maxAge: "1y",
immutable: true,
serveDotFiles: true,
lastModified: true,
}),

fastify.register(fastifyStatic, {
root: path.join(resolvedBuildDirectory, "client"),
prefix: "/",
wildcard: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
maxAge: "1h",
serveDotFiles: true,
lastModified: true,
decorateReply: false,
}),
]);
let BUILD_DIR = path.join(resolvedBuildDirectory, "client");
let ASSET_DIR = path.join(BUILD_DIR, "assets");
await fastify.register(fastifyStatic, {
root: BUILD_DIR,
prefix: "/",
wildcard: false,
cacheControl: true,
dotfiles: "allow",
etag: true,
serveDotFiles: true,
lastModified: true,
setHeaders(res, filepath) {
let isAsset = filepath.startsWith(ASSET_DIR);
res.setHeader(
"cache-control",
isAsset
? cacheHeader(assetCacheControl)
: cacheHeader(defaultCacheControl),
);
},
});
}

fastify.register(async function (childServer) {
fastify.register(async function createRemixRequestHandler(childServer) {
// remove the default content type parsers
childServer.removeAllContentTypeParsers();
// allow all content types
Expand All @@ -114,7 +121,7 @@ export let remixFastify = fp<RemixFastifyOptions>(
if (!vite) throw new Error("we lost vite!");
return vite.ssrLoadModule("virtual:remix/server-build");
}
: () => import(serverBuildPath),
: () => import(SERVER_BUILD),
});

return handler(request, reply);
Expand Down
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a7fcb6d

Please sign in to comment.