Skip to content

Instantly share code, notes, and snippets.

@albanx
Last active May 29, 2021 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albanx/78fae254d2ea0cf601ff3d6359ffed99 to your computer and use it in GitHub Desktop.
Save albanx/78fae254d2ea0cf601ff3d6359ffed99 to your computer and use it in GitHub Desktop.
Full Deploy.js script
const execSync = require('child_process').execSync;
const AWS = require('aws-sdk');
const fs = require('fs');
const mime = require('mime');
const { version } = require('../package.json');
const CLOUDFRONT_ID = 'YOUR_CF_ID';
const S3_BUCKET_ID = 'BUCKET_NAME_IN_AWS_ACCOUNT';
const walkSync = dir => {
let results = [];
fs.readdirSync(dir).forEach(function(file) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat && stat.isDirectory()) {
results = results.concat(walkSync(filePath));
} else {
results.push(filePath);
}
});
return results;
};
const build = (buildDir) => {
execSync(`ng build --configuration production --build-optimizer --output-path=${buildDir}`, {
stdio: 'inherit',
});
};
const deployVersionOnS3 = (srcDir, dstDir, bucketName) => {
const s3 = new AWS.S3();
const filesToUpload = walkSync(srcDir);
return Promise.all(
filesToUpload.map((filePath) => {
return new Promise((resolve) => {
const bucketPath = filePath.split('\\').join('/').replace(srcDir, dstDir);
const params = {
Bucket: bucketName,
Key: bucketPath,
Body: fs.readFileSync(filePath),
ContentType: mime.getType(filePath),
// ACL: 'public-read'
};
s3.putObject(params, (err, data) => {
if (err) {
resolve(err);
console.log(err);
} else {
resolve();
console.log('Uploaded [' + filePath + '] => [' + bucketName + '/' + bucketPath + ']');
}
});
});
})
);
};
const getCFDistribution = () => {
return new Promise((res, rej) => {
const cloudfront = new AWS.CloudFront();
const params = {
Id: CLOUDFRONT_ID /* required */,
};
cloudfront.getDistribution(params, function (err, data) {
if (!err) {
res(data);
} else {
rej(err);
}
});
});
};
const updateOriginPathCF = async (OriginPath) => {
const { ETag, Distribution } = await getCFDistribution();
return new Promise((res, rej) => {
Distribution.DistributionConfig.Origins.Items[0].OriginPath = OriginPath;
const updatedDistribution = {
DistributionConfig: Distribution.DistributionConfig,
IfMatch: ETag,
Id: Distribution.Id
}
const cloudfront = new AWS.CloudFront();
cloudfront.updateDistribution(updatedDistribution, (err, data) => {
if (err) rej(err, err.stack);
// an error occurred
else res(data); // successful response
});
});
};
const invalidateCloudFrontCache = () => {
return new Promise((res, rej) => {
const cloudfront = new AWS.CloudFront();
const params = {
DistributionId: CLOUDFRONT_ID,
InvalidationBatch: {
CallerReference: Math.floor(Date.now() / 1000) + 't',
Paths: {
Quantity: 1,
Items: ['/*'],
},
},
};
cloudfront.createInvalidation(params, (err, data) => {
if (err) rej(err, err.stack);
else res(data);
});
});
};
const buildDir = `dist/prod/${version}`;
const destDir = `prod/${version}`;
const start = async () => {
console.log('Building...' + version);
build(buildDir, destDir + '/');
console.log(`Deploy on S3 ${destDir}...`);
await deployVersionOnS3(buildDir, destDir, S3_BUCKET_ID);
console.log(`Switching cloudfront to new version ${destDir}`);
await updateOriginPathCF(`/${destDir}`);
console.log(`Invalidating cloudfront cache`);
await invalidateCloudFrontCache();
console.log(`=========== VERSION ${version} successfully deplopyed online ===========`);
};
AWS.config.loadFromPath('./ci/aws_key_s3_frontend_deploy.json');
start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment