Skip to content

Commit b3a9164

Browse files
danielcondemarinsclaughl
authored andcommitted
initial commit
1 parent 46ed431 commit b3a9164

File tree

7 files changed

+316
-0
lines changed

7 files changed

+316
-0
lines changed

packages/s3-static-assets/README.md

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const mockUpload = jest.fn();
2+
3+
export default {
4+
S3: jest.fn(() => ({
5+
upload: mockUpload
6+
}))
7+
};

packages/s3-static-assets/index.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import path from "path";
2+
import fse from "fs-extra";
3+
import mime from "mime-types";
4+
import klaw, { Item } from "klaw";
5+
import AWS from "aws-sdk";
6+
7+
type UploadStaticAssetsOptions = {
8+
bucketName: string;
9+
nextAppDir: string;
10+
};
11+
12+
const readDirectoryFiles = (directory: string): Promise<Array<Item>> => {
13+
const items: Item[] = [];
14+
return new Promise((resolve, reject) => {
15+
klaw(directory.trim())
16+
.on("data", item => items.push(item))
17+
.on("end", () => {
18+
resolve(items);
19+
})
20+
.on("error", reject);
21+
});
22+
};
23+
24+
const uploadStaticAssets = async (
25+
options: UploadStaticAssetsOptions
26+
): Promise<void> => {
27+
const { bucketName, nextAppDir } = options;
28+
29+
const s3 = new AWS.S3();
30+
31+
const dotNextDirectory = path.join(nextAppDir, ".next");
32+
33+
const BUILD_ID = fse
34+
.readFileSync(path.join(dotNextDirectory, "BUILD_ID"))
35+
.toString("utf8");
36+
37+
const buildStaticFiles = await readDirectoryFiles(
38+
path.join(dotNextDirectory, "static", BUILD_ID)
39+
);
40+
41+
const uploadTasks = buildStaticFiles
42+
.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+
);
57+
});
58+
59+
await Promise.all(uploadTasks);
60+
// read public/ folder and upload files
61+
// read static/ folder and upload files
62+
// get HTML pages from pages manifest
63+
// get JSON data files from prerender manifest
64+
};
65+
66+
export default uploadStaticAssets;

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

Lines changed: 149 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@sls-next/s3-static-assets",
3+
"version": "1.0.0",
4+
"description": "Handles upload to S3 of next.js static assets",
5+
"main": "dist/index.js",
6+
"directories": {
7+
"test": "tests"
8+
},
9+
"scripts": {
10+
"test": "echo \"Error: no test specified\" && exit 1"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git+https://github.com/danielcondemarin/serverless-next.js.git",
15+
"directory": "packages/s3-static-assets"
16+
},
17+
"keywords": [
18+
"AWS",
19+
"S3",
20+
"Next.js",
21+
"Serverless"
22+
],
23+
"author": "Daniel Conde Marin <danielconde9@gmail.com>",
24+
"license": "ISC",
25+
"bugs": {
26+
"url": "https://github.com/danielcondemarin/serverless-next.js/issues"
27+
},
28+
"homepage": "https://github.com/danielcondemarin/serverless-next.js#readme",
29+
"dependencies": {
30+
"aws-sdk": "^2.664.0",
31+
"klaw": "^3.0.0",
32+
"mime-types": "^2.1.27"
33+
},
34+
"devDependencies": {
35+
"@types/klaw": "^3.0.1",
36+
"@types/mime-types": "^2.1.0"
37+
}
38+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import stream from "stream";
2+
import fse from "fs-extra";
3+
import path from "path";
4+
import uploadStaticAssets from "../index";
5+
import { mockUpload } from "aws-sdk";
6+
7+
declare module "aws-sdk" {
8+
const mockUpload: jest.Mock;
9+
}
10+
11+
describe("Upload assets tests", () => {
12+
it("uploads any contents inside build directory specified in BUILD_ID", async () => {
13+
await uploadStaticAssets({
14+
bucketName: "test-bucket-name",
15+
nextAppDir: path.join(__dirname, "./fixtures/basic-next-app")
16+
});
17+
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";
24+
25+
expect(mockUpload).toBeCalledWith({
26+
Bucket: "test-bucket-name",
27+
Key: "_next/static/a_test_build_id/testFileOne.js",
28+
Body: mockedBodyStream,
29+
ContentType: "application/javascript",
30+
CacheControl: expectedCacheControl
31+
});
32+
33+
expect(mockUpload).toBeCalledWith({
34+
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
39+
});
40+
});
41+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"compilerOptions": {
2+
"resolveJsonModule": true,
3+
"esModuleInterop": true,
4+
"declaration": true,
5+
"target": "ES2015",
6+
"module": "CommonJS",
7+
"noImplicitAny": true,
8+
"outDir": "dist",
9+
"sourceMap": true,
10+
"strict": true,
11+
"allowJs": true
12+
},
13+
"exclude": ["node_modules"],
14+
"include": ["**/*.ts"]
15+
}

0 commit comments

Comments
 (0)