From 5516db22c3dd38a6bb3ec8674e36bcc8f9bba90c Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sun, 29 Mar 2020 11:36:44 +1100 Subject: [PATCH] Gulp file broken down --- gulpfile.js | 518 +----------------------------------------------- tasks/build.js | 227 +++++++++++++++++++++ tasks/deploy.js | 272 +++++++++++++++++++++++++ 3 files changed, 501 insertions(+), 516 deletions(-) create mode 100644 tasks/build.js create mode 100644 tasks/deploy.js diff --git a/gulpfile.js b/gulpfile.js index 66966617..e1ebe778 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,522 +1,8 @@ // ========================================================================== // Gulp build script // ========================================================================== -/* eslint no-console: "off" */ -const path = require('path'); const gulp = require('gulp'); -// ------------------------------------ -// JavaScript -// ------------------------------------ -const terser = require('gulp-terser'); -const rollup = require('gulp-better-rollup'); -const babel = require('rollup-plugin-babel'); -const commonjs = require('rollup-plugin-commonjs'); -const resolve = require('rollup-plugin-node-resolve'); -// ------------------------------------ -// CSS -// ------------------------------------ -const sass = require('gulp-sass'); -const clean = require('gulp-clean-css'); -const prefix = require('gulp-autoprefixer'); -// ------------------------------------ -// Images -// ------------------------------------ -const svgstore = require('gulp-svgstore'); -const imagemin = require('gulp-imagemin'); -// ------------------------------------ -// Utils -// ------------------------------------ -const del = require('del'); -const filter = require('gulp-filter'); -const header = require('gulp-header'); -const gitbranch = require('git-branch'); -const rename = require('gulp-rename'); -const replace = require('gulp-replace'); -const ansi = require('ansi-colors'); -const log = require('fancy-log'); -const open = require('gulp-open'); -const plumber = require('gulp-plumber'); -const size = require('gulp-size'); -const sourcemaps = require('gulp-sourcemaps'); -const through = require('through2'); -const browserSync = require('browser-sync').create(); -// ------------------------------------ -// Deployment -// ------------------------------------ -const aws = require('aws-sdk'); -const publish = require('gulp-awspublish'); -const FastlyPurge = require('fastly-purge'); -// ------------------------------------ -// Configs -// ------------------------------------ -const pkg = require('./package.json'); -const build = require('./build.json'); -const deploy = require('./deploy.json'); -// ------------------------------------ -// Info from package -// ------------------------------------ -const { browserslist: browsers, version } = pkg; -const minSuffix = '.min'; +const HubRegistry = require('gulp-hub'); -// Get AWS config -Object.values(deploy).forEach(target => { - Object.assign(target, { - publisher: publish.create({ - region: target.region, - params: { - Bucket: target.bucket, - }, - credentials: new aws.SharedIniFileCredentials({ profile: 'plyr' }), - }), - }); -}); - -// Paths -const paths = { - plyr: { - // Source paths - src: { - sass: path.join(__dirname, 'src/sass/**/*.scss'), - js: path.join(__dirname, 'src/js/**/*.js'), - sprite: path.join(__dirname, 'src/sprite/*.svg'), - }, - - // Output paths - output: path.join(__dirname, 'dist/'), - }, - demo: { - // Source paths - src: { - sass: path.join(__dirname, 'demo/src/sass/**/*.scss'), - js: path.join(__dirname, 'demo/src/js/**/*.js'), - }, - - // Output paths - output: path.join(__dirname, 'demo/dist/'), - - // Demo - root: path.join(__dirname, 'demo/'), - }, - upload: [ - path.join(__dirname, `dist/*${minSuffix}.*`), - path.join(__dirname, 'dist/*.css'), - path.join(__dirname, 'dist/*.svg'), - path.join(__dirname, `demo/dist/*${minSuffix}.*`), - path.join(__dirname, 'demo/dist/*.css'), - path.join(__dirname, 'demo/dist/*.svg'), - ], -}; - -// Task arrays -const tasks = { - css: [], - js: [], - sprite: [], - clean: 'clean', -}; - -// Size plugin -const sizeOptions = { showFiles: true, gzip: true }; - -// Clean out /dist -gulp.task(tasks.clean, done => { - 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')}`); - - del(dirs); - - done(); -}); - -// JavaScript -Object.entries(build.js).forEach(([filename, entry]) => { - const { dist, formats, namespace, polyfill, src } = entry; - - formats.forEach(format => { - const name = `js:${filename}:${format}`; - const extension = format === 'es' ? 'mjs' : 'js'; - tasks.js.push(name); - - gulp.task(name, () => - gulp - .src(src) - .pipe(plumber()) - .pipe(sourcemaps.init()) - .pipe( - rollup( - { - plugins: [ - resolve(), - commonjs(), - babel({ - presets: [ - [ - '@babel/env', - { - // debug: true, - useBuiltIns: polyfill ? 'usage' : false, - corejs: polyfill ? 3 : undefined, - }, - ], - ], - babelrc: false, - exclude: [/\/core-js\//], - }), - ], - }, - { - name: namespace, - format, - }, - ), - ) - .pipe(header('typeof navigator === "object" && ')) // "Support" SSR (#935) - .pipe( - rename({ - extname: `.${extension}`, - }), - ) - .pipe(gulp.dest(dist)) - .pipe(filter(`**/*.${extension}`)) - .pipe(terser()) - .pipe(rename({ suffix: minSuffix })) - .pipe(size(sizeOptions)) - .pipe(sourcemaps.write('')) - .pipe(gulp.dest(dist)), - ); - }); -}); - -// CSS -Object.entries(build.css).forEach(([filename, entry]) => { - const { dist, src } = entry; - const name = `css:${filename}`; - tasks.css.push(name); - - gulp.task(name, () => - gulp - .src(src) - .pipe(plumber()) - .pipe(sass()) - .pipe( - prefix(browsers, { - cascade: false, - }), - ) - .pipe(clean()) - .pipe(size(sizeOptions)) - .pipe(gulp.dest(dist)), - ); -}); - -// SVG Sprites -Object.entries(build.sprite).forEach(([filename, entry]) => { - const { dist, src } = entry; - const name = `sprite:${filename}`; - tasks.sprite.push(name); - - gulp.task(name, () => - gulp - .src(src) - .pipe(plumber()) - .pipe( - imagemin([ - imagemin.svgo({ - plugins: [{ removeViewBox: false }], - }), - ]), - ) - .pipe(svgstore()) - .pipe(rename({ basename: path.parse(filename).name })) - .pipe(size(sizeOptions)) - .pipe(gulp.dest(dist)), - ); -}); - -// Build all JS -gulp.task('js', () => gulp.parallel(...tasks.js)); - -// Watch for file changes -gulp.task('watch', () => { - // Plyr core - gulp.watch(paths.plyr.src.js, gulp.parallel(...tasks.js)); - gulp.watch(paths.plyr.src.sass, gulp.parallel(...tasks.css)); - gulp.watch(paths.plyr.src.sprite, gulp.parallel(...tasks.sprite)); - - // Demo - gulp.watch(paths.demo.src.js, gulp.parallel(...tasks.js)); - gulp.watch(paths.demo.src.sass, gulp.parallel(...tasks.css)); -}); - -// Serve via browser sync -gulp.task('serve', () => - browserSync.init({ - server: { - baseDir: paths.demo.root, - }, - notify: false, - watch: true, - ghostMode: false, - }), -); - -// Build distribution -gulp.task('build', gulp.series(tasks.clean, gulp.parallel(...tasks.js, ...tasks.css, ...tasks.sprite))); - -// Default gulp task -gulp.task('default', gulp.series('build', gulp.parallel('serve', 'watch'))); - -// Publish a version to CDN and demo -// -------------------------------------------- -// Get deployment config -let credentials = {}; -try { - credentials = require('./credentials.json'); //eslint-disable-line -} catch (e) { - // Do nothing -} - -// Get branch info -const branch = { - current: gitbranch.sync(), - master: 'master', - beta: 'beta', -}; - -const maxAge = 31536000; // 1 year -const options = { - cdn: { - headers: { - 'Cache-Control': `max-age=${maxAge}`, - }, - }, - demo: { - uploadPath: branch.current === branch.beta ? '/beta' : null, - headers: { - 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', - }, - }, - symlinks(ver, filename) { - return { - 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', - }, - }; - }, -}; - -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://${deploy.cdn.domain}/${version}`; -const cdnpath = new RegExp(`${deploy.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.beta]; - - if (!allowed.includes(branch.current)) { - console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`); - - return false; - } - - return true; -}; - -gulp.task('version', done => { - if (!canDeploy()) { - done(); - return null; - } - - const { domain } = deploy.cdn; - - log(`Uploading ${ansi.green.bold(version)} to ${ansi.cyan(domain)}...`); - - // Replace versioned URLs in source - const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js']; - - return gulp - .src( - files.map(file => path.join(__dirname, `src/js/${file}`)), - { base: '.' }, - ) - .pipe(replace(semver, `v${version}`)) - .pipe(replace(cdnpath, `${domain}/${version}/`)) - .pipe(gulp.dest('./')); -}); - -// Publish version to CDN bucket -gulp.task('cdn', done => { - if (!canDeploy()) { - done(); - return null; - } - - const { domain, publisher } = deploy.cdn; - - if (!publisher) { - throw new Error('No publisher instance. Check AWS configuration.'); - } - - log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); - - // Upload to CDN - return ( - gulp - .src(paths.upload) - .pipe(renameFile) - // Remove min suffix from source map URL - .pipe( - replace( - /sourceMappingURL=([\w-?.]+)/, - (match, filename) => `sourceMappingURL=${filename.replace(minSuffix, '')}`, - ), - ) - .pipe(size(sizeOptions)) - .pipe(replace(localPath, versionPath)) - .pipe(publisher.publish(options.cdn.headers)) - .pipe(publish.reporter()) - ); -}); - -// Purge the fastly cache incase any 403/404 are cached -gulp.task('purge', () => { - if (!Object.keys(credentials).includes('fastly')) { - throw new Error('Fastly credentials required to purge cache.'); - } - - const { fastly } = credentials; - const list = []; - - return gulp - .src(paths.upload) - .pipe( - through.obj((file, enc, cb) => { - const filename = file.path.split('/').pop(); - list.push(`${versionPath}/${filename.replace(minSuffix, '')}`); - cb(null); - }), - ) - .on('end', () => { - const purge = new FastlyPurge(fastly.token); - - list.forEach(url => { - log(`Purging ${ansi.cyan(url)}...`); - - purge.url(url, (error, result) => { - if (error) { - log.error(error); - } else if (result) { - log(result); - } - }); - }); - }); -}); - -// Publish to demo bucket -gulp.task('demo', done => { - if (!canDeploy()) { - done(); - return null; - } - - const { publisher } = deploy.demo; - const { domain } = deploy.cdn; - - if (!publisher) { - throw new Error('No publisher instance. Check AWS configuration.'); - } - - log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); - - // Replace versioned files in readme.md - gulp.src([`${__dirname}/readme.md`]) - .pipe(replace(cdnpath, `${domain}/${version}/`)) - .pipe(gulp.dest(__dirname)); - - // Replace local file paths with remote paths in demo HTML - // e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js" - const index = `${paths.demo.root}index.html`; - const error = `${paths.demo.root}error.html`; - const pages = [index]; - - if (branch.current === branch.master) { - pages.push(error); - } - - return gulp - .src(pages) - .pipe(replace(localPath, versionPath)) - .pipe( - rename(p => { - if (options.demo.uploadPath) { - // eslint-disable-next-line no-param-reassign - p.dirname += options.demo.uploadPath; - } - }), - ) - .pipe(publisher.publish(options.demo.headers)) - .pipe(publish.reporter()); -}); - -gulp.task('error', done => { - // Only update CDN for master (prod) - if (!canDeploy() || branch.current !== branch.master) { - done(); - return null; - } - - const { publisher } = deploy.cdn; - - if (!publisher) { - throw new Error('No publisher instance. Check AWS configuration.'); - } - - // Replace local file paths with remote paths in demo HTML - // e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js" - // Upload error.html to cdn - return gulp - .src(`${paths.demo.root}error.html`) - .pipe(replace(localPath, versionPath)) - .pipe(publisher.publish(options.demo.headers)) - .pipe(publish.reporter()); -}); - -// Open the demo site to check it's ok -gulp.task('open', () => { - const { domain } = deploy.demo; - - return gulp.src(__filename).pipe( - open({ - uri: `https://${domain}/${branch.current === branch.beta ? 'beta' : ''}`, - }), - ); -}); - -// Do everything -gulp.task( - 'deploy', - gulp.series( - 'version', - tasks.clean, - gulp.parallel(...tasks.js, ...tasks.css, ...tasks.sprite), - 'cdn', - 'demo', - 'purge', - 'open', - ), -); +gulp.registry(new HubRegistry(['tasks/*.js'])); diff --git a/tasks/build.js b/tasks/build.js new file mode 100644 index 00000000..797f67a7 --- /dev/null +++ b/tasks/build.js @@ -0,0 +1,227 @@ +/* eslint-disable import/no-extraneous-dependencies */ +// ========================================================================== +// Gulp build script +// ========================================================================== +/* eslint no-console: "off" */ + +const path = require('path'); +const gulp = require('gulp'); +// JavaScript +const terser = require('gulp-terser'); +const rollup = require('gulp-better-rollup'); +const babel = require('rollup-plugin-babel'); +const commonjs = require('rollup-plugin-commonjs'); +const resolve = require('rollup-plugin-node-resolve'); +// CSS +const sass = require('gulp-sass'); +const clean = require('gulp-clean-css'); +const prefix = require('gulp-autoprefixer'); +// Images +const svgstore = require('gulp-svgstore'); +const imagemin = require('gulp-imagemin'); +// Utils +const del = require('del'); +const filter = require('gulp-filter'); +const header = require('gulp-header'); +const rename = require('gulp-rename'); +const plumber = require('gulp-plumber'); +const size = require('gulp-size'); +const sourcemaps = require('gulp-sourcemaps'); +const browserSync = require('browser-sync').create(); +// Configs +const pkg = require('../package.json'); +const build = require('../build.json'); +// Info from package +const { browserslist: browsers } = pkg; +const minSuffix = '.min'; +// Paths +const root = path.join(__dirname, '..'); +const paths = { + plyr: { + // Source paths + src: { + sass: path.join(root, 'src/sass/**/*.scss'), + js: path.join(root, 'src/js/**/*.js'), + sprite: path.join(root, 'src/sprite/*.svg'), + }, + + // Output paths + output: path.join(root, 'dist/'), + }, + demo: { + // Source paths + src: { + sass: path.join(root, 'demo/src/sass/**/*.scss'), + js: path.join(root, 'demo/src/js/**/*.js'), + }, + + // Output paths + output: path.join(root, 'demo/dist/'), + + // Demo + root: path.join(root, 'demo/'), + }, +}; + +// Task lists +const tasks = { + css: [], + js: [], + sprite: [], +}; + +// Size plugin +const sizeOptions = { showFiles: true, gzip: true }; + +// Clean out /dist +gulp.task('clean', done => { + 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')}`); + + del(dirs); + + done(); +}); + +// JavaScript +Object.entries(build.js).forEach(([filename, entry]) => { + const { dist, formats, namespace, polyfill, src } = entry; + + formats.forEach(format => { + const name = `js:${filename}:${format}`; + const extension = format === 'es' ? 'mjs' : 'js'; + tasks.js.push(name); + + gulp.task(name, () => + gulp + .src(src) + .pipe(plumber()) + .pipe(sourcemaps.init()) + .pipe( + rollup( + { + plugins: [ + resolve(), + commonjs(), + babel({ + presets: [ + [ + '@babel/env', + { + // debug: true, + useBuiltIns: polyfill ? 'usage' : false, + corejs: polyfill ? 3 : undefined, + bugfixes: true, + }, + ], + ], + babelrc: false, + exclude: [/\/core-js\//], + }), + ], + }, + { + name: namespace, + format, + }, + ), + ) + .pipe(header('typeof navigator === "object" && ')) // "Support" SSR (#935) + .pipe( + rename({ + extname: `.${extension}`, + }), + ) + .pipe(gulp.dest(dist)) + .pipe(filter(`**/*.${extension}`)) + .pipe(terser()) + .pipe(rename({ suffix: minSuffix })) + .pipe(size(sizeOptions)) + .pipe(sourcemaps.write('')) + .pipe(gulp.dest(dist)), + ); + }); +}); + +// CSS +Object.entries(build.css).forEach(([filename, entry]) => { + const { dist, src } = entry; + const name = `css:${filename}`; + tasks.css.push(name); + + gulp.task(name, () => + gulp + .src(src) + .pipe(plumber()) + .pipe(sass()) + .pipe( + prefix(browsers, { + cascade: false, + }), + ) + .pipe(clean()) + .pipe(size(sizeOptions)) + .pipe(gulp.dest(dist)), + ); +}); + +// SVG Sprites +Object.entries(build.sprite).forEach(([filename, entry]) => { + const { dist, src } = entry; + const name = `sprite:${filename}`; + tasks.sprite.push(name); + + gulp.task(name, () => + gulp + .src(src) + .pipe(plumber()) + .pipe( + imagemin([ + imagemin.svgo({ + plugins: [{ removeViewBox: false }], + }), + ]), + ) + .pipe(svgstore()) + .pipe(rename({ basename: path.parse(filename).name })) + .pipe(size(sizeOptions)) + .pipe(gulp.dest(dist)), + ); +}); + +// Build all tasks +gulp.task('js', gulp.parallel(...tasks.js)); +gulp.task('css', gulp.parallel(...tasks.css)); +gulp.task('sprites', gulp.parallel(...tasks.sprite)); + +// Watch for file changes +gulp.task('watch', () => { + // Plyr core + gulp.watch(paths.plyr.src.js, gulp.parallel('js')); + gulp.watch(paths.plyr.src.sass, gulp.parallel('css')); + gulp.watch(paths.plyr.src.sprite, gulp.parallel('sprites')); + + // Demo + gulp.watch(paths.demo.src.js, gulp.parallel('js')); + gulp.watch(paths.demo.src.sass, gulp.parallel('css')); +}); + +// Serve via browser sync +gulp.task('serve', () => + browserSync.init({ + server: { + baseDir: paths.demo.root, + }, + notify: false, + watch: true, + ghostMode: false, + }), +); + +// Build distribution +gulp.task('build', gulp.series('clean', gulp.parallel('js', 'css', 'sprites'))); + +// Default gulp task +gulp.task('default', gulp.series('build', gulp.parallel('serve', 'watch'))); diff --git a/tasks/deploy.js b/tasks/deploy.js new file mode 100644 index 00000000..4ff94680 --- /dev/null +++ b/tasks/deploy.js @@ -0,0 +1,272 @@ +/* eslint-disable import/no-extraneous-dependencies */ +// ========================================================================== +// Publish a version to CDN and demo +// ========================================================================== +/* eslint no-console: "off" */ + +const path = require('path'); +const gulp = require('gulp'); +// Utils +const gitbranch = require('git-branch'); +const rename = require('gulp-rename'); +const replace = require('gulp-replace'); +const ansi = require('ansi-colors'); +const log = require('fancy-log'); +const open = require('gulp-open'); +const size = require('gulp-size'); +const through = require('through2'); +// Deployment +const aws = require('aws-sdk'); +const publish = require('gulp-awspublish'); +const FastlyPurge = require('fastly-purge'); +// Configs +const pkg = require('../package.json'); +const deploy = require('../deploy.json'); +// Info from package +const { version } = pkg; +const minSuffix = '.min'; + +// Get AWS config +Object.values(deploy).forEach(target => { + Object.assign(target, { + publisher: publish.create({ + region: target.region, + params: { + Bucket: target.bucket, + }, + credentials: new aws.SharedIniFileCredentials({ profile: 'plyr' }), + }), + }); +}); + +// Paths +const root = path.join(__dirname, '..'); +const paths = { + upload: [ + path.join(root, `dist/*${minSuffix}.*`), + path.join(root, 'dist/*.css'), + path.join(root, 'dist/*.svg'), + path.join(root, `demo/dist/*${minSuffix}.*`), + path.join(root, 'demo/dist/*.css'), + path.join(root, 'demo/dist/*.svg'), + ], +}; + +// Get credentials +let credentials = {}; +try { + credentials = require('../credentials.json'); //eslint-disable-line +} catch (e) { + // Do nothing +} + +// Get branch info +const branch = { + current: gitbranch.sync(), + master: 'master', + beta: 'beta', +}; + +const maxAge = 31536000; // 1 year +const options = { + cdn: { + headers: { + 'Cache-Control': `max-age=${maxAge}, immutable`, + }, + }, + demo: { + uploadPath: branch.current === branch.beta ? '/beta' : null, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0', + }, + }, + symlinks(ver, filename) { + return { + 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', + }, + }; + }, +}; + +// Size plugin +const sizeOptions = { showFiles: true, gzip: true }; + +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://${deploy.cdn.domain}/${version}`; +const cdnpath = new RegExp(`${deploy.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.beta]; + + if (!allowed.includes(branch.current)) { + console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`); + + return false; + } + + return true; +}; + +gulp.task('version', done => { + if (!canDeploy()) { + done(); + return null; + } + + const { domain } = deploy.cdn; + + log(`Uploading ${ansi.green.bold(version)} to ${ansi.cyan(domain)}...`); + + // Replace versioned URLs in source + const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js']; + + return gulp + .src( + files.map(file => path.join(__dirname, `src/js/${file}`)), + { base: '.' }, + ) + .pipe(replace(semver, `v${version}`)) + .pipe(replace(cdnpath, `${domain}/${version}/`)) + .pipe(gulp.dest('./')); +}); + +// Publish version to CDN bucket +gulp.task('cdn', done => { + if (!canDeploy()) { + done(); + return null; + } + + const { domain, publisher } = deploy.cdn; + + if (!publisher) { + throw new Error('No publisher instance. Check AWS configuration.'); + } + + log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); + + // Upload to CDN + return ( + gulp + .src(paths.upload) + .pipe(renameFile) + // Remove min suffix from source map URL + .pipe( + replace( + /sourceMappingURL=([\w-?.]+)/, + (match, filename) => `sourceMappingURL=${filename.replace(minSuffix, '')}`, + ), + ) + .pipe(size(sizeOptions)) + .pipe(replace(localPath, versionPath)) + .pipe(publisher.publish(options.cdn.headers)) + .pipe(publish.reporter()) + ); +}); + +// Purge the fastly cache incase any 403/404 are cached +gulp.task('purge', () => { + if (!Object.keys(credentials).includes('fastly')) { + throw new Error('Fastly credentials required to purge cache.'); + } + + const { fastly } = credentials; + const list = []; + + return gulp + .src(paths.upload) + .pipe( + through.obj((file, enc, cb) => { + const filename = file.path.split('/').pop(); + list.push(`${versionPath}/${filename.replace(minSuffix, '')}`); + cb(null); + }), + ) + .on('end', () => { + const purge = new FastlyPurge(fastly.token); + + list.forEach(url => { + log(`Purging ${ansi.cyan(url)}...`); + + purge.url(url, (error, result) => { + if (error) { + log.error(error); + } else if (result) { + log(result); + } + }); + }); + }); +}); + +// Publish to demo bucket +gulp.task('demo', done => { + if (!canDeploy()) { + done(); + return null; + } + + const { publisher } = deploy.demo; + const { domain } = deploy.cdn; + + if (!publisher) { + throw new Error('No publisher instance. Check AWS configuration.'); + } + + log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`); + + // Replace versioned files in readme.md + gulp.src([`${__dirname}/readme.md`]) + .pipe(replace(cdnpath, `${domain}/${version}/`)) + .pipe(gulp.dest(__dirname)); + + // Replace local file paths with remote paths in demo HTML + // e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js" + const index = `${paths.demo.root}index.html`; + const error = `${paths.demo.root}error.html`; + const pages = [index]; + + if (branch.current === branch.master) { + pages.push(error); + } + + return gulp + .src(pages) + .pipe(replace(localPath, versionPath)) + .pipe( + rename(p => { + if (options.demo.uploadPath) { + // eslint-disable-next-line no-param-reassign + p.dirname += options.demo.uploadPath; + } + }), + ) + .pipe(publisher.publish(options.demo.headers)) + .pipe(publish.reporter()); +}); + +// Open the demo site to check it's ok +gulp.task('open', () => { + const { domain } = deploy.demo; + + return gulp.src(__filename).pipe( + open({ + uri: `https://${domain}/${branch.current === branch.beta ? 'beta' : ''}`, + }), + ); +}); + +// Do everything +gulp.task('deploy', gulp.series('cdn', 'demo', 'purge', 'open'));