var gulp = require('gulp') var fs = require('fs') var webpack = require('webpack') var config = require('./webpack.prod') var devConfig = require('./webpack.dev') var gulpZip = require('gulp-zip') var crx3 = require('crx3') var webstoreClient = require('chrome-webstore-upload') var rename = require('gulp-rename') var path = require('path') // Provide a dummy credential file for third-party builders try { fs.accessSync('./google-api.credentials.json') } catch (e) { fs.writeFileSync('./google-api.credentials.json', JSON.stringify({ 'web': { 'client_id': 'yourappidhere.apps.googleusercontent.com', 'project_id': 'YOUR PROJECT ID HERE', 'auth_uri': 'https://accounts.google.com/o/oauth2/auth', 'token_uri': 'https://oauth2.googleapis.com/token', 'auth_provider_x509_cert_url': 'https://www.googleapis.com/oauth2/v1/certs', 'client_secret': 'YOUR CLIENT SECRET HERE', 'redirect_uris': [ 'https://yourappidhere.chromiumapp.org/', 'https://yourappidhere.extensions.allizom.org/' ] } })) } // eslint-disable-next-line @typescript-eslint/no-var-requires const VERSION = require('./package.json').version const paths = { zip: [ './**', (process.env['CI'] ? './' : '!') + 'dist/js/test.js', '!builds/**', '!src/**', '!node_modules/**', '!img/**', '!ISSUE_TEMPLATE.md', '!gulpfile.js', '!key.pem', '!android/**', '!ios/**', '!manifest*.json' ], views: './html/*.html', nativeHTML: './html/index.html', entries: 'src/entries/*.js', js: 'src/**', builds: './builds/', icons: 'icons/*', dist: './dist/**', distJs: './dist/js', } paths.chromeZip = [...paths.zip, 'manifest.chrome.json'] paths.firefoxZip = [...paths.zip, 'manifest.firefox.json'] const WEBSTORE_ID = 'fnaicdffflnofjppbagibeoednhnbjhg' let WEBSTORE_CREDENTIALS let webstore try { WEBSTORE_CREDENTIALS = require('./builds/google-api.json') webstore = webstoreClient( Object.assign({}, WEBSTORE_CREDENTIALS, { extensionId: WEBSTORE_ID, }) ) } catch (e) { // noop } const icons = function() { return gulp.src(paths.icons).pipe(gulp.dest('./dist/icons/')) } const devjs = function() { return new Promise((resolve) => webpack(devConfig, (err, stats) => { if (err) console.log('Webpack', err) console.log( stats.toString({ /* stats options */ }) ) resolve() }) ) } const js = async function() { fs.mkdirSync(paths.distJs,{ recursive: true }) await new Promise((resolve) => webpack(config, (err, stats) => { console.log( stats.toString({ /* stats options */ }) ) if (err) { console.log('Webpack', err) return } const statsJson = stats.toJson() html(statsJson) resolve() }) ) } const html = function(statsJson) { fs.mkdirSync('dist/html/', { recursive: true }) let html, scripts, bgScript, addition ;['index.html', 'options.html', 'background.html', 'test.html'].forEach(htmlFile => { switch (htmlFile) { case 'index.html': html = fs.readFileSync('html/' + htmlFile, 'utf8') scripts = statsJson.entrypoints.native.assets.map(asset => ``).join('\n') html = html.replace('{{ scripts }}', scripts) fs.writeFileSync('dist/' + htmlFile, html) break case 'options.html': html = fs.readFileSync('html/' + htmlFile, 'utf8') scripts = statsJson.entrypoints.options.assets.map(asset => ``).join('\n') html = html.replace('{{ scripts }}', scripts) console.log(statsJson.entrypoints.options.assets) fs.writeFileSync('dist/html/' + htmlFile, html) break case 'test.html': html = fs.readFileSync('html/' + htmlFile, 'utf8') scripts = statsJson.entrypoints.test.assets.map(asset => ``).join('\n') html = html.replace('{{ scripts }}', scripts) fs.writeFileSync('dist/html/' + htmlFile, html) break case 'background.html': html = fs.readFileSync('html/' + htmlFile, 'utf8') scripts = statsJson.entrypoints['background-script'].assets.map(asset => ``).join('\n') html = html.replace('{{ scripts }}', scripts) fs.writeFileSync('dist/html/' + htmlFile, html) bgScript = fs.readFileSync(paths.distJs + '/background-script.js', 'utf8') addition = ` if ("undefined"!=typeof self && 'importScripts' in self) { ${statsJson.entrypoints['background-script'].assets.map(asset => asset.name !== 'background-script.js' ? `self.importScripts('./${asset.name}')` : '').join('\n')} } ` fs.writeFileSync(paths.distJs + '/background-script.js', addition + bgScript) break } }) } const mochajs = function() { return gulp.src('./node_modules/mocha/mocha.js').pipe(gulp.dest('./dist/js/')) } const mochacss = function() { return gulp .src('./node_modules/mocha/mocha.css') .pipe(gulp.dest('./dist/css/')) } const native = async function() { const execa = (await import('execa')).execa const {stdout} = await execa('cap', ['sync']) console.log(stdout) } const cleanJs = async function() { try { fs.rmSync(paths.distJs, { recursive: true }) } catch (e) { // noop } } const mocha = gulp.parallel(mochajs, mochacss) const thirdparty = gulp.parallel(mocha) const assets = gulp.parallel(thirdparty, icons) const build = gulp.series(cleanJs, js, assets) const main = gulp.series(build, native) const chromeZip = function() { return gulp .src(paths.chromeZip, { buffer: false }) .pipe(rename((path) => { if (path.basename.startsWith('manifest') && path.extname === '.json') { path.basename = 'manifest' } })) .pipe(gulpZip(`floccus-build-v${VERSION}-chrome.zip`)) .pipe(gulp.dest(paths.builds)) } const firefoxZip = function() { return gulp .src(paths.firefoxZip, { buffer: false }) .pipe(rename((path) => { if (path.basename.startsWith('manifest') && path.extname === '.json') { path.basename = 'manifest' } })) .pipe(gulpZip(`floccus-build-v${VERSION}-firefox.zip`)) .pipe(gulp.dest(paths.builds)) } const xpi = function() { return gulp .src(paths.firefoxZip, { buffer: false }) .pipe(rename((path) => { if (path.basename.startsWith('manifest') && path.extname === '.json') { path.basename = 'manifest' } })) .pipe(gulpZip(`floccus-build-v${VERSION}.xpi`)) .pipe(gulp.dest(paths.builds)) } const crx = function() { return crx3( fs.createReadStream(`${paths.builds}/floccus-build-v${VERSION}-chrome.zip`), { keyPath: 'key.pem', crxPath: `${paths.builds}/floccus-build-v${VERSION}.crx`, } ) } const release = gulp.series(main, gulp.parallel(firefoxZip, chromeZip, xpi), crx) const publish = gulp.series(main, chromeZip, function() { return webstore .uploadExisting( fs.createReadStream(`${paths.builds}floccus-build-v${VERSION}-chrome.zip`) ) .then(function() { return webstore.publish('default') }) }) const watch = function() { let jsWatcher = gulp.watch(paths.js, assets) let nativeWatcher = gulp.watch(paths.dist, native) jsWatcher.on('change', onWatchEvent) nativeWatcher.on('change', onWatchEvent) webpack(devConfig).watch({}, (err, stats) => { if (err) { console.log(err) } html({entrypoints: { native: {assets: [{name: 'native.js'}]}, options: {assets: [{name: 'options.js'}]}, 'background-script': {assets: [{name: 'background-script.js'}]}, 'test': {assets: [{name: 'test.js'}]}, }}) console.log(stats.toString({ chunks: false, colors: true })) }) } function onWatchEvent(path) { console.log( 'File ' + path + ' was changed, running tasks...' ) } exports.assets = assets exports.js = js exports.mocha = mocha exports.release = release exports.watch = gulp.series(cleanJs,gulp.parallel(assets, devjs), native, watch) exports.publish = publish exports.build = build exports.native = native exports.package = gulp.series(gulp.parallel(firefoxZip, chromeZip, xpi), crx) /* * Define default task that can be called by just running `gulp` from cli */ exports.default = main