documenting AWS options, WIP making AWS deployments work again
This commit is contained in:
parent
5db32796f6
commit
6062d60b28
13 changed files with 137 additions and 212 deletions
4
.d.ts
vendored
4
.d.ts
vendored
|
|
@ -14,6 +14,7 @@ declare module '@serverless/core' {
|
||||||
};
|
};
|
||||||
instance: {
|
instance: {
|
||||||
debugMode: boolean;
|
debugMode: boolean;
|
||||||
|
metrics: any;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -56,14 +57,13 @@ type BaseDeploymentOptions = {
|
||||||
onPreDeploy?: () => Promise<void>;
|
onPreDeploy?: () => Promise<void>;
|
||||||
onPostDeploy?: () => Promise<void>;
|
onPostDeploy?: () => Promise<void>;
|
||||||
onShutdown?: () => Promise<void>;
|
onShutdown?: () => Promise<void>;
|
||||||
buildOptions?: BuildOptions | boolean;
|
build?: BuildOptions;
|
||||||
nextConfigDir?: string;
|
nextConfigDir?: string;
|
||||||
domain?: string | string[];
|
domain?: string | string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type BuildOptions = {
|
type BuildOptions = {
|
||||||
cwd?: string;
|
cwd?: string;
|
||||||
enabled?: boolean;
|
|
||||||
cmd: string;
|
cmd: string;
|
||||||
args: string[];
|
args: string[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
79
README.md
79
README.md
|
|
@ -129,18 +129,18 @@ The deployment configuration is to be provided through `next-deploy.config.js`,
|
||||||
|
|
||||||
All engines support the basic options:
|
All engines support the basic options:
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ------------- | ------------------------------- | ------- | -------------------------------------------------------------------------------------------------------- |
|
| ------------- | --------------------- | ------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
| engine | `"aws"\|"github"` | `aws` | The platform to deploy to. |
|
| engine | `"aws"\|"github"` | `aws` | The platform to deploy to. |
|
||||||
| debug | `boolean` | `false` | Print helpful messages to |
|
| debug | `boolean` | `false` | Print helpful messages to |
|
||||||
| onPreDeploy | `() => Promise<void>` | `null` | A callback that gets called before the deployment. |
|
| onPreDeploy | `() => Promise<void>` | `null` | A callback that gets called before the deployment. |
|
||||||
| onPostDeploy | `() => Promise<void>` | `null` | A callback that gets called after the deployment successfully finishes. |
|
| onPostDeploy | `() => Promise<void>` | `null` | A callback that gets called after the deployment successfully finishes. |
|
||||||
| onShutdown | `() => Promise<void>` | `null` | A callback that gets called after the deployment is shutdown by a INT/QUIT/TERM signal like from ctrl+c. |
|
| onShutdown | `() => Promise<void>` | `null` | A callback that gets called after the deployment is shutdown by a INT/QUIT/TERM signal like from ctrl+c. |
|
||||||
| buildOptions | [`BuildOptions`](#BuildOptions) | `{}` | Build related options. |
|
| build | [`Build`](#Build) | `{}` | Build related options. |
|
||||||
| nextConfigDir | `string` | `./` | The directory holding the `next.config.js`. |
|
| nextConfigDir | `string` | `./` | The directory holding the `next.config.js`. |
|
||||||
| domain | `string\|string[]` | `null` | The domain to deploy to . |
|
| domain | `string\|string[]` | `null` | The domain to deploy to . |
|
||||||
|
|
||||||
#### BuildOptions
|
#### Build
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ---- | ---------- | ------------------------ | ---------------------------------------------------- |
|
| ---- | ---------- | ------------------------ | ---------------------------------------------------- |
|
||||||
|
|
@ -150,9 +150,9 @@ All engines support the basic options:
|
||||||
|
|
||||||
### Github Options
|
### Github Options
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| -------------- | --------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
| ------- | -------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||||
| publishOptions | [`PublishOptions`](https://github.com/tschaub/gh-pages#options) | `{message: "Next Deployment Update", dotfiles: true}` | The [git-hub page options](https://github.com/tschaub/gh-pages#options) to publish with. |
|
| publish | [`Publish`](https://github.com/tschaub/gh-pages#options) | `{message: "Next Deployment Update", dotfiles: true}` | The [git-hub page options](https://github.com/tschaub/gh-pages#options) to publish with. |
|
||||||
|
|
||||||
### AWS Options
|
### AWS Options
|
||||||
|
|
||||||
|
|
@ -172,33 +172,31 @@ All engines support the basic options:
|
||||||
|
|
||||||
#### PublicDirectoryCache
|
#### PublicDirectoryCache
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ----- | -------- | ------------------------------------------------- | ---------------------------------------- |
|
| ----- | -------- | --------------------------------------------------------- | ---------------------------------------- |
|
||||||
| test | `string` | `/\.(gif|jpe?g|jp2|tiff|png|webp|bmp|svg|ico)$/i` | The test to apply the caching behaviour. |
|
| test | `string` | `/\.(gif\|jpe?g\|jp2\|tiff\|png\|webp\|bmp\|svg\|ico)$/i` | The test to apply the caching behaviour. |
|
||||||
| value | `string` | `public, max-age=31536000, must-revalidate` | The caching behavior. |
|
| value | `string` | `public, max-age=31536000, must-revalidate` | The caching behavior. |
|
||||||
|
|
||||||
#### CloudFront
|
#### CloudFront
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ---------------------- | ------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------- | ----------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| ttl | `number` | `0` | The amount of time that you want objects to stay in CloudFront's cache before it forwards another request to determine whether the object has been updated. |
|
| ttl | `number` | `0` | The amount of time that you want objects to stay in CloudFront's cache before it forwards another request to determine whether the object has been updated. |
|
||||||
| smoothStreaming | `boolean` | `false` | Indicates whether you want to distribute media files in the Microsoft Smooth Streaming format. |
|
| smoothStreaming | `boolean` | `false` | Indicates whether you want to distribute media files in the Microsoft Smooth Streaming format. |
|
||||||
| viewerProtocolPolicy | `string` | `redirect-to-https` | The policy for viewers to access the content. |
|
| viewerProtocolPolicy | `string` | `redirect-to-https` | The policy for viewers to access the content. |
|
||||||
| fieldLevelEncryptionId | `string` | `""` | The value of the ID for the field-level encryption configuration that you want to use. |
|
| fieldLevelEncryptionId | `string` | `""` | The value of the ID for the field-level encryption configuration that you want to use. |
|
||||||
| forward | [`Forward`](#Forward) | `{}` | Determines the forwarding configuration |
|
| forward | [`Forward`](#Forward) | `{}` | Determines the forwarding configuration |
|
||||||
| viewerCertificate | [`ViewerCertificate`](#ViewerCertificate) | `{}` | Determines the SSL/TLS configuration for communicating with viewers. |
|
| viewerCertificate | [`ViewerCertificate`](#ViewerCertificate) | `{}` | Determines the SSL/TLS configuration for communicating with viewers. |
|
||||||
| cookies | `string\|string[]` | `all` | Indicates which cookies should be forwarded. |
|
| "lambda@edge" | [`LambdaAtEdge`](#LambdaAtEdge) | `{}` | Additional lambda@edge functions. |
|
||||||
| queryString | `boolean` | `true` | Indicates whether the query string should be forwarded. |
|
|
||||||
| lambda@edge | [`LambdaAtEdgeConfig`](#LambdaAtEdgeConfig) | `TODO` | TODO |
|
|
||||||
|
|
||||||
#### Forward
|
#### Forward
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| -------------------- | ---------- | ------- | ----------- |
|
| -------------------- | ------------------ | ------- | ------------------------------------------------------------------------ |
|
||||||
| cookies | `string[]` | `TODO` | TODO |
|
| cookies | `string\|string[]` | `all` | Indicates which cookies should be forwarded. |
|
||||||
| queryString | `string` | `TODO` | TODO |
|
| queryString | `boolean` | `true` | Indicates whether the query string should be forwarded. |
|
||||||
| headers | `string[]` | `TODO` | TODO |
|
| headers | `string[]` | `[]` | Headers to forward (whitelisted headers). |
|
||||||
| queryStringCacheKeys | `string[]` | `TODO` | TODO |
|
| queryStringCacheKeys | `string[]` | `[]` | Details of the query string parameters that you want to use for caching. |
|
||||||
|
|
||||||
#### ViewerCertificate
|
#### ViewerCertificate
|
||||||
|
|
||||||
|
|
@ -208,17 +206,18 @@ All engines support the basic options:
|
||||||
| SSLSupportMethod | `string` | `sni-only` | Specifies which viewers the distribution accepts HTTPS connections from. **sni-only** – The distribution accepts HTTPS connections only from viewers that support server SNI (all modern browsers). **vip** – The distribution accepts HTTPS connections from **all** (not recommended and results in additional monthly charges). |
|
| SSLSupportMethod | `string` | `sni-only` | Specifies which viewers the distribution accepts HTTPS connections from. **sni-only** – The distribution accepts HTTPS connections only from viewers that support server SNI (all modern browsers). **vip** – The distribution accepts HTTPS connections from **all** (not recommended and results in additional monthly charges). |
|
||||||
| minimumProtocolVersion | `string` | `TLSv1.2_2018` | The security policy that you want to use for HTTPS connections with viewers. |
|
| minimumProtocolVersion | `string` | `TLSv1.2_2018` | The security policy that you want to use for HTTPS connections with viewers. |
|
||||||
|
|
||||||
#### LambdaAtEdgeConfig
|
#### LambdaAtEdge
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| ----------- | --------- | ------- | ----------- |
|
| ------------------ | ------------------------------------------ | ------- | ----------------------------------------------------------------------- |
|
||||||
| arn | `string` | `null` | TODO |
|
| _cloudfront event_ | `string\|{arn:string,includeBody:boolean}` | `null` | The customization for a new CloudFront event handler (lambda function). |
|
||||||
| includeBody | `boolean` | `TODO` | TODO |
|
|
||||||
|
|
||||||
### Advanced Configuration
|
### Advanced Configuration
|
||||||
|
|
||||||
Environment variables may be substituted from `process.env` to allow for more flexibility.
|
Environment variables may be substituted from `process.env` to allow for more flexibility.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
### CI/CD
|
### CI/CD
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
## AWS Permissions
|
|
||||||
|
|
||||||
If you are deploying from a restricted AWS account, you will need the following permissions:
|
|
||||||
|
|
||||||
```
|
|
||||||
"acm:DescribeCertificate", // only for custom domains
|
|
||||||
"acm:ListCertificates", // only for custom domains
|
|
||||||
"acm:RequestCertificate", // only for custom domains
|
|
||||||
"cloudfront:CreateCloudFrontOriginAccessIdentity",
|
|
||||||
"cloudfront:CreateDistribution",
|
|
||||||
"cloudfront:CreateInvalidation",
|
|
||||||
"cloudfront:GetDistribution",
|
|
||||||
"cloudfront:GetDistributionConfig",
|
|
||||||
"cloudfront:ListCloudFrontOriginAccessIdentities",
|
|
||||||
"cloudfront:ListDistributions",
|
|
||||||
"cloudfront:ListDistributionsByLambdaFunction",
|
|
||||||
"cloudfront:ListDistributionsByWebACLId",
|
|
||||||
"cloudfront:ListFieldLevelEncryptionConfigs",
|
|
||||||
"cloudfront:ListFieldLevelEncryptionProfiles",
|
|
||||||
"cloudfront:ListInvalidations",
|
|
||||||
"cloudfront:ListPublicKeys",
|
|
||||||
"cloudfront:ListStreamingDistributions",
|
|
||||||
"cloudfront:UpdateDistribution",
|
|
||||||
"iam:AttachRolePolicy",
|
|
||||||
"iam:CreateRole",
|
|
||||||
"iam:CreateServiceLinkedRole",
|
|
||||||
"iam:GetRole",
|
|
||||||
"iam:PassRole",
|
|
||||||
"lambda:CreateFunction",
|
|
||||||
"lambda:EnableReplication",
|
|
||||||
"lambda:DeleteFunction", // only for custom domains
|
|
||||||
"lambda:GetFunction",
|
|
||||||
"lambda:GetFunctionConfiguration",
|
|
||||||
"lambda:PublishVersion",
|
|
||||||
"lambda:UpdateFunctionCode",
|
|
||||||
"lambda:UpdateFunctionConfiguration",
|
|
||||||
"route53:ChangeResourceRecordSets", // only for custom domains
|
|
||||||
"route53:ListHostedZonesByName",
|
|
||||||
"route53:ListResourceRecordSets", // only for custom domains
|
|
||||||
"s3:CreateBucket",
|
|
||||||
"s3:GetAccelerateConfiguration",
|
|
||||||
"s3:GetObject", // only if persisting state to S3 for CI/CD
|
|
||||||
"s3:HeadBucket",
|
|
||||||
"s3:ListBucket",
|
|
||||||
"s3:PutAccelerateConfiguration",
|
|
||||||
"s3:PutBucketPolicy",
|
|
||||||
"s3:PutObject"
|
|
||||||
```
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { LambdaAtEdgeConfig, LambdaAtEdgeType } from '../../types';
|
import { LambdaAtEdgeConfig, LambdaAtEdge } from '../../types';
|
||||||
|
|
||||||
const validLambdaTriggers = [
|
const validLambdaTriggers = [
|
||||||
'viewer-request',
|
'viewer-request',
|
||||||
|
|
@ -9,7 +9,7 @@ const validLambdaTriggers = [
|
||||||
|
|
||||||
const triggersAllowedBody = ['viewer-request', 'origin-request'];
|
const triggersAllowedBody = ['viewer-request', 'origin-request'];
|
||||||
|
|
||||||
const makeCacheItem = (eventType: string, lambdaConfig: LambdaAtEdgeType) => {
|
const makeCacheItem = (eventType: string, lambdaConfig: string | LambdaAtEdgeConfig) => {
|
||||||
let arn, includeBody;
|
let arn, includeBody;
|
||||||
if (typeof lambdaConfig === 'string') {
|
if (typeof lambdaConfig === 'string') {
|
||||||
arn = lambdaConfig;
|
arn = lambdaConfig;
|
||||||
|
|
@ -29,11 +29,8 @@ const makeCacheItem = (eventType: string, lambdaConfig: LambdaAtEdgeType) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// adds lambda@edge to cache behavior passed
|
// adds lambda@edge to cache behavior passed
|
||||||
const addLambdaAtEdgeToCacheBehavior = (
|
const addLambdaAtEdgeToCacheBehavior = (cacheBehavior: any, lambdaAtEdge: LambdaAtEdge = {}) => {
|
||||||
cacheBehavior: any,
|
Object.keys(lambdaAtEdge).forEach((eventType) => {
|
||||||
lambdaAtEdgeConfig: LambdaAtEdgeConfig = {}
|
|
||||||
) => {
|
|
||||||
Object.keys(lambdaAtEdgeConfig).forEach((eventType) => {
|
|
||||||
if (!validLambdaTriggers.includes(eventType)) {
|
if (!validLambdaTriggers.includes(eventType)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`"${eventType}" is not a valid lambda trigger. See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-cloudfront-trigger-events.html for valid event types.`
|
`"${eventType}" is not a valid lambda trigger. See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-cloudfront-trigger-events.html for valid event types.`
|
||||||
|
|
@ -41,7 +38,7 @@ const addLambdaAtEdgeToCacheBehavior = (
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheBehavior.LambdaFunctionAssociations.Items.push(
|
cacheBehavior.LambdaFunctionAssociations.Items.push(
|
||||||
makeCacheItem(eventType, lambdaAtEdgeConfig[eventType])
|
makeCacheItem(eventType, lambdaAtEdge[eventType])
|
||||||
);
|
);
|
||||||
|
|
||||||
cacheBehavior.LambdaFunctionAssociations.Quantity =
|
cacheBehavior.LambdaFunctionAssociations.Quantity =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { CloudFront } from 'aws-sdk';
|
import { CloudFront } from 'aws-sdk';
|
||||||
|
|
||||||
import { Forward, PathPatternConfig } from '../../types';
|
import { Forward } from '../../types';
|
||||||
|
|
||||||
const forwardDefaults = {
|
const forwardDefaults = {
|
||||||
cookies: 'none',
|
cookies: 'none',
|
||||||
|
|
@ -12,7 +12,7 @@ const forwardDefaults = {
|
||||||
* @param defaults Default framework values (default cache behavior and custom cache behavior have different default values)
|
* @param defaults Default framework values (default cache behavior and custom cache behavior have different default values)
|
||||||
* @returns Object
|
* @returns Object
|
||||||
*/
|
*/
|
||||||
export default function getForwardedValues(config: Forward = {}, defaults?: PathPatternConfig) {
|
export default function getForwardedValues(config: Forward = {}, defaults?: Forward) {
|
||||||
const defaultValues = { ...forwardDefaults, ...defaults };
|
const defaultValues = { ...forwardDefaults, ...defaults };
|
||||||
const {
|
const {
|
||||||
cookies,
|
cookies,
|
||||||
|
|
@ -23,7 +23,7 @@ export default function getForwardedValues(config: Forward = {}, defaults?: Path
|
||||||
|
|
||||||
// Cookies
|
// Cookies
|
||||||
const forwardCookies: CloudFront.CookiePreference = {
|
const forwardCookies: CloudFront.CookiePreference = {
|
||||||
Forward: defaultValues.cookies,
|
Forward: defaultValues.cookies as string,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof cookies === 'string') {
|
if (typeof cookies === 'string') {
|
||||||
|
|
|
||||||
24
packages/aws-cloudfront/types.d.ts
vendored
24
packages/aws-cloudfront/types.d.ts
vendored
|
|
@ -15,30 +15,24 @@ type PathPatternConfig = {
|
||||||
fieldLevelEncryptionId?: string;
|
fieldLevelEncryptionId?: string;
|
||||||
forward?: Forward;
|
forward?: Forward;
|
||||||
viewerCertificate?: ViewerCertificate;
|
viewerCertificate?: ViewerCertificate;
|
||||||
cookies?: string;
|
'lambda@edge'?: LambdaAtEdge;
|
||||||
queryString?: boolean;
|
|
||||||
'lambda@edge'?: LambdaAtEdgeConfig;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ViewerCertificate = {
|
type ViewerCertificate = {
|
||||||
ACMCertificateArn: string;
|
ACMCertificateArn: string;
|
||||||
SSLSupportMethod: string;
|
SSLSupportMethod: string;
|
||||||
minimumProtocolVersion: string;
|
minimumProtocolVersion: string;
|
||||||
certificate: string;
|
};
|
||||||
certificateSource: string;
|
|
||||||
|
type LambdaAtEdge = {
|
||||||
|
[type: string]: string | LambdaAtEdgeConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LambdaAtEdgeConfig = {
|
type LambdaAtEdgeConfig = {
|
||||||
[type: string]: LambdaAtEdgeType;
|
arn: string;
|
||||||
|
includeBody: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LambdaAtEdgeType =
|
|
||||||
| string
|
|
||||||
| {
|
|
||||||
arn: string;
|
|
||||||
includeBody: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Origin = {
|
type Origin = {
|
||||||
url: string;
|
url: string;
|
||||||
private?: boolean;
|
private?: boolean;
|
||||||
|
|
@ -47,8 +41,8 @@ type Origin = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type Forward = {
|
type Forward = {
|
||||||
cookies?: string[];
|
cookies?: string | string[];
|
||||||
queryString?: string;
|
queryString?: boolean;
|
||||||
headers?: string[];
|
headers?: string[];
|
||||||
queryStringCacheKeys?: string[];
|
queryStringCacheKeys?: string[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@ export const REQUEST_LAMBDA_CODE_DIR = `${BUILD_DIR}/request-lambda`;
|
||||||
|
|
||||||
class AwsComponent extends Component {
|
class AwsComponent extends Component {
|
||||||
async default(inputs: AwsComponentInputs = {}): Promise<DeploymentResult> {
|
async default(inputs: AwsComponentInputs = {}): Promise<DeploymentResult> {
|
||||||
if (inputs.buildOptions !== false) {
|
await this.build(inputs);
|
||||||
await this.build(inputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.deploy(inputs);
|
return this.deploy(inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,49 +102,45 @@ class AwsComponent extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async build(inputs: AwsComponentInputs = {}): Promise<void> {
|
async build({ build, nextConfigDir }: AwsComponentInputs = {}): Promise<void> {
|
||||||
const nextConfigPath = inputs.nextConfigDir ? resolve(inputs.nextConfigDir) : process.cwd();
|
const nextConfigPath = nextConfigDir ? resolve(nextConfigDir) : process.cwd();
|
||||||
const buildCwd =
|
const builder = new Builder(nextConfigPath, join(nextConfigPath, BUILD_DIR), {
|
||||||
typeof inputs.buildOptions === 'boolean' ||
|
cmd: build?.cmd || 'node_modules/.bin/next',
|
||||||
typeof inputs.buildOptions === 'undefined' ||
|
cwd: build?.cwd ? resolve(build.cwd) : nextConfigPath,
|
||||||
!inputs.buildOptions.cwd
|
args: build?.args || ['build'],
|
||||||
? nextConfigPath
|
});
|
||||||
: resolve(inputs.buildOptions.cwd);
|
|
||||||
const buildConfig: BuildOptions = {
|
|
||||||
enabled: inputs.buildOptions
|
|
||||||
? // @ts-ignore
|
|
||||||
inputs.buildOptions !== false && inputs.buildOptions.enabled !== false
|
|
||||||
: true,
|
|
||||||
cmd: 'node_modules/.bin/next',
|
|
||||||
args: ['build'],
|
|
||||||
...(typeof inputs.buildOptions === 'object' ? inputs.buildOptions : {}),
|
|
||||||
cwd: buildCwd,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (buildConfig.enabled) {
|
this.context.instance.metrics.status.message = 'Building';
|
||||||
const builder = new Builder(nextConfigPath, join(nextConfigPath, BUILD_DIR), {
|
|
||||||
cmd: buildConfig.cmd,
|
|
||||||
cwd: buildConfig.cwd,
|
|
||||||
args: buildConfig.args,
|
|
||||||
});
|
|
||||||
|
|
||||||
await builder.build(this.context.instance.debugMode ? this.context.debug : undefined);
|
await builder.build(this.context.instance.debugMode ? this.context.debug : undefined);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deploy(inputs: AwsComponentInputs = {}): Promise<DeploymentResult> {
|
async deploy({
|
||||||
const nextConfigPath = inputs.nextConfigDir ? resolve(inputs.nextConfigDir) : process.cwd();
|
nextConfigDir,
|
||||||
|
nextStaticDir,
|
||||||
|
bucketRegion,
|
||||||
|
bucketName,
|
||||||
|
cloudfront,
|
||||||
|
policy,
|
||||||
|
publicDirectoryCache,
|
||||||
|
domain,
|
||||||
|
domainType,
|
||||||
|
...inputs
|
||||||
|
}: AwsComponentInputs = {}): Promise<DeploymentResult> {
|
||||||
|
this.context.instance.metrics.status.message = 'Deploying';
|
||||||
|
|
||||||
const nextStaticPath = inputs.nextStaticDir ? resolve(inputs.nextStaticDir) : nextConfigPath;
|
const nextConfigPath = nextConfigDir ? resolve(nextConfigDir) : process.cwd();
|
||||||
|
|
||||||
const customCloudFrontConfig: Record<string, any> = inputs.cloudfrontOptions || {};
|
const nextStaticPath = nextStaticDir ? resolve(nextStaticDir) : nextConfigPath;
|
||||||
const bucketRegion = inputs.bucketRegion || 'us-east-1';
|
|
||||||
|
const customCloudFrontConfig: Record<string, any> = cloudfront || {};
|
||||||
|
const calculatedBucketRegion = bucketRegion || 'us-east-1';
|
||||||
|
|
||||||
const [defaultBuildManifest] = await Promise.all([
|
const [defaultBuildManifest] = await Promise.all([
|
||||||
this.readRequestLambdaBuildManifest(nextConfigPath),
|
this.readRequestLambdaBuildManifest(nextConfigPath),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [bucket, cloudFront, requestEdgeLambda] = await Promise.all([
|
const [bucket, AwsCloudFront, requestEdgeLambda] = await Promise.all([
|
||||||
this.load('@next-deploy/aws-s3'),
|
this.load('@next-deploy/aws-s3'),
|
||||||
this.load('@next-deploy/aws-cloudfront'),
|
this.load('@next-deploy/aws-cloudfront'),
|
||||||
this.load('@next-deploy/aws-lambda', 'requestEdgeLambda'),
|
this.load('@next-deploy/aws-lambda', 'requestEdgeLambda'),
|
||||||
|
|
@ -155,8 +148,8 @@ class AwsComponent extends Component {
|
||||||
|
|
||||||
const bucketOutputs = await bucket({
|
const bucketOutputs = await bucket({
|
||||||
accelerated: true,
|
accelerated: true,
|
||||||
name: inputs.bucketName,
|
name: bucketName,
|
||||||
region: bucketRegion,
|
region: calculatedBucketRegion,
|
||||||
});
|
});
|
||||||
|
|
||||||
await AwsS3.uploadStaticAssets({
|
await AwsS3.uploadStaticAssets({
|
||||||
|
|
@ -164,7 +157,7 @@ class AwsComponent extends Component {
|
||||||
nextConfigDir: nextConfigPath,
|
nextConfigDir: nextConfigPath,
|
||||||
nextStaticDir: nextStaticPath,
|
nextStaticDir: nextStaticPath,
|
||||||
credentials: this.context.credentials.aws,
|
credentials: this.context.credentials.aws,
|
||||||
publicDirectoryCache: inputs.publicDirectoryCache,
|
publicDirectoryCache: publicDirectoryCache,
|
||||||
});
|
});
|
||||||
|
|
||||||
const bucketUrl = `http://${bucketOutputs.name}.s3.${bucketRegion}.amazonaws.com`;
|
const bucketUrl = `http://${bucketOutputs.name}.s3.${bucketRegion}.amazonaws.com`;
|
||||||
|
|
@ -187,10 +180,10 @@ class AwsComponent extends Component {
|
||||||
|
|
||||||
// parse origins from inputs
|
// parse origins from inputs
|
||||||
let inputOrigins: any = [];
|
let inputOrigins: any = [];
|
||||||
if (inputs.cloudfrontOptions && inputs.cloudfrontOptions.origins) {
|
if (cloudfront?.origins) {
|
||||||
const origins = inputs.cloudfrontOptions.origins as string[];
|
const origins = cloudfront.origins as string[];
|
||||||
inputOrigins = origins.map(expandRelativeUrls);
|
inputOrigins = origins.map(expandRelativeUrls);
|
||||||
delete inputs.cloudfrontOptions.origins;
|
delete cloudfront.origins;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloudFrontOrigins = [
|
const cloudFrontOrigins = [
|
||||||
|
|
@ -242,7 +235,7 @@ class AwsComponent extends Component {
|
||||||
role: {
|
role: {
|
||||||
service: ['lambda.amazonaws.com', 'edgelambda.amazonaws.com'],
|
service: ['lambda.amazonaws.com', 'edgelambda.amazonaws.com'],
|
||||||
policy: {
|
policy: {
|
||||||
arn: inputs.policy || 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole',
|
arn: policy || 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
memory: getLambdaInputValue('memory', 'requestLambda', 512) as number,
|
memory: getLambdaInputValue('memory', 'requestLambda', 512) as number,
|
||||||
|
|
@ -262,9 +255,9 @@ class AwsComponent extends Component {
|
||||||
|
|
||||||
let defaultCloudfrontInputs = {} as PathPatternConfig;
|
let defaultCloudfrontInputs = {} as PathPatternConfig;
|
||||||
|
|
||||||
if (inputs.cloudfrontOptions && inputs.cloudfrontOptions.defaults) {
|
if (cloudfront && cloudfront.defaults) {
|
||||||
defaultCloudfrontInputs = inputs.cloudfrontOptions.defaults;
|
defaultCloudfrontInputs = cloudfront.defaults;
|
||||||
delete inputs.cloudfrontOptions.defaults;
|
delete cloudfront.defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate that the custom config paths match generated paths in the manifest
|
// validate that the custom config paths match generated paths in the manifest
|
||||||
|
|
@ -317,14 +310,10 @@ class AwsComponent extends Component {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// make sure that origin-response is not set.
|
|
||||||
// this is reserved for our usage
|
|
||||||
const defaultLambdaAtEdgeConfig = {
|
const defaultLambdaAtEdgeConfig = {
|
||||||
...(defaultCloudfrontInputs['lambda@edge'] || {}),
|
...(defaultCloudfrontInputs['lambda@edge'] || {}),
|
||||||
};
|
};
|
||||||
delete defaultLambdaAtEdgeConfig['origin-response'];
|
const cloudFrontOutputs = await AwsCloudFront({
|
||||||
|
|
||||||
const cloudFrontOutputs = await cloudFront({
|
|
||||||
defaults: {
|
defaults: {
|
||||||
ttl: 0,
|
ttl: 0,
|
||||||
...defaultCloudfrontInputs,
|
...defaultCloudfrontInputs,
|
||||||
|
|
@ -333,7 +322,6 @@ class AwsComponent extends Component {
|
||||||
queryString: true,
|
queryString: true,
|
||||||
...defaultCloudfrontInputs.forward,
|
...defaultCloudfrontInputs.forward,
|
||||||
},
|
},
|
||||||
// everything after here cant be overridden
|
|
||||||
allowedHttpMethods: ['HEAD', 'DELETE', 'POST', 'GET', 'OPTIONS', 'PUT', 'PATCH'],
|
allowedHttpMethods: ['HEAD', 'DELETE', 'POST', 'GET', 'OPTIONS', 'PUT', 'PATCH'],
|
||||||
'lambda@edge': {
|
'lambda@edge': {
|
||||||
...defaultLambdaAtEdgeConfig,
|
...defaultLambdaAtEdgeConfig,
|
||||||
|
|
@ -351,17 +339,17 @@ class AwsComponent extends Component {
|
||||||
credentials: this.context.credentials.aws,
|
credentials: this.context.credentials.aws,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { domain, subdomain } = getDomains(inputs.domain);
|
const { domain: calculatedDomain, subdomain } = getDomains(domain);
|
||||||
|
|
||||||
if (domain && subdomain) {
|
if (calculatedDomain && subdomain) {
|
||||||
const domainComponent = await this.load('@next-deploy/aws-domain');
|
const domainComponent = await this.load('@next-deploy/aws-domain');
|
||||||
const domainOutputs = await domainComponent({
|
const domainOutputs = await domainComponent({
|
||||||
privateZone: false,
|
privateZone: false,
|
||||||
domain,
|
domain: calculatedDomain,
|
||||||
subdomains: {
|
subdomains: {
|
||||||
[subdomain]: cloudFrontOutputs,
|
[subdomain]: cloudFrontOutputs,
|
||||||
},
|
},
|
||||||
domainType: inputs.domainType || 'both',
|
domainType: domainType || 'both',
|
||||||
defaultCloudfrontInputs,
|
defaultCloudfrontInputs,
|
||||||
});
|
});
|
||||||
appUrl = domainOutputs.domains[0];
|
appUrl = domainOutputs.domains[0];
|
||||||
|
|
|
||||||
2
packages/aws-component/types.d.ts
vendored
2
packages/aws-component/types.d.ts
vendored
|
|
@ -14,7 +14,7 @@ type AwsComponentInputs = BaseDeploymentOptions & {
|
||||||
description?: string | { [key in LambdaType]: string };
|
description?: string | { [key in LambdaType]: string };
|
||||||
policy?: string;
|
policy?: string;
|
||||||
domainType?: DomainType;
|
domainType?: DomainType;
|
||||||
cloudfrontOptions?: CloudFrontInputs;
|
cloudfront?: CloudFrontInputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LambdaType = 'requestLambda' | 'responseLambda';
|
type LambdaType = 'requestLambda' | 'responseLambda';
|
||||||
|
|
|
||||||
|
|
@ -393,8 +393,8 @@ export const addDomainToCloudfrontDistribution = async (
|
||||||
SSLSupportMethod: viewerCertificate?.SSLSupportMethod || 'sni-only',
|
SSLSupportMethod: viewerCertificate?.SSLSupportMethod || 'sni-only',
|
||||||
MinimumProtocolVersion:
|
MinimumProtocolVersion:
|
||||||
viewerCertificate?.minimumProtocolVersion || DEFAULT_MINIMUM_PROTOCOL_VERSION,
|
viewerCertificate?.minimumProtocolVersion || DEFAULT_MINIMUM_PROTOCOL_VERSION,
|
||||||
Certificate: viewerCertificate?.certificate || certificateArn,
|
Certificate: certificateArn,
|
||||||
CertificateSource: viewerCertificate?.certificateSource || 'acm',
|
CertificateSource: 'acm',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"compile": "tsc -p tsconfig.build.json"
|
"compile": "tsc -p tsconfig.build.json"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@next-deploy/aws-lambda-builder": "link:../aws-lambda-builder",
|
||||||
"typescript": "^3.9.6"
|
"typescript": "^3.9.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@next-deploy/aws-lambda-builder@link:.":
|
||||||
|
version "0.0.0"
|
||||||
|
uid ""
|
||||||
|
|
||||||
typescript@^3.9.6:
|
typescript@^3.9.6:
|
||||||
version "3.9.6"
|
version "3.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a"
|
||||||
|
|
|
||||||
|
|
@ -4,62 +4,52 @@ import { publish } from 'gh-pages';
|
||||||
import { emptyDir } from 'fs-extra';
|
import { emptyDir } from 'fs-extra';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
|
|
||||||
import build from './builder';
|
import builder from './builder';
|
||||||
import { GithubInputs, DeploymentResult } from '../types';
|
import { GithubInputs, DeploymentResult } from '../types';
|
||||||
|
|
||||||
class GithubComponent extends Component {
|
class GithubComponent extends Component {
|
||||||
async default(inputs: GithubInputs = {}): Promise<DeploymentResult> {
|
async default(inputs: GithubInputs = {}): Promise<DeploymentResult> {
|
||||||
if (inputs.buildOptions !== false) {
|
await this.build(inputs);
|
||||||
await this.build(inputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.deploy(inputs);
|
return this.deploy(inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
async build(inputs: GithubInputs = {}): Promise<void> {
|
async build({ build, nextConfigDir, domain }: GithubInputs = {}): Promise<void> {
|
||||||
const nextConfigPath = inputs.nextConfigDir ? resolve(inputs.nextConfigDir) : process.cwd();
|
this.context.instance.metrics.status.message = 'Building';
|
||||||
const buildCwd =
|
|
||||||
typeof inputs.buildOptions === 'boolean' ||
|
|
||||||
typeof inputs.buildOptions === 'undefined' ||
|
|
||||||
!inputs.buildOptions.cwd
|
|
||||||
? nextConfigPath
|
|
||||||
: resolve(inputs.buildOptions.cwd);
|
|
||||||
const buildConfig: BuildOptions = {
|
|
||||||
enabled: inputs.buildOptions
|
|
||||||
? // @ts-ignore
|
|
||||||
inputs.buildOptions !== false && inputs.buildOptions.enabled !== false
|
|
||||||
: true,
|
|
||||||
cmd: 'node_modules/.bin/next',
|
|
||||||
args: ['build'],
|
|
||||||
...(typeof inputs.buildOptions === 'object' ? inputs.buildOptions : {}),
|
|
||||||
cwd: buildCwd,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (buildConfig.enabled) {
|
const nextConfigPath = nextConfigDir ? resolve(nextConfigDir) : process.cwd();
|
||||||
await build(buildConfig, this.context.instance.debugMode ? this.context.debug : undefined);
|
|
||||||
|
|
||||||
if (inputs?.domain?.length) {
|
await builder(
|
||||||
const domain = getDomains(inputs.domain);
|
{
|
||||||
|
cmd: build?.cmd || 'node_modules/.bin/next',
|
||||||
|
cwd: build?.cwd ? resolve(build.cwd) : nextConfigPath,
|
||||||
|
args: build?.args || ['build'],
|
||||||
|
},
|
||||||
|
this.context.instance.debugMode ? this.context.debug : undefined
|
||||||
|
);
|
||||||
|
|
||||||
if (domain) {
|
if (domain?.length) {
|
||||||
writeFileSync('out/CNAME', domain);
|
const computedDomain = getComputedDomain(domain);
|
||||||
}
|
|
||||||
|
if (computedDomain) {
|
||||||
|
writeFileSync('out/CNAME', computedDomain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deploy(inputs: GithubInputs = {}): Promise<DeploymentResult> {
|
async deploy({ domain, publish: publishOptions }: GithubInputs = {}): Promise<DeploymentResult> {
|
||||||
|
this.context.instance.metrics.status.message = 'Deploying';
|
||||||
|
|
||||||
let outputs: DeploymentResult = {};
|
let outputs: DeploymentResult = {};
|
||||||
|
|
||||||
if (inputs?.domain?.length) {
|
if (domain?.length) {
|
||||||
const domain = getDomains(inputs.domain);
|
const computedDomain = getComputedDomain(domain);
|
||||||
outputs.appUrl = `https://${domain}`;
|
outputs.appUrl = `https://${computedDomain}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const publishPromise = new Promise((resolve, reject) => {
|
const publishPromise = new Promise((resolve, reject) => {
|
||||||
publish(
|
publish(
|
||||||
'out',
|
'out',
|
||||||
{ message: 'Next Deployment Update', dotfiles: true, ...inputs.publishOptions },
|
{ message: 'Next Deployment Update', dotfiles: true, ...publishOptions },
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
|
|
@ -93,7 +83,7 @@ class GithubComponent extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDomains(inputDomain: string | string[]): string | undefined {
|
function getComputedDomain(inputDomain: string | string[]): string | undefined {
|
||||||
let domain;
|
let domain;
|
||||||
|
|
||||||
if (typeof inputDomain === 'string') {
|
if (typeof inputDomain === 'string') {
|
||||||
|
|
|
||||||
2
packages/github/types.d.ts
vendored
2
packages/github/types.d.ts
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
import { PublishOptions } from 'gh-pages';
|
import { PublishOptions } from 'gh-pages';
|
||||||
|
|
||||||
export type GithubInputs = BaseDeploymentOptions & {
|
export type GithubInputs = BaseDeploymentOptions & {
|
||||||
publishOptions?: PublishOptions;
|
publish?: PublishOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DeploymentResult = {
|
type DeploymentResult = {
|
||||||
|
|
|
||||||
Reference in a new issue