Skip to content
This repository was archived by the owner on Jan 28, 2025. It is now read-only.

Commit 86228a3

Browse files
feat(serverless-component): custom cache control config. for next public directory
2 parents 0dc5881 + ff90c65 commit 86228a3

File tree

20 files changed

+352
-90
lines changed

20 files changed

+352
-90
lines changed

package-lock.json

Lines changed: 120 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/s3-static-assets/package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/s3-static-assets/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"aws-sdk": "^2.664.0",
3636
"fs-extra": "^9.0.0",
3737
"klaw": "^3.0.0",
38-
"mime-types": "^2.1.27"
38+
"mime-types": "^2.1.27",
39+
"regex-parser": "^2.2.10"
3940
},
4041
"devDependencies": {
4142
"@types/fs-extra": "^8.1.0",

packages/s3-static-assets/src/index.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import filterOutDirectories from "./lib/filterOutDirectories";
66
import { IMMUTABLE_CACHE_CONTROL_HEADER } from "./lib/constants";
77
import S3ClientFactory, { Credentials } from "./lib/s3";
88
import pathToPosix from "./lib/pathToPosix";
9+
import getPublicAssetCacheControl, {
10+
PublicDirectoryCache
11+
} from "./lib/getPublicAssetCacheControl";
912

1013
type UploadStaticAssetsOptions = {
1114
bucketName: string;
1215
nextConfigDir: string;
1316
nextStaticDir?: string;
1417
credentials: Credentials;
18+
publicDirectoryCache?: PublicDirectoryCache;
1519
};
1620

1721
const uploadStaticAssets = async (
@@ -66,7 +70,8 @@ const uploadStaticAssets = async (
6670
});
6771

6872
const uploadPublicOrStaticDirectory = async (
69-
directory: "public" | "static"
73+
directory: "public" | "static",
74+
publicDirectoryCache?: PublicDirectoryCache
7075
): Promise<Promise<AWS.S3.ManagedUpload.SendData>[]> => {
7176
const directoryPath = path.join(nextStaticDir, directory);
7277
if (!(await fse.pathExists(directoryPath))) {
@@ -80,13 +85,23 @@ const uploadStaticAssets = async (
8085
filePath: fileItem.path,
8186
s3Key: pathToPosix(
8287
path.relative(path.resolve(nextStaticDir), fileItem.path)
88+
),
89+
cacheControl: getPublicAssetCacheControl(
90+
fileItem.path,
91+
publicDirectoryCache
8392
)
8493
})
8594
);
8695
};
8796

88-
const publicDirUploads = await uploadPublicOrStaticDirectory("public");
89-
const staticDirUploads = await uploadPublicOrStaticDirectory("static");
97+
const publicDirUploads = await uploadPublicOrStaticDirectory(
98+
"public",
99+
options.publicDirectoryCache
100+
);
101+
const staticDirUploads = await uploadPublicOrStaticDirectory(
102+
"static",
103+
options.publicDirectoryCache
104+
);
90105

91106
const allUploads = [
92107
...buildStaticFileUploads, // .next/static
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
export const IMMUTABLE_CACHE_CONTROL_HEADER =
22
"public, max-age=31536000, immutable";
3+
4+
export const DEFAULT_PUBLIC_DIR_CACHE_CONTROL =
5+
"public, max-age=31536000, must-revalidate";
6+
export const DEFAULT_PUBLIC_DIR_CACHE_REGEX = /\.(gif|jpe?g|jp2|tiff|png|webp|bmp|svg|ico)$/i;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import path from "path";
2+
import regexParser from "regex-parser";
3+
import {
4+
DEFAULT_PUBLIC_DIR_CACHE_CONTROL,
5+
DEFAULT_PUBLIC_DIR_CACHE_REGEX
6+
} from "./constants";
7+
8+
export type PublicDirectoryCache =
9+
| boolean
10+
| {
11+
test?: string;
12+
value?: string;
13+
};
14+
15+
/**
16+
* If options is not present, or is explicitly set to true, returns a default Cache-Control configuration for image types.
17+
* If options is explicitly set to false, it returns undefined.
18+
* If assigned an options object, it uses whichever value is defined there, falling back to the default if one is not present.
19+
*/
20+
const getPublicAssetCacheControl = (
21+
filePath: string,
22+
options?: PublicDirectoryCache
23+
): string | undefined => {
24+
if (options === false) {
25+
return undefined;
26+
}
27+
28+
let value: string = DEFAULT_PUBLIC_DIR_CACHE_CONTROL;
29+
let test: RegExp = DEFAULT_PUBLIC_DIR_CACHE_REGEX;
30+
31+
if (typeof options === "object") {
32+
if (options.value) {
33+
value = options.value;
34+
}
35+
36+
if (options.test) {
37+
test = regexParser(options.test);
38+
}
39+
}
40+
41+
if (test.test(path.basename(filePath))) {
42+
return value;
43+
}
44+
45+
return undefined;
46+
};
47+
48+
export default getPublicAssetCacheControl;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"/todos/terms": "pages/todos/terms.html",
3+
"/todos/terms/[section]": "pages/todos/terms/[section].html"
4+
}

