Skip to content

Commit b226d37

Browse files
authored
fix: align cacheImmutable and Cache-Control semantics (#32)
1 parent 5019cef commit b226d37

5 files changed

Lines changed: 400 additions & 44 deletions

File tree

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ See [below](#other-servers) for examples of use with other servers.
7272
| **[`etag`](#tag)** | `boolean\| "weak"\| "strong"` | `undefined` | Enable or disable etag generation. |
7373
| **[`lastModified`](#lastmodified)** | `boolean` | `undefined` | Enable or disable `Last-Modified` header. Uses the file system's last modified value. |
7474
| **[`cacheControl`](#cachecontrol)** | `boolean\|number\|string\|Object` | `undefined` | Enable or disable setting `Cache-Control` response header. |
75-
| **[`cacheImmutable`](#cacheimmutable)** | `boolean\` | `undefined` | Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets. |
75+
| **[`cacheImmutable`](#cacheimmutable)** | `boolean` | `true` | Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets. |
7676
| **[`publicPath`](#publicpath)** | `string` | `undefined` | The public path that the middleware is bound to. |
7777
| **[`stats`](#stats)** | `boolean\|string\|Object` | `stats` (from a configuration) | Stats options object or preset name. |
7878
| **[`serverSideRender`](#serversiderender)** | `boolean` | `undefined` | Instructs the module to enable or disable the server-side rendering mode. |
@@ -196,21 +196,25 @@ Default: `undefined`
196196

197197
Depending on the setting, the following headers will be generated:
198198

199-
- `Boolean` - `Cache-Control: public, max-age=31536000000`
200-
- `Number` - `Cache-Control: public, max-age=YOUR_NUMBER`
199+
- `Boolean` - `Cache-Control: public, max-age=31536000`
200+
- `Number` - `Cache-Control: public, max-age=YOUR_NUMBER_IN_SECONDS`
201201
- `String` - `Cache-Control: YOUR_STRING`
202-
- `{ maxAge?: number, immutable?: boolean }` - `Cache-Control: public, max-age=YOUR_MAX_AGE_or_31536000000`, also `, immutable` can be added if you set the `immutable` option to `true`
202+
- `{ maxAge?: number, immutable?: boolean }` - `Cache-Control: public, max-age=YOUR_MAX_AGE_IN_SECONDS_or_31536000`, also `, immutable` is added when you set the `immutable` option to `true`
203+
204+
Numeric `cacheControl` and `cacheControl.maxAge` values are interpreted as milliseconds, clamped to `0..31536000000`, and converted to seconds for the response header.
203205

204206
Enable or disable setting `Cache-Control` response header.
205207

206208
### cacheImmutable
207209

208210
Type: `Boolean`
209-
Default: `undefined`
211+
Default: `true`
210212

211213
Enable or disable setting `Cache-Control: public, max-age=31536000, immutable` response header for immutable assets (i.e. asset with a hash like `image.a4c12bde.jpg`).
212214
Immutable assets are assets that have their hash in the file name therefore they can be cached, because if you change their contents the file name will be changed.
213-
Take preference over the `cacheControl` option if the asset was defined as immutable.
215+
When omitted, immutable assets use this header by default.
216+
Set `cacheImmutable: false` to fall back to the `cacheControl` option even for immutable assets.
217+
This takes precedence over the `cacheControl` option only when the asset was defined as immutable and `cacheImmutable` is not `false`.
214218

215219
### publicPath
216220

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ const noop = () => {};
126126
* @property {"weak" | "strong"=} etag options to generate etag header
127127
* @property {boolean=} lastModified options to generate last modified header
128128
* @property {(boolean | number | string | { maxAge?: number, immutable?: boolean })=} cacheControl options to generate cache headers
129-
* @property {boolean=} cacheImmutable is cache immutable
129+
* @property {boolean=} cacheImmutable enable immutable cache headers for immutable assets (defaults to true when omitted)
130130
*/
131131

132132
/**

src/middleware.js

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -605,40 +605,36 @@ function wrapper(context) {
605605
}
606606

607607
if (!getResponseHeader(res, "Cache-Control")) {
608-
// TODO enable the `cacheImmutable` by default for the next major release
609-
const cacheControl =
610-
context.options.cacheImmutable && extra.immutable
611-
? { immutable: true }
612-
: context.options.cacheControl;
613-
614-
if (cacheControl) {
615-
let cacheControlValue;
616-
617-
if (typeof cacheControl === "boolean") {
618-
cacheControlValue = "public, max-age=31536000";
619-
} else if (typeof cacheControl === "number") {
620-
const maxAge = Math.floor(
621-
Math.min(Math.max(0, cacheControl), MAX_MAX_AGE) / 1000,
622-
);
623-
624-
cacheControlValue = `public, max-age=${maxAge}`;
625-
} else if (typeof cacheControl === "string") {
626-
cacheControlValue = cacheControl;
627-
} else {
628-
const maxAge = cacheControl.maxAge
629-
? Math.floor(
630-
Math.min(Math.max(0, cacheControl.maxAge), MAX_MAX_AGE) /
631-
1000,
632-
)
633-
: MAX_MAX_AGE / 1000;
634-
635-
cacheControlValue = `public, max-age=${maxAge}`;
636-
637-
if (cacheControl.immutable) {
638-
cacheControlValue += ", immutable";
639-
}
608+
const { cacheControl, cacheImmutable } = context.options;
609+
const useImmutableCache =
610+
(cacheImmutable === undefined || cacheImmutable) && extra.immutable;
611+
612+
let cacheControlValue;
613+
614+
if (useImmutableCache) {
615+
cacheControlValue = `public, max-age=${Math.floor(MAX_MAX_AGE / 1000)}, immutable`;
616+
} else if (cacheControl === true) {
617+
cacheControlValue = `public, max-age=${Math.floor(MAX_MAX_AGE / 1000)}`;
618+
} else if (typeof cacheControl === "number") {
619+
const maxAge = Math.min(Math.max(0, cacheControl), MAX_MAX_AGE);
620+
621+
cacheControlValue = `public, max-age=${Math.floor(maxAge / 1000)}`;
622+
} else if (typeof cacheControl === "string") {
623+
cacheControlValue = cacheControl;
624+
} else if (cacheControl) {
625+
const maxAge =
626+
cacheControl.maxAge !== undefined
627+
? Math.min(Math.max(0, cacheControl.maxAge), MAX_MAX_AGE)
628+
: MAX_MAX_AGE;
629+
630+
cacheControlValue = `public, max-age=${Math.floor(maxAge / 1000)}`;
631+
632+
if (cacheControl.immutable) {
633+
cacheControlValue += ", immutable";
640634
}
635+
}
641636

637+
if (cacheControlValue) {
642638
setResponseHeader(res, "Cache-Control", cacheControlValue);
643639
}
644640
}

0 commit comments

Comments
 (0)