diff --git a/.gitignore b/.gitignore index 23ba2cd4..dedf82a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules .DS_Store -aws.json +credentials.json *.mp4 !dist/blank.mp4 index-*.html diff --git a/.npmignore b/.npmignore index 6f9b5aae..32ff635b 100644 --- a/.npmignore +++ b/.npmignore @@ -2,7 +2,7 @@ demo .github .vscode *.code-workspace -aws.json +credentials.json bundles.json yarn.lock package-lock.json diff --git a/gulpfile.js b/gulpfile.js index 28909e27..2a8f6927 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -29,18 +29,12 @@ const sourcemaps = require('gulp-sourcemaps'); const uglify = require('gulp-uglify-es').default; const commonjs = require('rollup-plugin-commonjs'); const resolve = require('rollup-plugin-node-resolve'); +const FastlyPurge = require('fastly-purge'); +const through = require('through2'); const bundles = require('./bundles.json'); const pkg = require('./package.json'); -// Get AWS config -let aws = {}; -try { - aws = require('./aws.json'); //eslint-disable-line -} catch (e) { - // Do nothing -} - const minSuffix = '.min'; // Paths @@ -95,16 +89,18 @@ const browsers = ['> 1%']; // Babel config const babelrc = { - presets: [[ - 'env', - { - targets: { - browsers, + presets: [ + [ + 'env', + { + targets: { + browsers, + }, + useBuiltIns: true, + modules: false, }, - useBuiltIns: true, - modules: false, - }, - ]], + ], + ], plugins: ['external-helpers'], babelrc: false, exclude: 'node_modules/**', @@ -112,10 +108,9 @@ const babelrc = { // Clean out /dist gulp.task('clean', () => { - const dirs = [ - paths.plyr.output, - paths.demo.output, - ].map(dir => path.join(dir, '**/*')); + const dirs = [paths.plyr.output, paths.demo.output].map(dir => + path.join(dir, '**/*'), + ); // Don't delete the mp4 dirs.push(`!${path.join(paths.plyr.output, '**/*.mp4')}`); @@ -187,9 +182,11 @@ const build = { .src(paths[bundle].src.sprite) .pipe( svgmin({ - plugins: [{ - removeDesc: true, - }], + plugins: [ + { + removeDesc: true, + }, + ], }), ) .pipe(svgstore()) @@ -238,9 +235,21 @@ gulp.task('default', () => { // Publish a version to CDN and demo // -------------------------------------------- -// If aws is setup -if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { +// Get deployment config +let credentials = {}; +try { + credentials = require('./credentials.json'); //eslint-disable-line +} catch (e) { + // Do nothing +} + +// If deployment is setup +if ( + Object.keys(credentials).includes('cdn') && + Object.keys(credentials).includes('demo') +) { const { version } = pkg; + const { aws, fastly } = credentials; // Get branch info const branch = { @@ -248,10 +257,6 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { master: 'master', develop: 'develop', }; - const allowed = [ - branch.master, - branch.develop, - ]; const maxAge = 31536000; // 1 year const options = { @@ -264,7 +269,8 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { demo: { uploadPath: branch.current === branch.develop ? 'beta/' : null, headers: { - 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', + 'Cache-Control': + 'no-cache, no-store, must-revalidate, max-age=0', Vary: 'Accept-Encoding', }, }, @@ -273,27 +279,51 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { headers: { // http://stackoverflow.com/questions/2272835/amazon-s3-object-redirect 'x-amz-website-redirect-location': `/${ver}/${filename}`, - 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', + 'Cache-Control': + 'no-cache, no-store, must-revalidate, max-age=0', }, }; }, }; - const regex = '(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*).(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?'; + const regex = + '(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*).(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?'; const semver = new RegExp(`v${regex}`, 'gi'); const localPath = new RegExp('(../)?dist', 'gi'); const versionPath = `https://${aws.cdn.domain}/${version}`; const cdnpath = new RegExp(`${aws.cdn.domain}/${regex}/`, 'gi'); + const renameFile = rename(p => { + p.basename = p.basename.replace(minSuffix, ''); // eslint-disable-line + p.dirname = p.dirname.replace('.', version); // eslint-disable-line + }); + + // Check we're on the correct branch to deploy + const canDeploy = () => { + const allowed = [branch.master, branch.develop]; + + if (!allowed.includes(branch.current)) { + console.error( + `Must be on ${allowed.join(', ')} to publish! (current: ${ + branch.current + })`, + ); + + return false; + } + + return true; + }; + gulp.task('version', () => { + if (!canDeploy()) { + return null; + } + console.log(`Updating versions to '${version}'...`); // Replace versioned URLs in source - const files = [ - 'plyr.js', - 'plyr.polyfilled.js', - 'defaults.js', - ]; + const files = ['plyr.js', 'plyr.polyfilled.js', 'defaults.js']; return gulp .src(files.map(file => path.join(root, `src/js/${file}`))) @@ -304,8 +334,7 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { // Publish version to CDN bucket gulp.task('cdn', () => { - if (!allowed.includes(branch.current)) { - console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`); + if (!canDeploy()) { return null; } @@ -315,14 +344,15 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { return ( gulp .src(paths.upload) - .pipe( - rename(p => { - p.basename = p.basename.replace(minSuffix, ''); // eslint-disable-line - p.dirname = p.dirname.replace('.', version); // eslint-disable-line - }), - ) + .pipe(renameFile) // Remove min suffix from source map URL - .pipe(replace(/sourceMappingURL=([\w-?.]+)/, (match, p1) => `sourceMappingURL=${p1.replace(minSuffix, '')}`)) + .pipe( + replace( + /sourceMappingURL=([\w-?.]+)/, + (match, p1) => + `sourceMappingURL=${p1.replace(minSuffix, '')}`, + ), + ) .pipe( size({ showFiles: true, @@ -334,10 +364,36 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { ); }); + // Purge the fastly cache incase any 403/404 are cached + gulp.task('purge', () => { + const list = []; + + return gulp.src(paths.upload).pipe( + through.obj((file, enc, cb) => { + const filename = file.path.split('/').pop(); + list.push(`${versionPath}/${filename}`); + cb(null); + }), + ).on('end', () => { + const purge = new FastlyPurge(fastly.token); + + list.forEach(url => { + console.log(`Purging ${url}...`); + + purge.url(url, (error, result) => { + if (error) { + console.log(error); + } else if (result) { + console.log(result); + } + }); + }); + }); + }); + // Publish to demo bucket gulp.task('demo', () => { - if (!allowed.includes(branch.current)) { - console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`); + if (!canDeploy()) { return null; } @@ -399,22 +455,29 @@ if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) { })); }); */ - // Open the demo site to check it's sweet - gulp.task('open', () => { - console.log(`Opening ${aws.demo.domain}...`); - - // A file must be specified or gulp will skip the task - // Doesn't matter which file since we set the URL above - // Weird, I know... - return gulp.src([`${paths.demo.root}index.html`]).pipe( - open('', { - url: `http://${aws.demo.domain}`, + // Open the demo site to check it's ok + gulp.task('open', callback => { + gulp.src(__filename).pipe( + open({ + uri: `https://${aws.demo.domain}`, }), ); + + callback(); }); // Do everything - gulp.task('publish', callback => { - run('version', tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'cdn', 'demo', callback); - }); + gulp.task('deploy', () => + run( + 'version', + tasks.clean, + tasks.js, + tasks.sass, + tasks.sprite, + 'cdn', + 'purge', + 'demo', + 'open', + ), + ); } diff --git a/package.json b/package.json index 7c9a9963..ed942065 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "scripts": { "build": "gulp build", "lint": "eslint src/js && npm run-script remark", - "remark": "remark -f --use 'validate-links=repository:\"sampotts/plyr\"' '{,!(node_modules),.?**/}*.md'", + "remark": + "remark -f --use 'validate-links=repository:\"sampotts/plyr\"' '{,!(node_modules),.?**/}*.md'", "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { @@ -45,6 +46,7 @@ "eslint-config-airbnb-base": "^13.0.0", "eslint-config-prettier": "^2.9.0", "eslint-plugin-import": "^2.13.0", + "fastly-purge": "^1.0.1", "git-branch": "^2.0.1", "gulp": "^3.9.1", "gulp-autoprefixer": "^5.0.0", @@ -80,7 +82,8 @@ "stylelint-config-sass-guidelines": "^5.0.0", "stylelint-order": "^0.8.1", "stylelint-scss": "^3.1.3", - "stylelint-selector-bem-pattern": "^2.0.0" + "stylelint-selector-bem-pattern": "^2.0.0", + "through2": "^2.0.3" }, "dependencies": { "babel-polyfill": "^6.26.0", diff --git a/yarn.lock b/yarn.lock index c741eb41..a5973f66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2319,6 +2319,12 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fastly-purge@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fastly-purge/-/fastly-purge-1.0.1.tgz#3bdfe9ea1d0fbf2a65712f2f5fe2eca63fcb5960" + dependencies: + request "^2.55.0" + fault@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.2.tgz#c3d0fec202f172a3a4d414042ad2bb5e2a3ffbaa" @@ -5801,6 +5807,31 @@ request@2: tunnel-agent "^0.6.0" uuid "^3.1.0" +request@^2.55.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + request@~2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"