Skip to content

Commit 8517f0c

Browse files
danielcondemarinsclaughl
authored andcommitted
implementing upload of HTML pages
1 parent b3a9164 commit 8517f0c

File tree

6 files changed

+802
-49
lines changed

6 files changed

+802
-49
lines changed

package-lock.json

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

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"homepage": "https://github.com/danielcondemarin/serverless-next.js#readme",
3737
"devDependencies": {
3838
"@babel/preset-typescript": "^7.9.0",
39+
"@sls-next/lambda-at-edge": "file:packages/lambda-at-edge",
40+
"@types/fs-extra": "^8.1.0",
3941
"@types/jest": "^25.2.1",
4042
"@typescript-eslint/eslint-plugin": "^2.28.0",
4143
"@typescript-eslint/parser": "^2.28.0",
@@ -49,7 +51,6 @@
4951
"lerna": "^3.16.4",
5052
"next": "^9.1.5",
5153
"next-aws-cloudfront": "file:packages/lambda-at-edge-compat",
52-
"@sls-next/lambda-at-edge": "file:packages/lambda-at-edge",
5354
"prettier": "^1.17.1",
5455
"react": "^16.9.0",
5556
"react-dom": "^16.9.0",
@@ -84,6 +85,8 @@
8485
]
8586
},
8687
"dependencies": {
88+
"@aws-sdk/client-s3-node": "0.1.0-preview.2",
89+
"fs-extra": "^9.0.0",
8790
"opencollective-postinstall": "^2.0.2"
8891
},
8992
"collective": {
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
const promisifyMock = (mockFn: jest.Mock): jest.Mock => {
2+
const promise = jest.fn();
3+
mockFn.mockReturnValue({ promise });
4+
return promise;
5+
};
6+
17
export const mockUpload = jest.fn();
8+
export const mockUploadPromise = promisifyMock(mockUpload);
9+
10+
const MockS3 = jest.fn(() => ({
11+
upload: mockUpload
12+
}));
213

314
export default {
4-
S3: jest.fn(() => ({
5-
upload: mockUpload
6-
}))
15+
S3: MockS3
716
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const IMMUTABLE_CACHE_CONTROL_HEADER =
2+
"public, max-age=31536000, immutable";

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ type UploadStaticAssetsOptions = {
88
bucketName: string;
99
nextAppDir: string;
1010
};
11-
11+
const filePathToS3Key = (filePath: string): string => {
12+
const relevantFilePathPart = filePath.substring(
13+
filePath.indexOf(".next" + path.sep)
14+
);
15+
return relevantFilePathPart.replace(".next", "_next");
16+
};
1217
const readDirectoryFiles = (directory: string): Promise<Array<Item>> => {
1318
const items: Item[] = [];
1419
return new Promise((resolve, reject) => {
@@ -40,20 +45,22 @@ const uploadStaticAssets = async (
4045

4146
const uploadTasks = buildStaticFiles
4247
.filter(item => !item.stats.isDirectory())
43-
.map(fileItem => {
44-
return fse.readFile(fileItem.path).then(fileBodyStream =>
45-
s3
46-
.upload({
47-
Bucket: bucketName,
48-
Key: fileItem.path,
49-
Body: fileBodyStream,
50-
ContentType:
51-
mime.lookup(path.basename(fileItem.path)) ||
52-
"application/octet-stream",
53-
CacheControl: "public, max-age=31536000, immutable"
54-
})
55-
.promise()
56-
);
48+
.map(async fileItem => {
49+
const fileBody = await fse.readFile(fileItem.path);
50+
51+
const s3Key = filePathToS3Key(fileItem.path);
52+
53+
return s3
54+
.upload({
55+
Bucket: bucketName,
56+
Key: s3Key,
57+
Body: fileBody,
58+
ContentType:
59+
mime.lookup(path.basename(fileItem.path)) ||
60+
"application/octet-stream",
61+
CacheControl: "public, max-age=31536000, immutable"
62+
})
63+
.promise();
5764
});
5865

5966
await Promise.all(uploadTasks);
Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,52 @@
1-
import stream from "stream";
2-
import fse from "fs-extra";
31
import path from "path";
4-
import uploadStaticAssets from "../index";
2+
import uploadStaticAssets from "../src/index";
3+
import { IMMUTABLE_CACHE_CONTROL_HEADER } from "../src/constants";
54
import { mockUpload } from "aws-sdk";
65

76
declare module "aws-sdk" {
87
const mockUpload: jest.Mock;
98
}
109

1110
describe("Upload assets tests", () => {
12-
it("uploads any contents inside build directory specified in BUILD_ID", async () => {
11+
beforeEach(async () => {
1312
await uploadStaticAssets({
1413
bucketName: "test-bucket-name",
1514
nextAppDir: path.join(__dirname, "./fixtures/basic-next-app")
1615
});
16+
});
1717

18-
const mockedBodyStream = new stream.Readable();
19-
jest
20-
.spyOn(fse, "readFile")
21-
.mockResolvedValue(Promise.resolve(mockedBodyStream));
22-
23-
const expectedCacheControl = "public, max-age=31536000, immutable";
18+
it("uploads any contents inside build directory specified in BUILD_ID", async () => {
19+
expect(mockUpload).toBeCalledTimes(2);
2420

2521
expect(mockUpload).toBeCalledWith({
2622
Bucket: "test-bucket-name",
27-
Key: "_next/static/a_test_build_id/testFileOne.js",
28-
Body: mockedBodyStream,
23+
Key: "_next/static/a_test_build_id/two.js",
24+
Body: expect.any(Buffer),
2925
ContentType: "application/javascript",
30-
CacheControl: expectedCacheControl
26+
CacheControl: IMMUTABLE_CACHE_CONTROL_HEADER
3127
});
3228

3329
expect(mockUpload).toBeCalledWith({
3430
Bucket: "test-bucket-name",
35-
Key: "_next/static/a_test_build_id/subdir/testFileTwo.js",
36-
Body: mockedBodyStream,
37-
ContentType: "application/javascript",
38-
CacheControl: expectedCacheControl
31+
Key: "_next/static/a_test_build_id/css/one.css",
32+
Body: expect.any(Buffer),
33+
ContentType: "text/css",
34+
CacheControl: IMMUTABLE_CACHE_CONTROL_HEADER
35+
});
36+
});
37+
38+
it("uploads prerendered HTML pages specified in pages manifest", async () => {
39+
expect(mockUpload).toBeCalledWith({
40+
Key: "static-pages/todos/terms.html",
41+
ContentType: "text/html",
42+
CacheControl: undefined
43+
});
44+
45+
expect(mockUpload).toBeCalledWith({
46+
Key: "static-pages/todos/terms/[section].html",
47+
Body: expect.any(Buffer),
48+
ContentType: "text/html",
49+
CacheControl: undefined
3950
});
4051
});
4152
});

0 commit comments

Comments
 (0)