Skip to content
This repository was archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
feat: add versions to static app deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
arantespp committed Dec 6, 2020
1 parent 881ae21 commit 33f9032
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 65 deletions.
61 changes: 36 additions & 25 deletions packages/cli/src/deploy/addDefaults.cloudFormation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,41 @@ const addLogGroupToResources = (
return template;
};

// const addEnvironmentsToLambdaResources = (
// template: CloudFormationTemplate,
// ): CloudFormationTemplate => {
// const environment = getEnvironment();

// const { Resources } = template;

// const resourcesEntries = Object.entries(Resources);

// resourcesEntries.forEach(([, resource]) => {
// if (resource.Type === 'AWS::Lambda::Function') {
// const { Properties } = resource;
// if (!Properties.Environment) {
// Properties.Environment = {};
// }
// if (!Properties.Environment.Variables) {
// Properties.Environment.Variables = {};
// }
// Properties.Environment.Variables.ENVIRONMENT = environment;
// }
// });

// return template;
// };
const addEnvironmentsToLambdaResources = (
template: CloudFormationTemplate,
): CloudFormationTemplate => {
const environment = getEnvironment();

const { Resources } = template;

const resourcesEntries = Object.entries(Resources);

resourcesEntries.forEach(([, resource]) => {
if (resource.Type === 'AWS::Lambda::Function') {
const { Properties } = resource;

/**
* Lambda@Edege does not support environment variables.
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-lambda-function-configuration
* Then every function that has "Lambda@Edge" in its description will not
* have the variables passed to Environment.Variables.
*/
if (((Properties.Description as string) || '').includes('Lambda@Edge')) {
return;
}

if (!Properties.Environment) {
Properties.Environment = {};
}
if (!Properties.Environment.Variables) {
Properties.Environment.Variables = {};
}
Properties.Environment.Variables.ENVIRONMENT = environment;
}
});

return template;
};

