documenting AWS options, WIP making AWS deployments work again

This commit is contained in:
Egor 2020-07-14 23:08:46 -07:00
parent 5db32796f6
commit 6062d60b28
13 changed files with 137 additions and 212 deletions

4
.d.ts vendored
View file

@ -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[];
}; };

View file

@ -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

View file

@ -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"
```

View file

@ -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 =

View file

@ -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') {

View file

@ -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[];
}; };

View file

@ -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];

View file

@ -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';

View file

@ -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',
}, },
}, },
}; };

View file

@ -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"
} }
} }

View file

@ -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"

View file

@ -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') {

View file

@ -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 = {