packages/s3-static-assets/tests/fixtures/app-with-images/.next/serverless/pages/todos/terms.html

Whitespace-only changes.

packages/s3-static-assets/tests/fixtures/app-with-images/.next/serverless/pages/todos/terms/[section].html

Whitespace-only changes.

packages/s3-static-assets/tests/fixtures/app-with-images/.next/static/a_test_build_id/css/one.css

Whitespace-only changes.

packages/s3-static-assets/tests/fixtures/app-with-images/.next/static/a_test_build_id/two.js

Whitespace-only changes.

packages/s3-static-assets/tests/fixtures/app-with-images/.next/static/chunks/chunk1.js

Whitespace-only changes.

packages/s3-static-assets/tests/fixtures/app-with-images/.next/static/runtime/runtime1.js

Whitespace-only changes.
Loading
Loading

packages/s3-static-assets/tests/upload-assets.test.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import path from "path";
22
import uploadStaticAssets from "../src/index";
3-
import { IMMUTABLE_CACHE_CONTROL_HEADER } from "../src/lib/constants";
3+
import {
4+
IMMUTABLE_CACHE_CONTROL_HEADER,
5+
DEFAULT_PUBLIC_DIR_CACHE_CONTROL
6+
} from "../src/lib/constants";
47
import AWS, {
58
mockGetBucketAccelerateConfigurationPromise,
69
mockGetBucketAccelerateConfiguration,
@@ -14,7 +17,13 @@ jest.mock("aws-sdk", () => require("./aws-sdk.mock"));
1417

1518
const upload = (
1619
nextConfigDir: string,
17-
nextStaticDir?: string
20+
nextStaticDir?: string,
21+
publicAssetCache?:
22+
| boolean
23+
| {
24+
test?: string;
25+
value?: string;
26+
}
1827
): Promise<AWS.S3.ManagedUpload.SendData[]> => {
1928
let staticDir = nextStaticDir;
2029

@@ -30,7 +39,8 @@ const upload = (
3039
accessKeyId: "fake-access-key",
3140
secretAccessKey: "fake-secret-key",
3241
sessionToken: "fake-session-token"
33-
}
42+
},
43+
publicDirectoryCache: publicAssetCache
3444
});
3545
};
3646

@@ -180,3 +190,41 @@ describe.each`
180190
});
181191
}
182192
);
193+
194+
describe.each`
195+
publicDirectoryCache | expected
196+
${undefined} | ${DEFAULT_PUBLIC_DIR_CACHE_CONTROL}
197+
${false} | ${undefined}
198+
${true} | ${DEFAULT_PUBLIC_DIR_CACHE_CONTROL}
199+
${{ value: "public, max-age=36000" }} | ${"public, max-age=36000"}
200+
${{ value: "public, max-age=36000", test: "/.(txt|xml)$/i" }} | ${undefined}
201+
`(
202+
"Public directory cache settings - publicDirectoryCache=$publicDirectoryCache, expected=$expected",
203+
({ publicDirectoryCache, expected }) => {
204+
beforeEach(async () => {
205+
await upload(
206+
"./fixtures/app-with-images",
207+
undefined,
208+
publicDirectoryCache
209+
);
210+
});
211+
212+
it(`sets ${expected} for input value of ${publicDirectoryCache}`, () => {
213+
expect(mockUpload).toBeCalledWith(
214+
expect.objectContaining({
215+
Key: "public/1x1.png",
216+
ContentType: "image/png",
217+
CacheControl: expected
218+
})
219+
);
220+
221+
expect(mockUpload).toBeCalledWith(
222+
expect.objectContaining({
223+
Key: "static/1x1.png",
224+
ContentType: "image/png",
225+
CacheControl: expected
226+
})
227+
);
228+
});
229+
}
230+
);

0 commit comments

Comments
 (0)