cdk-nuxt 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +2 -0
- package/index.js +8 -0
- package/lib/functions/assets-cleanup/index.d.ts +1 -0
- package/lib/functions/assets-cleanup/index.js +82 -0
- package/lib/stack/nuxt-app-stack-props.d.ts +38 -0
- package/lib/stack/nuxt-app-stack-props.js +3 -0
- package/lib/stack/nuxt-app-stack-props.ts +0 -1
- package/lib/stack/nuxt-app-static-assets.d.ts +32 -0
- package/lib/stack/nuxt-app-static-assets.js +166 -0
- package/lib/stack/server/nuxt-server-app-stack.d.ts +201 -0
- package/lib/stack/server/nuxt-server-app-stack.js +434 -0
- package/lib/stack/static/nuxt-static-app-stack.d.ts +90 -0
- package/lib/stack/static/nuxt-static-app-stack.js +182 -0
- package/package.json +12 -11
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NuxtStaticAppStack = exports.NuxtServerAppStack = void 0;
|
|
4
|
+
var nuxt_server_app_stack_1 = require("./lib/stack/server/nuxt-server-app-stack");
|
|
5
|
+
Object.defineProperty(exports, "NuxtServerAppStack", { enumerable: true, get: function () { return nuxt_server_app_stack_1.NuxtServerAppStack; } });
|
|
6
|
+
var nuxt_static_app_stack_1 = require("./lib/stack/static/nuxt-static-app-stack");
|
|
7
|
+
Object.defineProperty(exports, "NuxtStaticAppStack", { enumerable: true, get: function () { return nuxt_static_app_stack_1.NuxtStaticAppStack; } });
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxrRkFBb0c7QUFBNUYsMkhBQUEsa0JBQWtCLE9BQUE7QUFDMUIsa0ZBQW9HO0FBQTVGLDJIQUFBLGtCQUFrQixPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHtOdXh0U2VydmVyQXBwU3RhY2ssIE51eHRTZXJ2ZXJBcHBTdGFja1Byb3BzfSBmcm9tIFwiLi9saWIvc3RhY2svc2VydmVyL251eHQtc2VydmVyLWFwcC1zdGFja1wiXG5leHBvcnQge051eHRTdGF0aWNBcHBTdGFjaywgTnV4dFN0YXRpY0FwcFN0YWNrUHJvcHN9IGZyb20gXCIuL2xpYi9zdGFjay9zdGF0aWMvbnV4dC1zdGF0aWMtYXBwLXN0YWNrXCJcbiJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
4
|
+
const ONE_WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
|
|
5
|
+
exports.handler = async (event, context) => {
|
|
6
|
+
var _a;
|
|
7
|
+
console.log('Starting cleanup of static assets older than 1 week...');
|
|
8
|
+
try {
|
|
9
|
+
const client = new client_s3_1.S3Client({ region: process.env.AWS_REGION });
|
|
10
|
+
const bucketName = process.env.STATIC_ASSETS_BUCKET;
|
|
11
|
+
if (!bucketName) {
|
|
12
|
+
throw new Error("Static asset's bucket name not specified in environment!");
|
|
13
|
+
}
|
|
14
|
+
const deleteOlderThan = new Date(Date.now() - ONE_WEEK_IN_MILLISECONDS);
|
|
15
|
+
// As we don't have hundreds of deployments per week, there's no need for pagination
|
|
16
|
+
const deploymentFolders = await client.send(new client_s3_1.ListObjectsV2Command({
|
|
17
|
+
Bucket: bucketName,
|
|
18
|
+
Delimiter: '/', // Only retrieve the top level folders
|
|
19
|
+
}));
|
|
20
|
+
// The result is a list of objects containing the keys with a trailing slash
|
|
21
|
+
const folderNames = (_a = deploymentFolders.CommonPrefixes) === null || _a === void 0 ? void 0 : _a.map(folder => { var _a; return (_a = folder.Prefix) === null || _a === void 0 ? void 0 : _a.slice(0, -1); });
|
|
22
|
+
if (!folderNames) {
|
|
23
|
+
console.log('Canceled static assets cleanup as folder is empty.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// We sort the folders by their creation data and remove the latest one as this is the currently active one used in production
|
|
27
|
+
const legacyFolderNames = folderNames.sort((a, b) => {
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
const creationDateA = new Date(a);
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
const creationDateB = new Date(b);
|
|
32
|
+
return creationDateA.getTime() < creationDateB.getTime() ? -1 : 1;
|
|
33
|
+
});
|
|
34
|
+
const activeFolderName = legacyFolderNames.pop();
|
|
35
|
+
console.log(`Detected assets folder "${activeFolderName}" as current production folder...`);
|
|
36
|
+
// We want to get all outdated folders of our legacy (not productively used) folders for deletion
|
|
37
|
+
const outdatedFolderNames = legacyFolderNames.filter(folderName => {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
const creationDate = new Date(folderName);
|
|
40
|
+
return creationDate.getTime() < deleteOlderThan.getTime();
|
|
41
|
+
});
|
|
42
|
+
if (!outdatedFolderNames || outdatedFolderNames.length === 0) {
|
|
43
|
+
console.log('No outdated asset folders found.');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log(`Deleting ${outdatedFolderNames.length} outdated folders...`);
|
|
47
|
+
// Unfortunately it's not possible to delete folders recursively 🙄
|
|
48
|
+
// so we need to query all the contents in order to delete them
|
|
49
|
+
const pendingPromises = outdatedFolderNames.map(folderName => {
|
|
50
|
+
return client
|
|
51
|
+
.send(new client_s3_1.ListObjectsV2Command({
|
|
52
|
+
Bucket: bucketName,
|
|
53
|
+
Prefix: folderName,
|
|
54
|
+
}))
|
|
55
|
+
.then(outdatedAssets => {
|
|
56
|
+
var _a;
|
|
57
|
+
return client.send(new client_s3_1.DeleteObjectsCommand({
|
|
58
|
+
Bucket: bucketName,
|
|
59
|
+
Delete: {
|
|
60
|
+
Objects: (_a = outdatedAssets.Contents) === null || _a === void 0 ? void 0 : _a.map(outdatedAsset => {
|
|
61
|
+
return { Key: outdatedAsset.Key };
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
const results = await Promise.all(pendingPromises);
|
|
68
|
+
results.forEach(result => {
|
|
69
|
+
if (result.Errors && result.Errors.length) {
|
|
70
|
+
const errorMsg = 'Failed to delete outdated static assets.';
|
|
71
|
+
console.error(errorMsg, result.Errors);
|
|
72
|
+
throw new Error(errorMsg);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
console.log('Cleanup of old static assets finished.');
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('### unexpected runtime error ###', error);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGtEQUF3RjtBQUV4RixNQUFNLHdCQUF3QixHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFFekQsT0FBTyxDQUFDLE9BQU8sR0FBRyxLQUFLLEVBQUUsS0FBVSxFQUFFLE9BQVksRUFBRSxFQUFFOztJQUNqRCxPQUFPLENBQUMsR0FBRyxDQUFDLHdEQUF3RCxDQUFDLENBQUM7SUFFdEUsSUFBSTtRQUNBLE1BQU0sTUFBTSxHQUFHLElBQUksb0JBQVEsQ0FBQyxFQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUM7UUFDOUQsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQztRQUVwRCxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO1NBQy9FO1FBRUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLHdCQUF3QixDQUFDLENBQUM7UUFFeEUsb0ZBQW9GO1FBQ3BGLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUN2QyxJQUFJLGdDQUFvQixDQUFDO1lBQ3JCLE1BQU0sRUFBRSxVQUFVO1lBQ2xCLFNBQVMsRUFBRSxHQUFHLEVBQUUsc0NBQXNDO1NBQ3pELENBQUMsQ0FDTCxDQUFDO1FBRUYsNEVBQTRFO1FBQzVFLE1BQU0sV0FBVyxHQUFHLE1BQUEsaUJBQWlCLENBQUMsY0FBYywwQ0FBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsV0FBQyxPQUFBLE1BQUEsTUFBTSxDQUFDLE1BQU0sMENBQUUsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FB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LENBQUMsR0FBRyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7S0FDekQ7SUFBQyxPQUFPLEtBQUssRUFBRTtRQUNaLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLEVBQUUsS0FBSyxDQUFDLENBQUM7S0FDNUQ7QUFDTCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0RlbGV0ZU9iamVjdHNDb21tYW5kLCBMaXN0T2JqZWN0c1YyQ29tbWFuZCwgUzNDbGllbnR9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIjtcblxuY29uc3QgT05FX1dFRUtfSU5fTUlMTElTRUNPTkRTID0gMTAwMCAqIDYwICogNjAgKiAyNCAqIDc7XG5cbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIChldmVudDogYW55LCBjb250ZXh0OiBhbnkpID0+IHtcbiAgICBjb25zb2xlLmxvZygnU3RhcnRpbmcgY2xlYW51cCBvZiBzdGF0aWMgYXNzZXRzIG9sZGVyIHRoYW4gMSB3ZWVrLi4uJyk7XG5cbiAgICB0cnkge1xuICAgICAgICBjb25zdCBjbGllbnQgPSBuZXcgUzNDbGllbnQoe3JlZ2lvbjogcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTn0pO1xuICAgICAgICBjb25zdCBidWNrZXROYW1lID0gcHJvY2Vzcy5lbnYuU1RBVElDX0FTU0VUU19CVUNLRVQ7XG5cbiAgICAgICAgaWYgKCFidWNrZXROYW1lKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTdGF0aWMgYXNzZXQncyBidWNrZXQgbmFtZSBub3Qgc3BlY2lmaWVkIGluIGVudmlyb25tZW50IVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRlbGV0ZU9sZGVyVGhhbiA9IG5ldyBEYXRlKERhdGUubm93KCkgLSBPTkVfV0VFS19JTl9NSUxMSVNFQ09ORFMpO1xuXG4gICAgICAgIC8vIEFzIHdlIGRvbid0IGhhdmUgaHVuZHJlZHMgb2YgZGVwbG95bWVudHMgcGVyIHdlZWssIHRoZXJlJ3Mgbm8gbmVlZCBmb3IgcGFnaW5hdGlvblxuICAgICAgICBjb25zdCBkZXBsb3ltZW50Rm9sZGVycyA9IGF3YWl0IGNsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IExpc3RPYmplY3RzVjJDb21tYW5kKHtcbiAgICAgICAgICAgICAgICBCdWNrZXQ6IGJ1Y2tldE5hbWUsXG4gICAgICAgICAgICAgICAgRGVsaW1pdGVyOiAnLycsIC8vIE9ubHkgcmV0cmlldmUgdGhlIHRvcCBsZXZlbCBmb2xkZXJzXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFRoZSByZXN1bHQgaXMgYSBsaXN0IG9mIG9iamVjdHMgY29udGFpbmluZyB0aGUga2V5cyB3aXRoIGEgdHJhaWxpbmcgc2xhc2hcbiAgICAgICAgY29uc3QgZm9sZGVyTmFtZXMgPSBkZXBsb3ltZW50Rm9sZGVycy5Db21tb25QcmVmaXhlcz8ubWFwKGZvbGRlciA9PiBmb2xkZXIuUHJlZml4Py5zbGljZSgwLCAtMSkpXG4gICAgICAgIGlmICghZm9sZGVyTmFtZXMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdDYW5jZWxlZCBzdGF0aWMgYXNzZXRzIGNsZWFudXAgYXMgZm9sZGVyIGlzIGVtcHR5LicpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gV2Ugc29ydCB0aGUgZm9sZGVycyBieSB0aGVpciBjcmVhdGlvbiBkYXRhIGFuZCByZW1vdmUgdGhlIGxhdGVzdCBvbmUgYXMgdGhpcyBpcyB0aGUgY3VycmVudGx5IGFjdGl2ZSBvbmUgdXNlZCBpbiBwcm9kdWN0aW9uXG4gICAgICAgIGNvbnN0IGxlZ2FjeUZvbGRlck5hbWVzID0gZm9sZGVyTmFtZXMuc29ydCgoYSxiKSA9PiB7XG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICBjb25zdCBjcmVhdGlvbkRhdGVBID0gbmV3IERhdGUoYSk7XG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICBjb25zdCBjcmVhdGlvbkRhdGVCID0gbmV3IERhdGUoYik7XG5cbiAgICAgICAgICAgIHJldHVybiBjcmVhdGlvbkRhdGVBLmdldFRpbWUoKSA8IGNyZWF0aW9uRGF0ZUIuZ2V0VGltZSgpID8gLTEgOiAxO1xuICAgICAgICB9KVxuICAgICAgICBjb25zdCBhY3RpdmVGb2xkZXJOYW1lID0gbGVnYWN5Rm9sZGVyTmFtZXMucG9wKCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBEZXRlY3RlZCBhc3NldHMgZm9sZGVyIFwiJHthY3RpdmVGb2xkZXJOYW1lfVwiIGFzIGN1cnJlbnQgcHJvZHVjdGlvbiBmb2xkZXIuLi5gKTtcblxuICAgICAgICAvLyBXZSB3YW50IHRvIGdldCBhbGwgb3V0ZGF0ZWQgZm9sZGVycyBvZiBvdXIgbGVnYWN5IChub3QgcHJvZHVjdGl2ZWx5IHVzZWQpIGZvbGRlcnMgZm9yIGRlbGV0aW9uXG4gICAgICAgIGNvbnN0IG91dGRhdGVkRm9sZGVyTmFtZXMgPSBsZWdhY3lGb2xkZXJOYW1lcy5maWx0ZXIoZm9sZGVyTmFtZSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgICAgIGNvbnN0IGNyZWF0aW9uRGF0ZSA9IG5ldyBEYXRlKGZvbGRlck5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybiBjcmVhdGlvbkRhdGUuZ2V0VGltZSgpIDwgZGVsZXRlT2xkZXJUaGFuLmdldFRpbWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIW91dGRhdGVkRm9sZGVyTmFtZXMgfHwgb3V0ZGF0ZWRGb2xkZXJOYW1lcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdObyBvdXRkYXRlZCBhc3NldCBmb2xkZXJzIGZvdW5kLicpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYERlbGV0aW5nICR7b3V0ZGF0ZWRGb2xkZXJOYW1lcy5sZW5ndGh9IG91dGRhdGVkIGZvbGRlcnMuLi5gKTtcblxuICAgICAgICAgICAgLy8gVW5mb3J0dW5hdGVseSBpdCdzIG5vdCBwb3NzaWJsZSB0byBkZWxldGUgZm9sZGVycyByZWN1cnNpdmVseSDwn5mEXG4gICAgICAgICAgICAvLyBzbyB3ZSBuZWVkIHRvIHF1ZXJ5IGFsbCB0aGUgY29udGVudHMgaW4gb3JkZXIgdG8gZGVsZXRlIHRoZW1cbiAgICAgICAgICAgIGNvbnN0IHBlbmRpbmdQcm9taXNlcyA9IG91dGRhdGVkRm9sZGVyTmFtZXMubWFwKGZvbGRlck5hbWUgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBjbGllbnRcbiAgICAgICAgICAgICAgICAgICAgLnNlbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgTGlzdE9iamVjdHNWMkNvbW1hbmQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcmVmaXg6IGZvbGRlck5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKG91dGRhdGVkQXNzZXRzID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjbGllbnQuc2VuZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgRGVsZXRlT2JqZWN0c0NvbW1hbmQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdWNrZXQ6IGJ1Y2tldE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbGV0ZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2JqZWN0czogb3V0ZGF0ZWRBc3NldHMuQ29udGVudHM/Lm1hcChvdXRkYXRlZEFzc2V0ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge0tleTogb3V0ZGF0ZWRBc3NldC5LZXl9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChwZW5kaW5nUHJvbWlzZXMpO1xuICAgICAgICAgICAgcmVzdWx0cy5mb3JFYWNoKHJlc3VsdCA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5FcnJvcnMgJiYgcmVzdWx0LkVycm9ycy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JNc2cgPSAnRmFpbGVkIHRvIGRlbGV0ZSBvdXRkYXRlZCBzdGF0aWMgYXNzZXRzLic7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JNc2csIHJlc3VsdC5FcnJvcnMpO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JNc2cpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZS5sb2coJ0NsZWFudXAgb2Ygb2xkIHN0YXRpYyBhc3NldHMgZmluaXNoZWQuJyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignIyMjIHVuZXhwZWN0ZWQgcnVudGltZSBlcnJvciAjIyMnLCBlcnJvcik7XG4gICAgfVxufTsiXX0=
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StackProps } from "aws-cdk-lib";
|
|
2
|
+
/**
|
|
3
|
+
* Defines the common props required to deploy Nuxt apps on AWS.
|
|
4
|
+
*/
|
|
5
|
+
export interface NuxtAppStackProps extends StackProps {
|
|
6
|
+
/**
|
|
7
|
+
* A string identifier for the project the Nuxt app is part of.
|
|
8
|
+
* A project might have multiple different services.
|
|
9
|
+
*/
|
|
10
|
+
readonly project: string;
|
|
11
|
+
/**
|
|
12
|
+
* A string identifier for the project's service the Nuxt app is created for.
|
|
13
|
+
* This can be seen as the name of the Nuxt app.
|
|
14
|
+
*/
|
|
15
|
+
readonly service: string;
|
|
16
|
+
/**
|
|
17
|
+
* A string to identify the environment of the Nuxt app. This enables us
|
|
18
|
+
* to deploy multiple different environments of the same Nuxt app, e.g., production and development.
|
|
19
|
+
*/
|
|
20
|
+
readonly environment: string;
|
|
21
|
+
/**
|
|
22
|
+
* The domain (without the protocol) at which the Nuxt app shall be publicly available.
|
|
23
|
+
* A DNS record will be automatically created in Route53 for the domain.
|
|
24
|
+
* This also supports subdomains.
|
|
25
|
+
* Examples: "example.com", "sub.example.com"
|
|
26
|
+
*/
|
|
27
|
+
readonly domain: string;
|
|
28
|
+
/**
|
|
29
|
+
* The id of the hosted zone to create a DNS record for the specified domain.
|
|
30
|
+
*/
|
|
31
|
+
readonly hostedZoneId: string;
|
|
32
|
+
/**
|
|
33
|
+
* The ARN of the certificate to use on CloudFront for the Nuxt app to make it accessible via HTTPS.
|
|
34
|
+
* The certificate must be issued for the specified domain in us-east-1 (global) regardless of the
|
|
35
|
+
* region specified via 'env.region' as CloudFront only works globally.
|
|
36
|
+
*/
|
|
37
|
+
readonly globalTlsCertificateArn: string;
|
|
38
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1hcHAtc3RhY2stcHJvcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJudXh0LWFwcC1zdGFjay1wcm9wcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtTdGFja1Byb3BzfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcblxuLyoqXG4gKiBEZWZpbmVzIHRoZSBjb21tb24gcHJvcHMgcmVxdWlyZWQgdG8gZGVwbG95IE51eHQgYXBwcyBvbiBBV1MuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTnV4dEFwcFN0YWNrUHJvcHMgZXh0ZW5kcyBTdGFja1Byb3BzIHtcblxuICAgIC8qKlxuICAgICAqIEEgc3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBwcm9qZWN0IHRoZSBOdXh0IGFwcCBpcyBwYXJ0IG9mLlxuICAgICAqIEEgcHJvamVjdCBtaWdodCBoYXZlIG11bHRpcGxlIGRpZmZlcmVudCBzZXJ2aWNlcy5cbiAgICAgKi9cbiAgICByZWFkb25seSBwcm9qZWN0OiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBBIHN0cmluZyBpZGVudGlmaWVyIGZvciB0aGUgcHJvamVjdCdzIHNlcnZpY2UgdGhlIE51eHQgYXBwIGlzIGNyZWF0ZWQgZm9yLlxuICAgICAqIFRoaXMgY2FuIGJlIHNlZW4gYXMgdGhlIG5hbWUgb2YgdGhlIE51eHQgYXBwLlxuICAgICAqL1xuICAgIHJlYWRvbmx5IHNlcnZpY2U6IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIEEgc3RyaW5nIHRvIGlkZW50aWZ5IHRoZSBlbnZpcm9ubWVudCBvZiB0aGUgTnV4dCBhcHAuIFRoaXMgZW5hYmxlcyB1c1xuICAgICAqIHRvIGRlcGxveSBtdWx0aXBsZSBkaWZmZXJlbnQgZW52aXJvbm1lbnRzIG9mIHRoZSBzYW1lIE51eHQgYXBwLCBlLmcuLCBwcm9kdWN0aW9uIGFuZCBkZXZlbG9wbWVudC5cbiAgICAgKi9cbiAgICByZWFkb25seSBlbnZpcm9ubWVudDogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGRvbWFpbiAod2l0aG91dCB0aGUgcHJvdG9jb2wpIGF0IHdoaWNoIHRoZSBOdXh0IGFwcCBzaGFsbCBiZSBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAgICogQSBETlMgcmVjb3JkIHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGluIFJvdXRlNTMgZm9yIHRoZSBkb21haW4uXG4gICAgICogVGhpcyBhbHNvIHN1cHBvcnRzIHN1YmRvbWFpbnMuXG4gICAgICogRXhhbXBsZXM6IFwiZXhhbXBsZS5jb21cIiwgXCJzdWIuZXhhbXBsZS5jb21cIlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGRvbWFpbjogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGlkIG9mIHRoZSBob3N0ZWQgem9uZSB0byBjcmVhdGUgYSBETlMgcmVjb3JkIGZvciB0aGUgc3BlY2lmaWVkIGRvbWFpbi5cbiAgICAgKi9cbiAgICByZWFkb25seSBob3N0ZWRab25lSWQ6IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIFRoZSBBUk4gb2YgdGhlIGNlcnRpZmljYXRlIHRvIHVzZSBvbiBDbG91ZEZyb250IGZvciB0aGUgTnV4dCBhcHAgdG8gbWFrZSBpdCBhY2Nlc3NpYmxlIHZpYSBIVFRQUy5cbiAgICAgKiBUaGUgY2VydGlmaWNhdGUgbXVzdCBiZSBpc3N1ZWQgZm9yIHRoZSBzcGVjaWZpZWQgZG9tYWluIGluIHVzLWVhc3QtMSAoZ2xvYmFsKSByZWdhcmRsZXNzIG9mIHRoZVxuICAgICAqIHJlZ2lvbiBzcGVjaWZpZWQgdmlhICdlbnYucmVnaW9uJyBhcyBDbG91ZEZyb250IG9ubHkgd29ya3MgZ2xvYmFsbHkuXG4gICAgICovXG4gICAgcmVhZG9ubHkgZ2xvYmFsVGxzQ2VydGlmaWNhdGVBcm46IHN0cmluZztcblxufSJdfQ==
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CacheControl } from "aws-cdk-lib/aws-s3-deployment";
|
|
2
|
+
export interface StaticAssetConfig {
|
|
3
|
+
/**
|
|
4
|
+
* The file pattern for the incoming requests that should be forwarded to the target path in the static assets S3 bucket
|
|
5
|
+
* with the appropriate cache and content settings defined in the same object.
|
|
6
|
+
*/
|
|
7
|
+
pattern: string;
|
|
8
|
+
/**
|
|
9
|
+
* The local directory to upload the files from.
|
|
10
|
+
*/
|
|
11
|
+
source: string;
|
|
12
|
+
/**
|
|
13
|
+
* The remote path at which to make the uploaded files from source accessible.
|
|
14
|
+
*/
|
|
15
|
+
target: string;
|
|
16
|
+
/**
|
|
17
|
+
* The content type to set for the files in the source folder when uploading them to the target.
|
|
18
|
+
*/
|
|
19
|
+
contentType: string;
|
|
20
|
+
/**
|
|
21
|
+
* The cache settings to use for the uploaded source files when accessing them on the target path with the specified pattern.
|
|
22
|
+
*/
|
|
23
|
+
cacheControl?: CacheControl[];
|
|
24
|
+
/**
|
|
25
|
+
* Whether to invalidate the files matching the config's pattern in the distribution's edge caches after the files are uploaded to the destination bucket.
|
|
26
|
+
*/
|
|
27
|
+
invalidateOnChange?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves the static assets of the Nuxt app that shall be publicly available.
|
|
31
|
+
*/
|
|
32
|
+
export declare const getNuxtAppStaticAssetConfigs: () => StaticAssetConfig[];
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getNuxtAppStaticAssetConfigs = void 0;
|
|
4
|
+
const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
/**
|
|
7
|
+
* Retrieves the custom static assets of the Nuxt app that shall be publicly available.
|
|
8
|
+
*/
|
|
9
|
+
const getNuxtAppCustomAssetConfigs = () => {
|
|
10
|
+
// The custom assets of server Nuxt apps are located in the src 'static' folder
|
|
11
|
+
// The custom assets of static Nuxt apps are located in the build files 'dist' folder
|
|
12
|
+
const customAssetsSourcePath = `./.output/public`;
|
|
13
|
+
const customAssetsTargetPath = '/';
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
pattern: '*.txt',
|
|
17
|
+
source: customAssetsSourcePath,
|
|
18
|
+
target: customAssetsTargetPath,
|
|
19
|
+
contentType: 'text/plain; charset=UTF-8',
|
|
20
|
+
cacheControl: [aws_s3_deployment_1.CacheControl.setPublic(), aws_s3_deployment_1.CacheControl.maxAge(aws_cdk_lib_1.Duration.days(1))],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pattern: '*.xml',
|
|
24
|
+
source: customAssetsSourcePath,
|
|
25
|
+
target: customAssetsTargetPath,
|
|
26
|
+
contentType: 'text/xml; charset=UTF-8',
|
|
27
|
+
cacheControl: [aws_s3_deployment_1.CacheControl.setPublic(), aws_s3_deployment_1.CacheControl.maxAge(aws_cdk_lib_1.Duration.days(1))],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: '.well-known/*',
|
|
31
|
+
source: customAssetsSourcePath,
|
|
32
|
+
target: customAssetsTargetPath,
|
|
33
|
+
contentType: 'application/json; charset=UTF-8',
|
|
34
|
+
cacheControl: [aws_s3_deployment_1.CacheControl.setPublic(), aws_s3_deployment_1.CacheControl.maxAge(aws_cdk_lib_1.Duration.days(1))],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
pattern: '*.ico',
|
|
38
|
+
source: customAssetsSourcePath,
|
|
39
|
+
target: customAssetsTargetPath,
|
|
40
|
+
contentType: 'image/x-icon',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: '*.png',
|
|
44
|
+
source: customAssetsSourcePath,
|
|
45
|
+
target: customAssetsTargetPath,
|
|
46
|
+
contentType: 'image/png',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
pattern: '*.jpg',
|
|
50
|
+
source: customAssetsSourcePath,
|
|
51
|
+
target: customAssetsTargetPath,
|
|
52
|
+
contentType: 'image/jpg',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: '*.svg',
|
|
56
|
+
source: customAssetsSourcePath,
|
|
57
|
+
target: customAssetsTargetPath,
|
|
58
|
+
contentType: 'image/svg+xml',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
pattern: '*.js',
|
|
62
|
+
source: customAssetsSourcePath,
|
|
63
|
+
target: customAssetsTargetPath,
|
|
64
|
+
contentType: 'application/javascript; charset=UTF-8',
|
|
65
|
+
// The js files in the custom static directory are usually not versioned
|
|
66
|
+
// whereby we want to prevent any caching issues when updating them -> cache for only 2 days
|
|
67
|
+
cacheControl: [aws_s3_deployment_1.CacheControl.setPublic(), aws_s3_deployment_1.CacheControl.maxAge(aws_cdk_lib_1.Duration.days(2))],
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves the static assets of the Nuxt app that are generated by the build of the app.
|
|
73
|
+
*/
|
|
74
|
+
const getNuxtAppBuildAssetConfigs = () => {
|
|
75
|
+
// The build assets required for CSR that are generated by 'nuxt build'
|
|
76
|
+
const buildAssetsSourcePath = './.output/public/_nuxt';
|
|
77
|
+
const buildAssetsTargetPath = ('/_nuxt/'); // Must match 'build.publicPath' in nuxt.config.js
|
|
78
|
+
return [
|
|
79
|
+
// Build Assets
|
|
80
|
+
{
|
|
81
|
+
pattern: '*.js',
|
|
82
|
+
target: buildAssetsTargetPath,
|
|
83
|
+
source: buildAssetsSourcePath,
|
|
84
|
+
contentType: 'application/javascript; charset=UTF-8',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
pattern: '*.js.map',
|
|
88
|
+
target: buildAssetsTargetPath,
|
|
89
|
+
source: buildAssetsSourcePath,
|
|
90
|
+
contentType: 'application/json; charset=UTF-8',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
pattern: '*.css',
|
|
94
|
+
target: buildAssetsTargetPath,
|
|
95
|
+
source: buildAssetsSourcePath,
|
|
96
|
+
contentType: 'text/css; charset=UTF-8',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
pattern: '*.html',
|
|
100
|
+
target: buildAssetsTargetPath,
|
|
101
|
+
source: buildAssetsSourcePath,
|
|
102
|
+
contentType: 'text/html; charset=UTF-8',
|
|
103
|
+
// We do not want to cache html files on the browser as we want to be able to publish new changes quickly
|
|
104
|
+
// However, we do cache the html files on CloudFront for a performance boost and invalidate the cache on every deployment
|
|
105
|
+
cacheControl: [aws_s3_deployment_1.CacheControl.setPublic(), aws_s3_deployment_1.CacheControl.sMaxAge(aws_cdk_lib_1.Duration.days(7))],
|
|
106
|
+
invalidateOnChange: true
|
|
107
|
+
},
|
|
108
|
+
// Manifest created by PWA module
|
|
109
|
+
{
|
|
110
|
+
pattern: 'manifest.*.json',
|
|
111
|
+
target: buildAssetsTargetPath,
|
|
112
|
+
source: buildAssetsSourcePath,
|
|
113
|
+
contentType: 'application/json; charset=UTF-8'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
pattern: '*.png',
|
|
117
|
+
target: buildAssetsTargetPath,
|
|
118
|
+
source: buildAssetsSourcePath,
|
|
119
|
+
contentType: 'image/png',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
pattern: '*.jpg',
|
|
123
|
+
target: buildAssetsTargetPath,
|
|
124
|
+
source: buildAssetsSourcePath,
|
|
125
|
+
contentType: 'image/jpg',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
pattern: '*.svg',
|
|
129
|
+
target: buildAssetsTargetPath,
|
|
130
|
+
source: buildAssetsSourcePath,
|
|
131
|
+
contentType: 'image/svg+xml',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
pattern: '*.eot',
|
|
135
|
+
target: buildAssetsTargetPath,
|
|
136
|
+
source: buildAssetsSourcePath,
|
|
137
|
+
contentType: 'application/vnd.ms-fontobject',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
pattern: '*.ttf',
|
|
141
|
+
target: buildAssetsTargetPath,
|
|
142
|
+
source: buildAssetsSourcePath,
|
|
143
|
+
contentType: 'application/font-sfnt',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
pattern: '*.woff',
|
|
147
|
+
target: buildAssetsTargetPath,
|
|
148
|
+
source: buildAssetsSourcePath,
|
|
149
|
+
contentType: 'font/woff',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
pattern: '*.woff2',
|
|
153
|
+
target: buildAssetsTargetPath,
|
|
154
|
+
source: buildAssetsSourcePath,
|
|
155
|
+
contentType: 'font/woff2',
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Retrieves the static assets of the Nuxt app that shall be publicly available.
|
|
161
|
+
*/
|
|
162
|
+
const getNuxtAppStaticAssetConfigs = () => {
|
|
163
|
+
return [...getNuxtAppBuildAssetConfigs(), ...getNuxtAppCustomAssetConfigs()];
|
|
164
|
+
};
|
|
165
|
+
exports.getNuxtAppStaticAssetConfigs = getNuxtAppStaticAssetConfigs;
|
|
166
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1hcHAtc3RhdGljLWFzc2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm51eHQtYXBwLXN0YXRpYy1hc3NldHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBQTJEO0FBQzNELDZDQUFxQztBQW1DckM7O0dBRUc7QUFDSCxNQUFNLDRCQUE0QixHQUFHLEdBQXdCLEVBQUU7SUFFM0QsK0VBQStFO0lBQy9FLHFGQUFxRjtJQUNyRixNQUFNLHNCQUFzQixHQUFHLGtCQUFrQixDQUFDO0lBQ2xELE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDO0lBRW5DLE9BQU87UUFDSDtZQUNJLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE1BQU0sRUFBRSxzQkFBc0I7WUFDOUIsTUFBTSxFQUFFLHNCQUFzQjtZQUM5QixXQUFXLEVBQUUsMkJBQTJCO1lBQ3hDLFlBQVksRUFBRSxDQUFDLGdDQUFZLENBQUMsU0FBUyxFQUFFLEVBQUUsZ0NBQVksQ0FBQyxNQUFNLENBQUMsc0JBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNsRjtRQUNEO1lBQ0ksT0FBTyxFQUFFLE9BQU87WUFDaEIsTUFBTSxFQUFFLHNCQUFzQjtZQUM5QixNQUFNLEVBQUUsc0JBQXNCO1lBQzlCLFdBQVcsRUFBRSx5QkFBeUI7WUFDdEMsWUFBWSxFQUFFLENBQUMsZ0NBQVksQ0FBQyxTQUFTLEVBQUUsRUFBRSxnQ0FBWSxDQUFDLE1BQU0sQ0FBQyxzQkFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2xGO1FBQ0Q7WUFDSSxPQUFPLEVBQUUsZUFBZTtZQUN4QixNQUFNLEVBQUUsc0JBQXNCO1lBQzlCLE1BQU0sRUFBRSxzQkFBc0I7WUFDOUIsV0FBVyxFQUFFLGlDQUFpQztZQUM5QyxZQUFZLEVBQUUsQ0FBQyxnQ0FBWSxDQUFDLFNBQVMsRUFBRSxFQUFFLGdDQUFZLENBQUMsTUFBTSxDQUFDLHNCQUFRLENBQUMsSUFB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VyxFQUFFLGVBQWU7U0FDL0I7UUFDRDtZQUNJLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE1BQU0sRUFBRSxxQkFBcUI7WUFDN0IsTUFBTSxFQUFFLHFCQUFxQjtZQUM3QixXQUFXLEVBQUUsK0JBQStCO1NBQy9DO1FBQ0Q7WUFDSSxPQUFPLEVBQUUsT0FBTztZQUNoQixNQUFNLEVBQUUscUJBQXFCO1lBQzdCLE1BQU0sRUFBRSxxQkFBcUI7WUFDN0IsV0FBVyxFQUFFLHVCQUF1QjtTQUN2QztRQUNEO1lBQ0ksT0FBTyxFQUFFLFFBQVE7WUFDakIsTUFBTSxFQUFFLHFCQUFxQjtZQUM3QixNQUFNLEVBQUUscUJBQXFCO1lBQzdCLFdBQVcsRUFBRSxXQUFXO1NBQzNCO1FBQ0Q7WUFDSSxPQUFPLEVBQUUsU0FBUztZQUNsQixNQUFNLEVBQUUscUJBQXFCO1lBQzdCLE1BQU0sRUFBRSxxQkFBcUI7WUFDN0IsV0FBVyxFQUFFLFlBQVk7U0FDNUI7S0FDSixDQUFBO0FBQ0wsQ0FBQyxDQUFDO0FBRUY7O0dBRUc7QUFDSSxNQUFNLDRCQUE0QixHQUFHLEdBQXdCLEVBQUU7SUFDbEUsT0FBTyxDQUFDLEdBQUcsMkJBQTJCLEVBQUUsRUFBRSxHQUFHLDRCQUE0QixFQUFFLENBQUMsQ0FBQztBQUNqRixDQUFDLENBQUM7QUFGVyxRQUFBLDRCQUE0QixnQ0FFdkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0NhY2hlQ29udHJvbH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zMy1kZXBsb3ltZW50XCI7XG5pbXBvcnQge0R1cmF0aW9ufSBmcm9tIFwiYXdzLWNkay1saWJcIjtcblxuZXhwb3J0IGludGVyZmFjZSBTdGF0aWNBc3NldENvbmZpZyB7XG4gICAgLyoqXG4gICAgICogVGhlIGZpbGUgcGF0dGVybiBmb3IgdGhlIGluY29taW5nIHJlcXVlc3RzIHRoYXQgc2hvdWxkIGJlIGZvcndhcmRlZCB0byB0aGUgdGFyZ2V0IHBhdGggaW4gdGhlIHN0YXRpYyBhc3NldHMgUzMgYnVja2V0XG4gICAgICogd2l0aCB0aGUgYXBwcm9wcmlhdGUgY2FjaGUgYW5kIGNvbnRlbnQgc2V0dGluZ3MgZGVmaW5lZCBpbiB0aGUgc2FtZSBvYmplY3QuXG4gICAgICovXG4gICAgcGF0dGVybjogc3RyaW5nLFxuXG4gICAgLyoqXG4gICAgICogVGhlIGxvY2FsIGRpcmVjdG9yeSB0byB1cGxvYWQgdGhlIGZpbGVzIGZyb20uXG4gICAgICovXG4gICAgc291cmNlOiBzdHJpbmcsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmVtb3RlIHBhdGggYXQgd2hpY2ggdG8gbWFrZSB0aGUgdXBsb2FkZWQgZmlsZXMgZnJvbSBzb3VyY2UgYWNjZXNzaWJsZS5cbiAgICAgKi9cbiAgICB0YXJnZXQ6IHN0cmluZyxcblxuICAgIC8qKlxuICAgICAqIFRoZSBjb250ZW50IHR5cGUgdG8gc2V0IGZvciB0aGUgZmlsZXMgaW4gdGhlIHNvdXJjZSBmb2xkZXIgd2hlbiB1cGxvYWRpbmcgdGhlbSB0byB0aGUgdGFyZ2V0LlxuICAgICAqL1xuICAgIGNvbnRlbnRUeXBlOiBzdHJpbmcsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2FjaGUgc2V0dGluZ3MgdG8gdXNlIGZvciB0aGUgdXBsb2FkZWQgc291cmNlIGZpbGVzIHdoZW4gYWNjZXNzaW5nIHRoZW0gb24gdGhlIHRhcmdldCBwYXRoIHdpdGggdGhlIHNwZWNpZmllZCBwYXR0ZXJuLlxuICAgICAqL1xuICAgIGNhY2hlQ29udHJvbD86IENhY2hlQ29udHJvbFtdLFxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0byBpbnZhbGlkYXRlIHRoZSBmaWxlcyBtYXRjaGluZyB0aGUgY29uZmlnJ3MgcGF0dGVybiBpbiB0aGUgZGlzdHJpYnV0aW9uJ3MgZWRnZSBjYWNoZXMgYWZ0ZXIgdGhlIGZpbGVzIGFyZSB1cGxvYWRlZCB0byB0aGUgZGVzdGluYXRpb24gYnVja2V0LlxuICAgICAqL1xuICAgIGludmFsaWRhdGVPbkNoYW5nZT86IGJvb2xlYW47XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjdXN0b20gc3RhdGljIGFzc2V0cyBvZiB0aGUgTnV4dCBhcHAgdGhhdCBzaGFsbCBiZSBwdWJsaWNseSBhdmFpbGFibGUuXG4gKi9cbmNvbnN0IGdldE51eHRBcHBDdXN0b21Bc3NldENvbmZpZ3MgPSAoKTogU3RhdGljQXNzZXRDb25maWdbXSA9PiB7XG5cbiAgICAvLyBUaGUgY3VzdG9tIGFzc2V0cyBvZiBzZXJ2ZXIgTnV4dCBhcHBzIGFyZSBsb2NhdGVkIGluIHRoZSBzcmMgJ3N0YXRpYycgZm9sZGVyXG4gICAgLy8gVGhlIGN1c3RvbSBhc3NldHMgb2Ygc3RhdGljIE51eHQgYXBwcyBhcmUgbG9jYXRlZCBpbiB0aGUgYnVpbGQgZmlsZXMgJ2Rpc3QnIGZvbGRlclxuICAgIGNvbnN0IGN1c3RvbUFzc2V0c1NvdXJjZVBhdGggPSBgLi8ub3V0cHV0L3B1YmxpY2A7XG4gICAgY29uc3QgY3VzdG9tQXNzZXRzVGFyZ2V0UGF0aCA9ICcvJztcblxuICAgIHJldHVybiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLnR4dCcsIC8vIEUuZy4sIHJvYm90cy50eHQsIGFkcy50eHQsIC4uLlxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluOyBjaGFyc2V0PVVURi04JyxcbiAgICAgICAgICAgIGNhY2hlQ29udHJvbDogW0NhY2hlQ29udHJvbC5zZXRQdWJsaWMoKSwgQ2FjaGVDb250cm9sLm1heEFnZShEdXJhdGlvbi5kYXlzKDEpKV0sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLnhtbCcsIC8vIEUuZy4sIHNpdGVtYXAueG1sIC4uLlxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3htbDsgY2hhcnNldD1VVEYtOCcsXG4gICAgICAgICAgICBjYWNoZUNvbnRyb2w6IFtDYWNoZUNvbnRyb2wuc2V0UHVibGljKCksIENhY2hlQ29udHJvbC5tYXhBZ2UoRHVyYXRpb24uZGF5cygxKSldLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnLndlbGwta25vd24vKicsIC8vIEZpbGVzIGZvciBuYXRpdmUgYXBwIGxpbmtzXG4gICAgICAgICAgICBzb3VyY2U6IGN1c3RvbUFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICB0YXJnZXQ6IGN1c3RvbUFzc2V0c1RhcmdldFBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLTgnLFxuICAgICAgICAgICAgY2FjaGVDb250cm9sOiBbQ2FjaGVDb250cm9sLnNldFB1YmxpYygpLCBDYWNoZUNvbnRyb2wubWF4QWdlKER1cmF0aW9uLmRheXMoMSkpXSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcGF0dGVybjogJyouaWNvJywgLy8gRmF2aWNvblxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdpbWFnZS94LWljb24nLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5wbmcnLFxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdpbWFnZS9wbmcnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5qcGcnLFxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdpbWFnZS9qcGcnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5zdmcnLFxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdpbWFnZS9zdmcreG1sJyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcGF0dGVybjogJyouanMnLFxuICAgICAgICAgICAgc291cmNlOiBjdXN0b21Bc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgdGFyZ2V0OiBjdXN0b21Bc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0OyBjaGFyc2V0PVVURi04JyxcbiAgICAgICAgICAgIC8vIFRoZSBqcyBmaWxlcyBpbiB0aGUgY3VzdG9tIHN0YXRpYyBkaXJlY3RvcnkgYXJlIHVzdWFsbHkgbm90IHZlcnNpb25lZFxuICAgICAgICAgICAgLy8gd2hlcmVieSB3ZSB3YW50IHRvIHByZXZlbnQgYW55IGNhY2hpbmcgaXNzdWVzIHdoZW4gdXBkYXRpbmcgdGhlbSAtPiBjYWNoZSBmb3Igb25seSAyIGRheXNcbiAgICAgICAgICAgIGNhY2hlQ29udHJvbDogW0NhY2hlQ29udHJvbC5zZXRQdWJsaWMoKSwgQ2FjaGVDb250cm9sLm1heEFnZShEdXJhdGlvbi5kYXlzKDIpKV0sXG4gICAgICAgIH1cbiAgICBdO1xufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIHN0YXRpYyBhc3NldHMgb2YgdGhlIE51eHQgYXBwIHRoYXQgYXJlIGdlbmVyYXRlZCBieSB0aGUgYnVpbGQgb2YgdGhlIGFwcC5cbiAqL1xuY29uc3QgZ2V0TnV4dEFwcEJ1aWxkQXNzZXRDb25maWdzID0gKCk6IFN0YXRpY0Fzc2V0Q29uZmlnW10gPT4ge1xuXG4gICAgLy8gVGhlIGJ1aWxkIGFzc2V0cyByZXF1aXJlZCBmb3IgQ1NSIHRoYXQgYXJlIGdlbmVyYXRlZCBieSAnbnV4dCBidWlsZCdcbiAgICBjb25zdCBidWlsZEFzc2V0c1NvdXJjZVBhdGggPSAnLi8ub3V0cHV0L3B1YmxpYy9fbnV4dCc7XG4gICAgY29uc3QgYnVpbGRBc3NldHNUYXJnZXRQYXRoID0gKCcvX251eHQvJyk7IC8vIE11c3QgbWF0Y2ggJ2J1aWxkLnB1YmxpY1BhdGgnIGluIG51eHQuY29uZmlnLmpzXG5cbiAgICByZXR1cm4gW1xuXG4gICAgICAgIC8vIEJ1aWxkIEFzc2V0c1xuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5qcycsXG4gICAgICAgICAgICB0YXJnZXQ6IGJ1aWxkQXNzZXRzVGFyZ2V0UGF0aCxcbiAgICAgICAgICAgIHNvdXJjZTogYnVpbGRBc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0OyBjaGFyc2V0PVVURi04JyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcGF0dGVybjogJyouanMubWFwJyxcbiAgICAgICAgICAgIHRhcmdldDogYnVpbGRBc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgc291cmNlOiBidWlsZEFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLTgnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5jc3MnLFxuICAgICAgICAgICAgdGFyZ2V0OiBidWlsZEFzc2V0c1RhcmdldFBhdGgsXG4gICAgICAgICAgICBzb3VyY2U6IGJ1aWxkQXNzZXRzU291cmNlUGF0aCxcbiAgICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9jc3M7IGNoYXJzZXQ9VVRGLTgnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5odG1sJyxcbiAgICAgICAgICAgIHRhcmdldDogYnVpbGRBc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgc291cmNlOiBidWlsZEFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvaHRtbDsgY2hhcnNldD1VVEYtOCcsXG4gICAgICAgICAgICAvLyBXZSBkbyBub3Qgd2FudCB0byBjYWNoZSBodG1sIGZpbGVzIG9uIHRoZSBicm93c2VyIGFzIHdlIHdhbnQgdG8gYmUgYWJsZSB0byBwdWJsaXNoIG5ldyBjaGFuZ2VzIHF1aWNrbHlcbiAgICAgICAgICAgIC8vIEhvd2V2ZXIsIHdlIGRvIGNhY2hlIHRoZSBodG1sIGZpbGVzIG9uIENsb3VkRnJvbnQgZm9yIGEgcGVyZm9ybWFuY2UgYm9vc3QgYW5kIGludmFsaWRhdGUgdGhlIGNhY2hlIG9uIGV2ZXJ5IGRlcGxveW1lbnRcbiAgICAgICAgICAgIGNhY2hlQ29udHJvbDogW0NhY2hlQ29udHJvbC5zZXRQdWJsaWMoKSwgQ2FjaGVDb250cm9sLnNNYXhBZ2UoRHVyYXRpb24uZGF5cyg3KSldLFxuICAgICAgICAgICAgaW52YWxpZGF0ZU9uQ2hhbmdlOiB0cnVlXG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gTWFuaWZlc3QgY3JlYXRlZCBieSBQV0EgbW9kdWxlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICdtYW5pZmVzdC4qLmpzb24nLFxuICAgICAgICAgICAgdGFyZ2V0OiBidWlsZEFzc2V0c1RhcmdldFBhdGgsXG4gICAgICAgICAgICBzb3VyY2U6IGJ1aWxkQXNzZXRzU291cmNlUGF0aCxcbiAgICAgICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOCdcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgICAgcGF0dGVybjogJyoucG5nJyxcbiAgICAgICAgICAgIHRhcmdldDogYnVpbGRBc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgc291cmNlOiBidWlsZEFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ2ltYWdlL3BuZycsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLmpwZycsXG4gICAgICAgICAgICB0YXJnZXQ6IGJ1aWxkQXNzZXRzVGFyZ2V0UGF0aCxcbiAgICAgICAgICAgIHNvdXJjZTogYnVpbGRBc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdpbWFnZS9qcGcnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi5zdmcnLFxuICAgICAgICAgICAgdGFyZ2V0OiBidWlsZEFzc2V0c1RhcmdldFBhdGgsXG4gICAgICAgICAgICBzb3VyY2U6IGJ1aWxkQXNzZXRzU291cmNlUGF0aCxcbiAgICAgICAgICAgIGNvbnRlbnRUeXBlOiAnaW1hZ2Uvc3ZnK3htbCcsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLmVvdCcsXG4gICAgICAgICAgICB0YXJnZXQ6IGJ1aWxkQXNzZXRzVGFyZ2V0UGF0aCxcbiAgICAgICAgICAgIHNvdXJjZTogYnVpbGRBc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi92bmQubXMtZm9udG9iamVjdCcsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLnR0ZicsXG4gICAgICAgICAgICB0YXJnZXQ6IGJ1aWxkQXNzZXRzVGFyZ2V0UGF0aCxcbiAgICAgICAgICAgIHNvdXJjZTogYnVpbGRBc3NldHNTb3VyY2VQYXRoLFxuICAgICAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9mb250LXNmbnQnLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwYXR0ZXJuOiAnKi53b2ZmJyxcbiAgICAgICAgICAgIHRhcmdldDogYnVpbGRBc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgc291cmNlOiBidWlsZEFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ2ZvbnQvd29mZicsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAgIHBhdHRlcm46ICcqLndvZmYyJyxcbiAgICAgICAgICAgIHRhcmdldDogYnVpbGRBc3NldHNUYXJnZXRQYXRoLFxuICAgICAgICAgICAgc291cmNlOiBidWlsZEFzc2V0c1NvdXJjZVBhdGgsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ2ZvbnQvd29mZjInLFxuICAgICAgICB9XG4gICAgXVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIHN0YXRpYyBhc3NldHMgb2YgdGhlIE51eHQgYXBwIHRoYXQgc2hhbGwgYmUgcHVibGljbHkgYXZhaWxhYmxlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0TnV4dEFwcFN0YXRpY0Fzc2V0Q29uZmlncyA9ICgpOiBTdGF0aWNBc3NldENvbmZpZ1tdID0+IHtcbiAgICByZXR1cm4gWy4uLmdldE51eHRBcHBCdWlsZEFzc2V0Q29uZmlncygpLCAuLi5nZXROdXh0QXBwQ3VzdG9tQXNzZXRDb25maWdzKCldO1xufTsiXX0=
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Stack } from 'aws-cdk-lib';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
import { IBucket } from "aws-cdk-lib/aws-s3";
|
|
4
|
+
import { NuxtAppStackProps } from "../nuxt-app-stack-props";
|
|
5
|
+
/**
|
|
6
|
+
* Defines the props required for the {@see NuxtServerAppStack}.
|
|
7
|
+
*/
|
|
8
|
+
export interface NuxtServerAppStackProps extends NuxtAppStackProps {
|
|
9
|
+
/**
|
|
10
|
+
* The ARN of the certificate to use at the ApiGateway for the Nuxt app to make it accessible via the custom domain
|
|
11
|
+
* and to provide the custom domain to the Nuxt app via the 'Host' header for server side rendering use cases.
|
|
12
|
+
* The certificate must be issued in the same region as specified via 'env.region' as ApiGateway works regionally.
|
|
13
|
+
*/
|
|
14
|
+
readonly regionalTlsCertificateArn: string;
|
|
15
|
+
/**
|
|
16
|
+
* The memory size to apply to the Nuxt app's Lambda.
|
|
17
|
+
* Defaults to 1792MB (optimized for costs and performance for standard Nuxt apps).
|
|
18
|
+
*/
|
|
19
|
+
readonly memorySize?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to enable AWS X-Ray for the Nuxt Lambda function.
|
|
22
|
+
*/
|
|
23
|
+
readonly enableTracing?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to enable a global Sitemap bucket which is permanently accessible through multiple deployments.
|
|
26
|
+
*/
|
|
27
|
+
readonly enableSitemap?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* CDK stack to deploy a dynamic Nuxt app (target=server) on AWS with Lambda, ApiGateway, S3 and CloudFront.
|
|
31
|
+
*/
|
|
32
|
+
export declare class NuxtServerAppStack extends Stack {
|
|
33
|
+
/**
|
|
34
|
+
* The identifier prefix of the resources created by the stack.
|
|
35
|
+
*
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
private readonly resourceIdPrefix;
|
|
39
|
+
/**
|
|
40
|
+
* The identifier for the current deployment that is used as S3 folder name
|
|
41
|
+
* to store the static assets of the Nuxt app.
|
|
42
|
+
*
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
private readonly deploymentRevision;
|
|
46
|
+
/**
|
|
47
|
+
* The identity to use for accessing the deployment assets on S3.
|
|
48
|
+
*
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
private readonly cdnAccessIdentity;
|
|
52
|
+
/**
|
|
53
|
+
* The S3 bucket where the deployment assets gets stored.
|
|
54
|
+
*/
|
|
55
|
+
staticAssetsBucket: IBucket;
|
|
56
|
+
/**
|
|
57
|
+
* The S3 bucket where the sitemap assets gets stored.
|
|
58
|
+
*/
|
|
59
|
+
sitemapBucket: IBucket | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* The Lambda function to render the Nuxt app on the server side.
|
|
62
|
+
*
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
private readonly appLambdaFunction;
|
|
66
|
+
/**
|
|
67
|
+
* The Lambda function that cleanups the outdated static assets of the Nuxt app.
|
|
68
|
+
*
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private readonly cleanupLambdaFunction;
|
|
72
|
+
/**
|
|
73
|
+
* The API gateway to make the Lambda function to render the Nuxt app publicly available.
|
|
74
|
+
*
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
private apiGateway;
|
|
78
|
+
/**
|
|
79
|
+
* The configs for the static assets of the Nuxt app that shall be publicly available.
|
|
80
|
+
*
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
private staticAssetConfigs;
|
|
84
|
+
/**
|
|
85
|
+
* The CloudFront distribution to route incoming requests to the Nuxt Lambda function (via the API gateway)
|
|
86
|
+
* or the S3 assets folder (with caching).
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
private readonly cdn;
|
|
91
|
+
constructor(scope: Construct, id: string, props: NuxtServerAppStackProps);
|
|
92
|
+
/**
|
|
93
|
+
* Creates the identity to access the S3 deployment asset files via the CloudFront distribution.
|
|
94
|
+
*
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
private createCdnAccessIdentity;
|
|
98
|
+
/**
|
|
99
|
+
* Creates the bucket to store the static deployment asset files of the Nuxt app.
|
|
100
|
+
*
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
private createStaticAssetsBucket;
|
|
104
|
+
/**
|
|
105
|
+
* Creates the bucket to store the sitemap assets of the Nuxt app.
|
|
106
|
+
*
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
private createSitemapBucket;
|
|
110
|
+
/**
|
|
111
|
+
* Creates the Lambda function to render the Nuxt app.
|
|
112
|
+
*
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
private createAppLambdaFunction;
|
|
116
|
+
/**
|
|
117
|
+
* Creates the Lambda function that cleanups the outdated static assets of the Nuxt app.
|
|
118
|
+
*
|
|
119
|
+
* @param props
|
|
120
|
+
* @private
|
|
121
|
+
*/
|
|
122
|
+
private createCleanupLambdaFunction;
|
|
123
|
+
/**
|
|
124
|
+
* Creates the API gateway to make the Nuxt app render Lambda function publicly available.
|
|
125
|
+
*
|
|
126
|
+
* @private
|
|
127
|
+
*/
|
|
128
|
+
private createApiGateway;
|
|
129
|
+
/**
|
|
130
|
+
* Creates the CloudFront distribution that routes incoming requests to the Nuxt Lambda function (via the API gateway)
|
|
131
|
+
* or the S3 assets folder (with caching).
|
|
132
|
+
*
|
|
133
|
+
* @param props
|
|
134
|
+
* @private
|
|
135
|
+
*/
|
|
136
|
+
private createCloudFrontDistribution;
|
|
137
|
+
/**
|
|
138
|
+
* Creates a behavior for the CloudFront distribution to route incoming requests to the Nuxt render Lambda function (via API gateway).
|
|
139
|
+
* Additionally, this automatically redirects HTTP requests to HTTPS.
|
|
140
|
+
*
|
|
141
|
+
* @private
|
|
142
|
+
*/
|
|
143
|
+
private createNuxtAppRouteBehavior;
|
|
144
|
+
private setupCloudFrontRouting;
|
|
145
|
+
/**
|
|
146
|
+
* Creates a cache policy for the Nuxt app route behavior of the CloudFront distribution.
|
|
147
|
+
* Even though we don't want to cache SSR requests, we still have to create this cache policy in order to
|
|
148
|
+
* forward required cookies, query params and headers. This doesn't make any sense, because if nothing
|
|
149
|
+
* is cached, one would expect, that anything would/could be forwarded, but anyway...
|
|
150
|
+
*/
|
|
151
|
+
private createSsrCachePolicy;
|
|
152
|
+
/**
|
|
153
|
+
* Creates a behavior for the CloudFront distribution to route matching incoming requests for the static assets
|
|
154
|
+
* to the S3 bucket that holds these static assets.
|
|
155
|
+
*
|
|
156
|
+
* @private
|
|
157
|
+
*/
|
|
158
|
+
private createStaticAssetsRouteBehavior;
|
|
159
|
+
/**
|
|
160
|
+
* Creates a behavior for the CloudFront distribution to route matching incoming requests for the sitemap assets
|
|
161
|
+
* to the S3 bucket that holds these sitemap assets.
|
|
162
|
+
*
|
|
163
|
+
* @private
|
|
164
|
+
*/
|
|
165
|
+
private createSitemapRouteBehavior;
|
|
166
|
+
/**
|
|
167
|
+
* Uploads the static assets of the Nuxt app as defined in {@see getNuxtAppStaticAssetConfigs} to the static assets S3 bucket.
|
|
168
|
+
* In order to enable a zero-downtime deployment, we use a new subdirectory (revision) for every deployment.
|
|
169
|
+
* The previous versions are retained to allow clients to continue to work with an older revision but gets cleaned up
|
|
170
|
+
* after a specified period of time via the Lambda function in the {@see NuxtAppAssetsCleanupStack}.
|
|
171
|
+
*/
|
|
172
|
+
private configureDeployments;
|
|
173
|
+
/**
|
|
174
|
+
* Resolves the hosted zone at which the DNS records shall be created to access the Nuxt app on the internet.
|
|
175
|
+
*
|
|
176
|
+
* @param props
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
private findHostedZone;
|
|
180
|
+
/**
|
|
181
|
+
* Creates the DNS records to access the Nuxt app on the internet via the custom domain.
|
|
182
|
+
*
|
|
183
|
+
* @param props
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
private createDnsRecords;
|
|
187
|
+
/**
|
|
188
|
+
* Creates a scheduled rule to ping the Nuxt app Lambda function every 5 minutes in order to keep it warm
|
|
189
|
+
* and speed up initial SSR requests.
|
|
190
|
+
*
|
|
191
|
+
* @private
|
|
192
|
+
*/
|
|
193
|
+
private createAppPingRule;
|
|
194
|
+
/**
|
|
195
|
+
* Creates a scheduled rule that runs every tuesday at 03:30 AM GMT to trigger
|
|
196
|
+
* our cleanup Lambda function.
|
|
197
|
+
*
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
200
|
+
private createCleanupTriggerRule;
|
|
201
|
+
}
|