cdk-nuxt 0.1.1
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/README.md +14 -0
- package/lib/nuxt-app-stack.ts +282 -0
- package/lib/nuxt-app-static-assets.ts +107 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Welcome to your CDK TypeScript project!
|
|
2
|
+
|
|
3
|
+
This is a blank project for TypeScript development with CDK.
|
|
4
|
+
|
|
5
|
+
The `cdk.json` file tells the CDK Toolkit how to execute your app.
|
|
6
|
+
|
|
7
|
+
## Useful commands
|
|
8
|
+
|
|
9
|
+
* `npm run build` compile typescript to js
|
|
10
|
+
* `npm run watch` watch for changes and compile
|
|
11
|
+
* `npm run test` perform the jest unit tests
|
|
12
|
+
* `cdk deploy` deploy this stack to your default AWS account/region
|
|
13
|
+
* `cdk diff` compare deployed stack with current state
|
|
14
|
+
* `cdk synth` emits the synthesized CloudFormation template
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import {Duration, RemovalPolicy, Stack, StackProps, Tags, aws_lambda} from 'aws-cdk-lib';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
import {Certificate, ICertificate} from "aws-cdk-lib/aws-certificatemanager";
|
|
4
|
+
import {
|
|
5
|
+
AllowedMethods,
|
|
6
|
+
BehaviorOptions, CacheCookieBehavior,
|
|
7
|
+
CachedMethods, CacheHeaderBehavior,
|
|
8
|
+
CachePolicy, CacheQueryStringBehavior,
|
|
9
|
+
Distribution, ICachePolicy,
|
|
10
|
+
IOriginAccessIdentity, OriginAccessIdentity, OriginProtocolPolicy, PriceClass,
|
|
11
|
+
SecurityPolicyProtocol,
|
|
12
|
+
ViewerProtocolPolicy
|
|
13
|
+
} from "aws-cdk-lib/aws-cloudfront";
|
|
14
|
+
import {Architecture, Code, LayerVersion, Runtime} from "aws-cdk-lib/aws-lambda";
|
|
15
|
+
import {BlockPublicAccess, Bucket, BucketAccessControl, IBucket} from "aws-cdk-lib/aws-s3";
|
|
16
|
+
import {ARecord, AaaaRecord, HostedZone, IHostedZone, RecordTarget} from "aws-cdk-lib/aws-route53";
|
|
17
|
+
import {BucketDeployment, CacheControl, Source, StorageClass} from "aws-cdk-lib/aws-s3-deployment";
|
|
18
|
+
import {HttpOrigin, S3Origin} from "aws-cdk-lib/aws-cloudfront-origins";
|
|
19
|
+
import {CloudFrontTarget} from "aws-cdk-lib/aws-route53-targets";
|
|
20
|
+
import {HttpMethod} from "aws-cdk-lib/aws-stepfunctions-tasks";
|
|
21
|
+
import {RetentionDays} from "aws-cdk-lib/aws-logs";
|
|
22
|
+
import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations-alpha';
|
|
23
|
+
import {HttpApi} from "@aws-cdk/aws-apigatewayv2-alpha";
|
|
24
|
+
import {NuxtAppStaticAssets} from "./nuxt-app-static-assets";
|
|
25
|
+
|
|
26
|
+
export interface AppStackProps extends StackProps {
|
|
27
|
+
readonly project: string;
|
|
28
|
+
readonly service: string;
|
|
29
|
+
readonly environment: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface NuxtAppStackProps extends AppStackProps {
|
|
33
|
+
readonly baseDomain: string;
|
|
34
|
+
readonly subDomain?: string;
|
|
35
|
+
|
|
36
|
+
// Used by the CDN, must be issued in us-east-1 (global)
|
|
37
|
+
readonly globalTlsCertificateArn: string;
|
|
38
|
+
|
|
39
|
+
readonly hostedZoneId: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class NuxtAppStack extends Stack {
|
|
43
|
+
private readonly resourceIdPrefix: string;
|
|
44
|
+
private readonly deploymentRevision: string;
|
|
45
|
+
private readonly tlsCertificate: ICertificate;
|
|
46
|
+
private readonly cdnAccessIdentity: IOriginAccessIdentity;
|
|
47
|
+
public staticAssetsBucket: IBucket;
|
|
48
|
+
private readonly layer: LayerVersion;
|
|
49
|
+
private readonly lambdaFunction: aws_lambda.Function;
|
|
50
|
+
private apiGateway: HttpApi;
|
|
51
|
+
private readonly httpsForwardingBehavior: BehaviorOptions;
|
|
52
|
+
private readonly cdn: Distribution;
|
|
53
|
+
private readonly hostedZone: IHostedZone;
|
|
54
|
+
|
|
55
|
+
constructor(scope: Construct, id: string, props: NuxtAppStackProps) {
|
|
56
|
+
super(scope, id, props);
|
|
57
|
+
|
|
58
|
+
Tags.of(scope).add('project', props.project);
|
|
59
|
+
Tags.of(scope).add('domain', props.subDomain ? `${props.subDomain}.${props.baseDomain}` : props.baseDomain);
|
|
60
|
+
Tags.of(scope).add('service', props.service);
|
|
61
|
+
Tags.of(scope).add('environment', props.environment);
|
|
62
|
+
|
|
63
|
+
this.resourceIdPrefix = `${props.project}-${props.service}-${props.environment}`;
|
|
64
|
+
this.deploymentRevision = new Date().toISOString();
|
|
65
|
+
this.tlsCertificate = this.findTlsCertificate(props);
|
|
66
|
+
this.cdnAccessIdentity = this.createCdnAccessIdentity();
|
|
67
|
+
this.staticAssetsBucket = this.createStaticAssetsBucket();
|
|
68
|
+
this.layer = this.createSsrLambdaLayer();
|
|
69
|
+
this.lambdaFunction = this.createLambdaFunction();
|
|
70
|
+
this.apiGateway = this.createApiGateway();
|
|
71
|
+
this.httpsForwardingBehavior = this.createHttpsForwardingBehavior();
|
|
72
|
+
this.cdn = this.createCloudFrontDistribution(props);
|
|
73
|
+
this.configureDeployments();
|
|
74
|
+
this.hostedZone = this.findHostedZone(props);
|
|
75
|
+
this.createDnsRecords(props);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private findTlsCertificate(props: NuxtAppStackProps): ICertificate {
|
|
79
|
+
return Certificate.fromCertificateArn(this, `${this.resourceIdPrefix}-tls-certificate`, props.globalTlsCertificateArn);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private createCdnAccessIdentity(): IOriginAccessIdentity {
|
|
83
|
+
const originAccessIdentityName = `${this.resourceIdPrefix}-cdn-s3-access`;
|
|
84
|
+
return new OriginAccessIdentity(this, originAccessIdentityName);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private createStaticAssetsBucket(): IBucket {
|
|
88
|
+
const bucketName = `${this.resourceIdPrefix}-assets`;
|
|
89
|
+
const bucket = new Bucket(this, bucketName, {
|
|
90
|
+
accessControl: BucketAccessControl.AUTHENTICATED_READ,
|
|
91
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
92
|
+
bucketName,
|
|
93
|
+
// the bucket and all of its objects can be deleted, because all the content is managed in this project
|
|
94
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
95
|
+
autoDeleteObjects: true,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
bucket.grantReadWrite(this.cdnAccessIdentity);
|
|
99
|
+
|
|
100
|
+
return bucket;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private createSsrLambdaLayer(): LayerVersion {
|
|
104
|
+
const layerName = `${this.resourceIdPrefix}-ssr-layer`;
|
|
105
|
+
return new LayerVersion(this, layerName, {
|
|
106
|
+
layerVersionName: layerName,
|
|
107
|
+
code: Code.fromAsset('./server/layer'),
|
|
108
|
+
compatibleRuntimes: [Runtime.NODEJS_12_X],
|
|
109
|
+
description: `Contains node_modules required for server-side of ${this.resourceIdPrefix}.`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private createLambdaFunction(): aws_lambda.Function {
|
|
114
|
+
const funcName = `${this.resourceIdPrefix}-function`;
|
|
115
|
+
|
|
116
|
+
return new aws_lambda.Function(this, funcName, {
|
|
117
|
+
functionName: funcName,
|
|
118
|
+
runtime: Runtime.NODEJS_12_X,
|
|
119
|
+
architecture: Architecture.ARM_64,
|
|
120
|
+
layers: [this.layer],
|
|
121
|
+
handler: 'lambda-handler.render',
|
|
122
|
+
code: Code.fromAsset('./deployment', {
|
|
123
|
+
exclude: ['**.svg', '**.ico', '**.png', '**.jpg', 'chunk.*.js*', 'bundle.*.js*', 'bundle.*.js*', 'sw.js*'],
|
|
124
|
+
}),
|
|
125
|
+
timeout: Duration.seconds(10),
|
|
126
|
+
memorySize: 512,
|
|
127
|
+
logRetention: RetentionDays.ONE_MONTH,
|
|
128
|
+
environment: {},
|
|
129
|
+
allowPublicSubnet: false
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private createApiGateway(): HttpApi {
|
|
134
|
+
const lambdaIntegration = new HttpLambdaIntegration(`${this.resourceIdPrefix}-lambda-integration`, this.lambdaFunction);
|
|
135
|
+
const apiName = `${this.resourceIdPrefix}-api`;
|
|
136
|
+
const apiGateway = new HttpApi(this, apiName, {
|
|
137
|
+
apiName,
|
|
138
|
+
// The app does not allow any cross-origin access by purpose: the app should not be embeddable anywhere
|
|
139
|
+
corsPreflight: undefined,
|
|
140
|
+
defaultIntegration: lambdaIntegration,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
apiGateway.addRoutes({
|
|
144
|
+
integration: lambdaIntegration,
|
|
145
|
+
path: '/{proxy+}',
|
|
146
|
+
methods: [HttpMethod.GET, HttpMethod.HEAD],
|
|
147
|
+
});
|
|
148
|
+
return apiGateway;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private createHttpsForwardingBehavior(): BehaviorOptions {
|
|
152
|
+
return {
|
|
153
|
+
origin: new HttpOrigin(`${this.apiGateway.httpApiId}.execute-api.${this.region}.amazonaws.com`, {
|
|
154
|
+
connectionAttempts: 2,
|
|
155
|
+
connectionTimeout: Duration.seconds(2),
|
|
156
|
+
readTimeout: Duration.seconds(10),
|
|
157
|
+
protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
|
|
158
|
+
}),
|
|
159
|
+
allowedMethods: AllowedMethods.ALLOW_GET_HEAD,
|
|
160
|
+
compress: true,
|
|
161
|
+
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
162
|
+
originRequestPolicy: undefined,
|
|
163
|
+
cachePolicy: this.createSsrCachePolicy(),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Eventhough we don't want to cache SSR requests, we still have to create a cache policy, in order to
|
|
169
|
+
* forward required cookies, query params and headers. This doesn't make any sense, because if nothing
|
|
170
|
+
* is cached, one would expect, that anything would/could be forwarded, but anyway...
|
|
171
|
+
*/
|
|
172
|
+
private createSsrCachePolicy(): ICachePolicy {
|
|
173
|
+
|
|
174
|
+
// The headers to pass to the app
|
|
175
|
+
const headers = [
|
|
176
|
+
'User-Agent', // Required to distinguish between mobile and desktop template
|
|
177
|
+
'Authorization', // For authorization
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
return new CachePolicy(this, `${this.resourceIdPrefix}-cache-policy`, {
|
|
181
|
+
cachePolicyName: `${this.resourceIdPrefix}-cdn-cache-policy`,
|
|
182
|
+
comment: `Passes all required request data to the ${this.resourceIdPrefix} origin.`,
|
|
183
|
+
defaultTtl: Duration.seconds(0),
|
|
184
|
+
minTtl: Duration.seconds(0),
|
|
185
|
+
maxTtl: Duration.seconds(1), // the max TTL must not be 0 for a cache policy
|
|
186
|
+
queryStringBehavior: CacheQueryStringBehavior.all(),
|
|
187
|
+
headerBehavior: CacheHeaderBehavior.allowList(...headers),
|
|
188
|
+
cookieBehavior: CacheCookieBehavior.all(),
|
|
189
|
+
enableAcceptEncodingBrotli: true,
|
|
190
|
+
enableAcceptEncodingGzip: true,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private createCloudFrontDistribution(props: NuxtAppStackProps): Distribution {
|
|
195
|
+
const cdnName = `${this.resourceIdPrefix}-cdn`;
|
|
196
|
+
|
|
197
|
+
return new Distribution(this, cdnName, {
|
|
198
|
+
domainNames: props.subDomain ? [`${props.subDomain}.${props.baseDomain}`] : [props.baseDomain, `*.${props.baseDomain}`],
|
|
199
|
+
comment: `${this.resourceIdPrefix}-redirect`,
|
|
200
|
+
minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2018,
|
|
201
|
+
certificate: this.tlsCertificate,
|
|
202
|
+
defaultBehavior: this.httpsForwardingBehavior,
|
|
203
|
+
additionalBehaviors: this.createStaticAssetBehaviors(),
|
|
204
|
+
priceClass: PriceClass.PRICE_CLASS_100, // Use only North America and Europe
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private createStaticAssetBehaviors(): Record<string, BehaviorOptions> {
|
|
209
|
+
const staticAssetsCacheConfig: BehaviorOptions = {
|
|
210
|
+
origin: new S3Origin(this.staticAssetsBucket, {
|
|
211
|
+
connectionAttempts: 2,
|
|
212
|
+
connectionTimeout: Duration.seconds(3),
|
|
213
|
+
originAccessIdentity: this.cdnAccessIdentity,
|
|
214
|
+
originPath: this.deploymentRevision,
|
|
215
|
+
}),
|
|
216
|
+
compress: true,
|
|
217
|
+
allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
218
|
+
cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
219
|
+
cachePolicy: CachePolicy.CACHING_OPTIMIZED,
|
|
220
|
+
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const rules: Record<string, BehaviorOptions> = {};
|
|
224
|
+
NuxtAppStaticAssets.forEach(asset => {
|
|
225
|
+
rules[`${asset.target}${asset.pattern}`] = staticAssetsCacheConfig
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
return rules
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* In order to enable a zero-downtime deployment, we use a new subdirectory (revision) for every deployment.
|
|
233
|
+
* The previous versions are retained to allow clients to continue to work with an older revision.
|
|
234
|
+
*/
|
|
235
|
+
private configureDeployments(): BucketDeployment[] {
|
|
236
|
+
const defaultCacheConfig = [
|
|
237
|
+
CacheControl.setPublic(),
|
|
238
|
+
CacheControl.maxAge(Duration.days(365)),
|
|
239
|
+
CacheControl.fromString('immutable'),
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
// Returns a deployment for every configured static asset type to respect the different cache settings
|
|
243
|
+
return NuxtAppStaticAssets.map((asset, assetIndex) => {
|
|
244
|
+
return new BucketDeployment(this, `${this.resourceIdPrefix}-assets-deployment-${assetIndex}`, {
|
|
245
|
+
sources: [Source.asset(asset.source)],
|
|
246
|
+
destinationBucket: this.staticAssetsBucket,
|
|
247
|
+
destinationKeyPrefix: this.deploymentRevision + asset.target,
|
|
248
|
+
prune: false,
|
|
249
|
+
storageClass: StorageClass.STANDARD,
|
|
250
|
+
exclude: ['*'],
|
|
251
|
+
include: [asset.pattern],
|
|
252
|
+
cacheControl: asset.cacheControl ?? defaultCacheConfig,
|
|
253
|
+
contentType: asset.contentType,
|
|
254
|
+
})
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private findHostedZone(props: NuxtAppStackProps): IHostedZone {
|
|
259
|
+
return HostedZone.fromHostedZoneAttributes(this, `${this.resourceIdPrefix}-hosted-zone`, {
|
|
260
|
+
hostedZoneId: props.hostedZoneId,
|
|
261
|
+
zoneName: props.baseDomain,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private createDnsRecords(props: NuxtAppStackProps): void {
|
|
266
|
+
const dnsTarget = RecordTarget.fromAlias(new CloudFrontTarget(this.cdn));
|
|
267
|
+
|
|
268
|
+
// Create a record for IPv4
|
|
269
|
+
new ARecord(this, `${this.resourceIdPrefix}-ipv4-record`, {
|
|
270
|
+
recordName: props.subDomain ? `${props.subDomain}.${props.baseDomain}` : props.baseDomain,
|
|
271
|
+
zone: this.hostedZone,
|
|
272
|
+
target: dnsTarget,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Create a record for IPv6
|
|
276
|
+
new AaaaRecord(this, `${this.resourceIdPrefix}-ipv6-record`, {
|
|
277
|
+
recordName: props.subDomain ? `${props.subDomain}.${props.baseDomain}` : props.baseDomain,
|
|
278
|
+
zone: this.hostedZone,
|
|
279
|
+
target: dnsTarget,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {CacheControl} from "aws-cdk-lib/aws-s3-deployment";
|
|
2
|
+
import {Duration} from "aws-cdk-lib";
|
|
3
|
+
|
|
4
|
+
interface StaticAssetConfig {
|
|
5
|
+
pattern: string, // The pattern to use for accessing the files
|
|
6
|
+
contentType: string, // The type of the files to upload
|
|
7
|
+
source: string, // The local directory to upload the files from
|
|
8
|
+
target: string, // The remote path at which to make the uploaded files accessible
|
|
9
|
+
cacheControl?: CacheControl[] // The custom cache settings
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const buildAssetsSourcePath = './.nuxt/dist/client';
|
|
13
|
+
const buildAssetsTargetPath = '/assets/'; // Must match 'build.publicPath' in nuxt.config.js
|
|
14
|
+
|
|
15
|
+
const customAssetsSourcePath = './src/static';
|
|
16
|
+
const customAssetsTargetPath = '/';
|
|
17
|
+
|
|
18
|
+
// Defines the paths with their cache settings that shall be public available in our app
|
|
19
|
+
// These should match the files in 'src/.nuxt/dist/client' and 'static'
|
|
20
|
+
export const NuxtAppStaticAssets: StaticAssetConfig[] = [
|
|
21
|
+
|
|
22
|
+
// Build Assets
|
|
23
|
+
{
|
|
24
|
+
pattern: '*.js',
|
|
25
|
+
target: buildAssetsTargetPath,
|
|
26
|
+
source: buildAssetsSourcePath,
|
|
27
|
+
contentType: 'application/javascript; charset=UTF-8',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: '*.js.map',
|
|
31
|
+
target: buildAssetsTargetPath,
|
|
32
|
+
source: buildAssetsSourcePath,
|
|
33
|
+
contentType: 'application/json; charset=UTF-8',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
pattern: 'sw.js',
|
|
37
|
+
target: buildAssetsTargetPath,
|
|
38
|
+
source: buildAssetsSourcePath,
|
|
39
|
+
contentType: 'application/javascript; charset=UTF-8',
|
|
40
|
+
cacheControl: [CacheControl.setPublic(), CacheControl.maxAge(Duration.days(1))],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: 'sw.js.map',
|
|
44
|
+
target: buildAssetsTargetPath,
|
|
45
|
+
source: buildAssetsSourcePath,
|
|
46
|
+
contentType: 'application/json; charset=UTF-8',
|
|
47
|
+
cacheControl: [CacheControl.setPublic(), CacheControl.maxAge(Duration.days(1))],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
pattern: '*.svg',
|
|
51
|
+
target: buildAssetsTargetPath,
|
|
52
|
+
source: buildAssetsSourcePath,
|
|
53
|
+
contentType: 'image/svg+xml',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
pattern: '*.eot',
|
|
57
|
+
target: buildAssetsTargetPath,
|
|
58
|
+
source: buildAssetsSourcePath,
|
|
59
|
+
contentType: 'application/vnd.ms-fontobject',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
pattern: '*.ttf',
|
|
63
|
+
target: buildAssetsTargetPath,
|
|
64
|
+
source: buildAssetsSourcePath,
|
|
65
|
+
contentType: 'application/font-sfnt',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
pattern: '*.woff',
|
|
69
|
+
target: buildAssetsTargetPath,
|
|
70
|
+
source: buildAssetsSourcePath,
|
|
71
|
+
contentType: 'font/woff',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
pattern: '*.woff2',
|
|
75
|
+
target: buildAssetsTargetPath,
|
|
76
|
+
source: buildAssetsSourcePath,
|
|
77
|
+
contentType: 'font/woff2',
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// Custom Static Assets
|
|
81
|
+
{
|
|
82
|
+
pattern: '*.png',
|
|
83
|
+
source: customAssetsSourcePath,
|
|
84
|
+
target: customAssetsTargetPath,
|
|
85
|
+
contentType: 'image/png',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
pattern: '*.jpg',
|
|
89
|
+
source: customAssetsSourcePath,
|
|
90
|
+
target: customAssetsTargetPath,
|
|
91
|
+
contentType: 'image/jpg',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
pattern: 'robots.txt',
|
|
95
|
+
source: customAssetsSourcePath,
|
|
96
|
+
target: customAssetsTargetPath,
|
|
97
|
+
contentType: 'text/plain; charset=UTF-8',
|
|
98
|
+
cacheControl: [CacheControl.setPublic(), CacheControl.maxAge(Duration.days(1))],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
pattern: 'manifest.json',
|
|
102
|
+
source: customAssetsSourcePath,
|
|
103
|
+
target: customAssetsTargetPath,
|
|
104
|
+
contentType: 'application/json; charset=UTF-8',
|
|
105
|
+
cacheControl: [CacheControl.setPublic(), CacheControl.maxAge(Duration.days(2))],
|
|
106
|
+
},
|
|
107
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cdk-nuxt",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"files": [
|
|
5
|
+
"lib"
|
|
6
|
+
],
|
|
7
|
+
"main": "./lib/nuxt-app-stack.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"watch": "tsc -w",
|
|
11
|
+
"cdk": "cdk"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "10.17.27",
|
|
15
|
+
"aws-cdk": "2.10.0",
|
|
16
|
+
"ts-node": "^9.0.0",
|
|
17
|
+
"typescript": "~3.9.7"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@aws-cdk/aws-apigatewayv2-alpha": "^2.10.0-alpha.0",
|
|
21
|
+
"@aws-cdk/aws-apigatewayv2-integrations-alpha": "^2.10.0-alpha.0",
|
|
22
|
+
"aws-cdk-lib": "2.10.0",
|
|
23
|
+
"constructs": "^10.0.0",
|
|
24
|
+
"source-map-support": "^0.5.16"
|
|
25
|
+
}
|
|
26
|
+
}
|