Skip to content

Commit

Permalink
feat(serverless-component): custom cache control config. for next pub…
Browse files Browse the repository at this point in the history
…lic directory
  • Loading branch information
danielcondemarin authored May 9, 2020
2 parents 0dc5881 + ff90c65 commit 86228a3
Show file tree
Hide file tree
Showing 20 changed files with 352 additions and 90 deletions.
180 changes: 120 additions & 60 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions packages/s3-static-assets/package-lock.json

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

3 changes: 2 additions & 1 deletion packages/s3-static-assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"aws-sdk": "^2.664.0",
"fs-extra": "^9.0.0",
"klaw": "^3.0.0",
"mime-types": "^2.1.27"
"mime-types": "^2.1.27",
"regex-parser": "^2.2.10"
},
"devDependencies": {
"@types/fs-extra": "^8.1.0",
Expand Down
21 changes: 18 additions & 3 deletions packages/s3-static-assets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import filterOutDirectories from "./lib/filterOutDirectories";
import { IMMUTABLE_CACHE_CONTROL_HEADER } from "./lib/constants";
import S3ClientFactory, { Credentials } from "./lib/s3";
import pathToPosix from "./lib/pathToPosix";
import getPublicAssetCacheControl, {
PublicDirectoryCache
} from "./lib/getPublicAssetCacheControl";

type UploadStaticAssetsOptions = {
bucketName: string;
nextConfigDir: string;
nextStaticDir?: string;
credentials: Credentials;
publicDirectoryCache?: PublicDirectoryCache;
};

const uploadStaticAssets = async (
Expand Down Expand Up @@ -66,7 +70,8 @@ const uploadStaticAssets = async (
});

const uploadPublicOrStaticDirectory = async (
directory: "public" | "static"
directory: "public" | "static",
publicDirectoryCache?: PublicDirectoryCache
): Promise<Promise<AWS.S3.ManagedUpload.SendData>[]> => {
const directoryPath = path.join(nextStaticDir, directory);
if (!(await fse.pathExists(directoryPath))) {
Expand All @@ -80,13 +85,23 @@ const uploadStaticAssets = async (
filePath: fileItem.path,
s3Key: pathToPosix(
path.relative(path.resolve(nextStaticDir), fileItem.path)
),
cacheControl: getPublicAssetCacheControl(
fileItem.path,
publicDirectoryCache
)
})
);
};

const publicDirUploads = await uploadPublicOrStaticDirectory("public");
const staticDirUploads = await uploadPublicOrStaticDirectory("static");
const publicDirUploads = await uploadPublicOrStaticDirectory(
"public",
options.publicDirectoryCache
);
const staticDirUploads = await uploadPublicOrStaticDirectory(
"static",
options.publicDirectoryCache
);

const allUploads = [
...buildStaticFileUploads, // .next/static
Expand Down
4 changes: 4 additions & 0 deletions packages/s3-static-assets/src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export const IMMUTABLE_CACHE_CONTROL_HEADER =
"public, max-age=31536000, immutable";

export const DEFAULT_PUBLIC_DIR_CACHE_CONTROL =
"public, max-age=31536000, must-revalidate";
export const DEFAULT_PUBLIC_DIR_CACHE_REGEX = /\.(gif|jpe?g|jp2|tiff|png|webp|bmp|svg|ico)$/i;
48 changes: 48 additions & 0 deletions packages/s3-static-assets/src/lib/getPublicAssetCacheControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import path from "path";
import regexParser from "regex-parser";
import {
DEFAULT_PUBLIC_DIR_CACHE_CONTROL,
DEFAULT_PUBLIC_DIR_CACHE_REGEX
} from "./constants";

export type PublicDirectoryCache =
| boolean
| {
test?: string;
value?: string;
};

/**
* If options is not present, or is explicitly set to true, returns a default Cache-Control configuration for image types.
* If options is explicitly set to false, it returns undefined.
* If assigned an options object, it uses whichever value is defined there, falling back to the default if one is not present.
*/
const getPublicAssetCacheControl = (
filePath: string,
options?: PublicDirectoryCache
): string | undefined => {
if (options === false) {
return undefined;
}

let value: string = DEFAULT_PUBLIC_DIR_CACHE_CONTROL;
let test: RegExp = DEFAULT_PUBLIC_DIR_CACHE_REGEX;

if (typeof options === "object") {
if (options.value) {
value = options.value;
}

if (options.test) {
test = regexParser(options.test);
}
}

if (test.test(path.basename(filePath))) {
return value;
}

return undefined;
};

export default getPublicAssetCacheControl;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"/todos/terms": "pages/todos/terms.html",
"/todos/terms/[section]": "pages/todos/terms/[section].html"
}
Empty file.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 51 additions & 3 deletions packages/s3-static-assets/tests/upload-assets.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import path from "path";
import uploadStaticAssets from "../src/index";
import { IMMUTABLE_CACHE_CONTROL_HEADER } from "../src/lib/constants";
import {
IMMUTABLE_CACHE_CONTROL_HEADER,
DEFAULT_PUBLIC_DIR_CACHE_CONTROL
} from "../src/lib/constants";
import AWS, {
mockGetBucketAccelerateConfigurationPromise,
mockGetBucketAccelerateConfiguration,
Expand All @@ -14,7 +17,13 @@ jest.mock("aws-sdk", () => require("./aws-sdk.mock"));

const upload = (
nextConfigDir: string,
nextStaticDir?: string
nextStaticDir?: string,
publicAssetCache?:
| boolean
| {
test?: string;
value?: string;
}
): Promise<AWS.S3.ManagedUpload.SendData[]> => {
let staticDir = nextStaticDir;

Expand All @@ -30,7 +39,8 @@ const upload = (
accessKeyId: "fake-access-key",
secretAccessKey: "fake-secret-key",
sessionToken: "fake-session-token"
}
},
publicDirectoryCache: publicAssetCache
});
};

Expand Down Expand Up @@ -180,3 +190,41 @@ describe.each`
});
}
);

describe.each`
publicDirectoryCache | expected
${undefined} | ${DEFAULT_PUBLIC_DIR_CACHE_CONTROL}
${false} | ${undefined}
${true} | ${DEFAULT_PUBLIC_DIR_CACHE_CONTROL}
${{ value: "public, max-age=36000" }} | ${"public, max-age=36000"}
${{ value: "public, max-age=36000", test: "/.(txt|xml)$/i" }} | ${undefined}
`(
"Public directory cache settings - publicDirectoryCache=$publicDirectoryCache, expected=$expected",
({ publicDirectoryCache, expected }) => {
beforeEach(async () => {
await upload(
"./fixtures/app-with-images",
undefined,
publicDirectoryCache
);
});

it(`sets ${expected} for input value of ${publicDirectoryCache}`, () => {
expect(mockUpload).toBeCalledWith(
expect.objectContaining({
Key: "public/1x1.png",
ContentType: "image/png",
CacheControl: expected
})
);

expect(mockUpload).toBeCalledWith(
expect.objectContaining({
Key: "static/1x1.png",
ContentType: "image/png",
CacheControl: expected
})
);
});
}
);
Loading

0 comments on commit 86228a3

Please sign in to comment.