export const addDefaults = async ({
params,
Expand All @@ -149,7 +160,7 @@ export const addDefaults = async ({
const newTemplate = await [
addDefaultParametersToTemplate,
addLogGroupToResources,
// addEnvironmentsToLambdaResources,
addEnvironmentsToLambdaResources,
].reduce(async (acc, addFn) => addFn(await acc), Promise.resolve(template));

return {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/deploy/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ export const uploadDirectoryToS3 = async ({
groupOfFiles.map((file) =>
uploadFileToS3({
bucket,
key: path.relative(directory, file),
key: path.join(bucketKey, path.relative(directory, file)),
filePath: file,
}),
),
Expand Down
50 changes: 23 additions & 27 deletions packages/cli/src/deploy/staticApp/staticApp.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
* https://gist.github.com/jed/56b1f58297d374572bc51c59394c7e7f
*/
import { NAME } from '../../config';
import { CloudFormationTemplate, Resource, Output } from '../../utils';
import {
CloudFormationTemplate,
Resource,
Output,
getPackageVersion,
} from '../../utils';

const STATIC_APP_BUCKET_LOGICAL_ID = 'StaticBucket';

Expand Down Expand Up @@ -37,22 +42,23 @@ exports.handler = (event, context) => {
}
`.trim();

const LAMBDA_EDGE_ORIGIN_REQUEST_LOGICAL_ID = 'LambdaEdgeOriginRequest';
const LAMBDA_EDGE_VIEWER_REQUEST_LOGICAL_ID = 'LambdaEdgeOriginRequest';

const LAMBDA_EDGE_VERSION_ORIGIN_REQUEST_LOGICAL_ID =
const LAMBDA_EDGE_VERSION_VIEWER_REQUEST_LOGICAL_ID =
'LambdaEdgeVersionOriginRequest';

const LAMBDA_EDGE_ORIGIN_REQUEST_ZIP_FILE = `
const LAMBDA_EDGE_VIEWER_REQUEST_ZIP_FILE = `
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const uri = request.uri;
if (uri.endsWith('/')) {
if (request.uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.includes('.')) {
} else if (!request.uri.includes('.')) {
request.uri += '.html';
}
request.uri = "/${getPackageVersion()}" + request.uri;
callback(null, request);
};
`.trim();
Expand All @@ -62,12 +68,6 @@ const LAMBDA_EDGE_ORIGIN_RESPONSE_LOGICAL_ID = 'LambdaEdgeOriginResponse';
const LAMBDA_EDGE_VERSION_ORIGIN_RESPONSE_LOGICAL_ID =
'LambdaEdgeVersionOriginResponse';

/**
* Matches strings that:
* - contains substring '/static/'
*/
export const originCacheExpression = '/static/';

const defaultScp = [
"default-src 'self'",
"img-src 'self'",
Expand All @@ -82,8 +82,6 @@ const defaultScp = [
*
* - Add some headers to improve security
* {@link https://aws.amazon.com/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/}.
*
* @param param.spa tells if the static app is a SPA.
*/
export const getLambdaEdgeOriginResponseZipFile = ({
scp = defaultScp,
Expand All @@ -94,15 +92,13 @@ exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const response = event.Records[0].cf.response;
const headers = response.headers;
const cacheRegex = new RegExp('${originCacheExpression}');
const maxAge = cacheRegex.test(request.uri) ? 60 * 60 * 24 * 365 : 60;
const maxAge = 150;
headers['cache-control'] = [
{
key: 'Cache-Control',
value: \`public, max-age=\${maxAge}, immutable\`
value: \`max-age=\${maxAge}\`
}
];
headers['strict-transport-security'] = [
Expand Down Expand Up @@ -347,29 +343,29 @@ const getCloudFrontEdgeLambdas = ({
};

/**
* If not SPA, then add Lambda@Edge origin request, which handle the received
* If not SPA, then add Lambda@Edge viewer request, which handle the received
* URI and convert to final files to be retrieved from AWS S3.
*/
if (!spa) {
lambdaEdgeResources = {
...lambdaEdgeResources,
[LAMBDA_EDGE_ORIGIN_REQUEST_LOGICAL_ID]: {
[LAMBDA_EDGE_VIEWER_REQUEST_LOGICAL_ID]: {
Type: 'AWS::Lambda::Function',
Properties: {
Code: { ZipFile: LAMBDA_EDGE_ORIGIN_REQUEST_ZIP_FILE },
Description: 'Lambda@Edge function serving as origin request.',
Code: { ZipFile: LAMBDA_EDGE_VIEWER_REQUEST_ZIP_FILE },
Description: 'Lambda@Edge function serving as viewer request.',
Handler: 'index.handler',
MemorySize: 128,
Role: { 'Fn::GetAtt': `${LAMBDA_EDGE_IAM_ROLE_LOGICAL_ID}.Arn` },
Runtime: 'nodejs12.x',
Timeout: 5,
},
},
[LAMBDA_EDGE_VERSION_ORIGIN_REQUEST_LOGICAL_ID]: {
[LAMBDA_EDGE_VERSION_VIEWER_REQUEST_LOGICAL_ID]: {
Type: 'Custom::LatestLambdaVersion',
Properties: {
FunctionName: {
Ref: LAMBDA_EDGE_ORIGIN_REQUEST_LOGICAL_ID,
Ref: LAMBDA_EDGE_VIEWER_REQUEST_LOGICAL_ID,
},
Nonce: `${Date.now()}`,
ServiceToken: {
Expand Down Expand Up @@ -467,9 +463,9 @@ const getCloudFrontTemplate = ({
? []
: [
{
EventType: 'origin-request',
EventType: 'viewer-request',
LambdaFunctionARN: {
'Fn::GetAtt': `${LAMBDA_EDGE_VERSION_ORIGIN_REQUEST_LOGICAL_ID}.FunctionArn`,
'Fn::GetAtt': `${LAMBDA_EDGE_VERSION_VIEWER_REQUEST_LOGICAL_ID}.FunctionArn`,
},
},
]),
Expand Down
7 changes: 5 additions & 2 deletions packages/cli/src/deploy/staticApp/staticApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import { CloudFormation, CloudFront } from 'aws-sdk';
import log from 'npmlog';

import { getPackageVersion } from '../../utils';

import { cloudFormation, deploy } from '../cloudFormation';
import { uploadDirectoryToS3, emptyS3Directory } from '../s3';
import { getStackName } from '../stackName';
Expand Down Expand Up @@ -32,8 +34,9 @@ export const uploadBuiltAppToS3 = async ({
buildFolder: string;
bucket: string;
}) => {
await emptyS3Directory({ bucket });
await uploadDirectoryToS3({ bucket, directory });
const version = getPackageVersion();
await emptyS3Directory({ bucket, directory: version });
await uploadDirectoryToS3({ bucket, bucketKey: version, directory });
};

export const invalidateCloudFront = async ({
Expand Down
1 change: 0 additions & 1 deletion packages/website/api/vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ export { getLambdaLayerTemplate } from 'carlin/dist/deploy/lambdaLayer';
export {
getLambdaEdgeOriginResponseZipFile,
getStaticAppTemplate,
originCacheExpression,
} from 'carlin/dist/deploy/staticApp/staticApp.template';
11 changes: 2 additions & 9 deletions packages/website/pages/docs/usage/deploy-static-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const getStaticProps = async () => {
})();

const cloudfront = (() => {
const options = { cloudfront: true, spa: false };
const options = { cloudfront: true, spa: false, scp: [] };
const template = getJsonYamlTemplates(
apiVars.getStaticAppTemplate(options),
);
Expand All @@ -31,7 +31,6 @@ export const getStaticProps = async () => {
'deploy/staticApp/staticApp.template.js',
originCacheExpression: 'deploy/staticApp/staticApp.template.js',
});
const { originCacheExpression } = apiVars;
const getLambdaEdgeOriginResponseZipFile = apiVars.getLambdaEdgeOriginResponseZipFile(
options,
);
Expand All @@ -47,7 +46,6 @@ export const getStaticProps = async () => {
template,
comments,
customScp,
originCacheExpression,
getLambdaEdgeOriginResponseZipFile,
getLambdaEdgeOriginResponseZipFileWithScp,
};
Expand Down Expand Up @@ -90,12 +88,7 @@ const DocsUsageDeployStaticApp = ({ root, onlyS3, cloudfront }: Props) => {
functionality is explained below:
</Styled.p>
<CodeBlock className="js">
{[
cloudfront.comments.getLambdaEdgeOriginResponseZipFile,
'\n',
cloudfront.comments.originCacheExpression,
`const originCacheExpression = '${cloudfront.originCacheExpression}';`,
].join('\n')}
{[cloudfront.comments.getLambdaEdgeOriginResponseZipFile].join('\n')}
</CodeBlock>
<Styled.p>The Lambda@Edge code is show below:</Styled.p>
<CodeBlock className="js">
Expand Down

0 comments on commit 33f9032

Please sign in to comment.