scripts/deploy.js (145 lines of code) (raw):
import config from '../project.config.js';
import AWS from 'aws-sdk';
import {listDirectories, listFiles} from './utils/fileSystem.js';
import path from 'path';
import ora from 'ora';
import fs from 'fs';
import { lookup } from 'mime-types';
import { buildAtoms } from './build.js';
import { exit } from 'process';
const args = process.argv.slice(2);
const live = (args[0] && args[0] === '--live') || false;
const preview = (args[0] && args[0] === '--preview') || false;
if (!live && !preview) {
console.error("The command 'npm run deploy' is deprecated. Please use 'npm run deploy:preview', or 'npm run deploy:live'")
exit();
}
const version = `v/${Date.now()}`;
const s3Path = `atoms/${config.path}`;
const buildPath = path.resolve('build');
const atomsPath = path.resolve('src/atoms');
const localAssetsPath = path.resolve('src/assets');
const spinner = ora();
const s3 = new AWS.S3();
const bucketName = 'gdn-cdn';
const cdnUrl = 'https://interactive.guim.co.uk';
const assetsPath = `${cdnUrl}/${s3Path}/assets/${version}`;
deploy().catch(error => {
if (error.name === "InvalidToken") {
spinner.fail('Your AWS credentials are invalid. Please get a new set of credentials from Janus: https://janus.gutools.co.uk/');
} else if (error.name === "ExpiredToken") {
spinner.fail('Your AWS credentials have expired. Please get a new set of credentials from Janus: https://janus.gutools.co.uk/');
} else {
spinner.fail();
console.error(error);
}
});
async function deploy() {
await buildAtoms(assetsPath);
// print empty line
console.log('');
await deployAssets();
const atoms = await listDirectories(atomsPath);
for (let atom of atoms) {
if (config.excludeFromBuild && config.excludeFromBuild.includes(atom)) {
spinner.start(`Skipping atom '${atom}'`)
spinner.succeed()
continue;
}
await deployAtom(atom);
}
}
async function deployAssets() {
spinner.start('Deploying assets')
let paths = await listFiles(localAssetsPath, { filter: ['.DS_Store', '.gitkeep'] });
for (let filePath of paths) {
const body = fs.createReadStream(filePath);
const relativePath = path.relative(localAssetsPath, filePath);
const key = path.join(s3Path, 'assets', version, relativePath);
await upload(body, key);
}
spinner.succeed('Assets deployed')
}
async function deployAtom(atomName) {
spinner.start(`Deploying atom '${atomName}'`)
const files = filesToDeploy(atomName);
for (let file of files) {
const body = file.body || fs.createReadStream(file.path);
await upload(body, file.key, file.params || {});
}
const atomURL = `https://content.guardianapis.com/atom/interactive/interactives/${config.path}/${atomName}`
spinner.succeed(`Atom '${atomName}' (${version}) deployed to: ${atomURL}`)
}
async function upload(body, key, params = {}) {
let defaultParams = {
Bucket: bucketName,
ACL: 'public-read',
CacheControl: 'max-age=31536000',
}
const explicitContentType = lookup(key);
if (explicitContentType) {
defaultParams.ContentType = explicitContentType;
}
let uploadParams = {
...defaultParams,
...params,
Key: key,
Body: body,
}
return s3.upload(uploadParams).promise()
}
function filesToDeploy(atomName) {
const pathForFile = (fileName) => {
return path.join(buildPath, atomName, fileName)
}
const versionedKeyForFile = (fileName) => {
return path.join(s3Path, atomName, version, fileName)
}
const keyForFile = (fileName) => {
return path.join(s3Path, atomName, fileName)
}
const mainJS = `
var el = document.createElement('script');
el.src = '${cdnUrl}/${s3Path}/${atomName}/${version}/app.js';
document.body.appendChild(el);
`;
const files = [{
path: pathForFile('app.js'),
key: versionedKeyForFile('app.js')
},
{
body: mainJS,
key: versionedKeyForFile('main.js')
},
{
path: pathForFile('style.css'),
key: versionedKeyForFile('main.css')
},
{
path: pathForFile('main.html'),
key: versionedKeyForFile('main.html')
},
{
body: version,
key: keyForFile('preview'),
params: {
CacheControl: 'max-age=30'
},
},
{
body: JSON.stringify(config),
key: keyForFile('config.json'),
params: {
CacheControl: 'max-age=30'
},
}];
if (live) {
files.push({
body: version,
key: keyForFile('live'),
params: {
CacheControl: 'max-age=30'
},
})
}
return files;
}