Commit 8b961d3d authored by Robert Knight's avatar Robert Knight

Simplify gulpfile using functions from @hypothesis/frontend-build

See also https://github.com/hypothesis/frontend-shared/pull/215.
parent a0227d78
/* eslint-env node */
import { existsSync, readFileSync } from 'fs';
import * as path from 'path';
import {
buildCSS,
buildJS,
runTests,
watchJS,
} from '@hypothesis/frontend-build';
import changed from 'gulp-changed';
import log from 'fancy-log';
import gulp from 'gulp';
import replace from 'gulp-replace';
import rename from 'gulp-rename';
import through from 'through2';
import manifest from './scripts/gulp/manifest.js';
import serveDev from './dev-server/serve-dev.js';
import servePackage from './dev-server/serve-package.js';
'use strict';
const { existsSync, mkdirSync, writeFileSync } = require('fs');
const path = require('path');
const changed = require('gulp-changed');
const commander = require('commander');
const log = require('fancy-log');
const glob = require('glob');
const gulp = require('gulp');
const replace = require('gulp-replace');
const rename = require('gulp-rename');
const rollup = require('rollup');
const through = require('through2');
const createStyleBundle = require('./scripts/gulp/create-style-bundle');
const manifest = require('./scripts/gulp/manifest');
const serveDev = require('./dev-server/serve-dev');
const servePackage = require('./dev-server/serve-package');
const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production';
const STYLE_DIR = 'build/styles';
const FONTS_DIR = 'build/fonts';
function parseCommandLine() {
commander
.option(
'--grep <pattern>',
'Run only tests where filename matches a regex pattern'
)
.option('--watch', 'Continuously run tests (default: false)', false)
.option('--browser <browser>', 'Run tests in browser of choice.')
.option(
'--no-browser',
"Don't launch default browser. Instead, navigate to http://localhost:9876/ to run the tests."
)
.parse(process.argv);
const { grep, watch, browser } = commander.opts();
const karmaOptions = {
grep,
singleRun: !watch,
};
// browser option can be either false | undefined | string
if (browser === false) {
karmaOptions.browsers = null;
} else if (browser) {
karmaOptions.browsers = [browser];
}
return karmaOptions;
}
const karmaOptions = parseCommandLine();
/** @param {import('rollup').RollupWarning} */
function logRollupWarning(warning) {
log(`Rollup warning: ${warning} (${warning.url})`);
}
async function readConfig(path) {
const { default: config } = await import(path);
return Array.isArray(config) ? config : [config];
}
async function buildJS(rollupConfig) {
const configs = await readConfig(rollupConfig);
await Promise.all(
configs.map(async config => {
const bundle = await rollup.rollup({
...config,
onwarn: logRollupWarning,
});
await bundle.write(config.output);
})
);
}
async function watchJS(rollupConfig) {
const configs = await readConfig(rollupConfig);
const watcher = rollup.watch(
configs.map(config => ({
...config,
onwarn: logRollupWarning,
}))
);
return new Promise(resolve => {
watcher.on('event', event => {
switch (event.code) {
case 'START':
log('JS build starting...');
break;
case 'BUNDLE_END':
event.result.close();
break;
case 'ERROR':
log('JS build error', event.error);
break;
case 'END':
log('JS build completed.');
resolve(); // Resolve once the initial build completes.
break;
}
});
});
}
gulp.task('build-js', () => buildJS('./rollup.config.mjs'));
gulp.task('watch-js', () => watchJS('./rollup.config.mjs'));
const cssBundles = [
// Hypothesis client
'./src/styles/annotator/annotator.scss',
'./src/styles/annotator/pdfjs-overrides.scss',
'./src/styles/sidebar/sidebar.scss',
gulp.task('build-css', () =>
buildCSS([
// Hypothesis client
'./src/styles/annotator/annotator.scss',
'./src/styles/annotator/pdfjs-overrides.scss',
'./src/styles/sidebar/sidebar.scss',
// Vendor
'./node_modules/katex/dist/katex.min.css',
// Development tools
'./src/styles/ui-playground/ui-playground.scss',
];
// Vendor
'./node_modules/katex/dist/katex.min.css',
gulp.task('build-css', () => {
mkdirSync(STYLE_DIR, { recursive: true });
const bundles = cssBundles.map(entry =>
createStyleBundle({
input: entry,
output: `${STYLE_DIR}/${path.basename(entry, path.extname(entry))}.css`,
minify: IS_PRODUCTION_BUILD,
})
);
return Promise.all(bundles);
});
// Development tools
'./src/styles/ui-playground/ui-playground.scss',
])
);
gulp.task(
'watch-css',
gulp.series('build-css', function watchCSS() {
const vendorCSS = cssBundles.filter(path => path.endsWith('.css'));
const styleFileGlobs = vendorCSS.concat('./src/styles/**/*.scss');
gulp.watch(styleFileGlobs, gulp.task('build-css'));
gulp.watch(
['node_modules/katex/dist/katex.min.css', 'src/styles/**/*.scss'],
gulp.task('build-css')
);
})
);
......@@ -191,7 +92,7 @@ function generateBootScript(manifest, { usingDevServer = false } = {}) {
return;
}
const { version } = require('./package.json');
const { version } = JSON.parse(readFileSync('./package.json').toString());
const defaultNotebookAppUrl = process.env.NOTEBOOK_APP_URL
? `${process.env.NOTEBOOK_APP_URL}`
......@@ -283,58 +184,18 @@ gulp.task(
)
);
async function buildAndRunTests() {
const { grep, singleRun } = karmaOptions;
// Generate an entry file for the test bundle. This imports all the test
// modules, filtered by the pattern specified by the `--grep` CLI option.
const testFiles = [
'src/sidebar/test/bootstrap.js',
...glob
.sync('src/**/*-test.js')
.filter(path => (grep ? path.match(grep) : true)),
];
const testSource = testFiles
.map(path => `import "../../${path}";`)
.join('\n');
mkdirSync('build/scripts', { recursive: true });
writeFileSync('build/scripts/test-inputs.js', testSource);
// Build the test bundle.
log(`Building test bundle... (${testFiles.length} files)`);
if (singleRun) {
await buildJS('./rollup-tests.config.mjs');
} else {
await watchJS('./rollup-tests.config.mjs');
}
// Run the tests.
log('Starting Karma...');
return new Promise(resolve => {
const karma = require('karma');
new karma.Server(
karma.config.parseConfig(
path.resolve(__dirname, './src/karma.config.js'),
{ singleRun }
),
resolve
).start();
process.on('SIGINT', () => {
// Give Karma a chance to handle SIGINT and cleanup, but forcibly
// exit if it takes too long.
setTimeout(() => {
resolve();
process.exit(1);
}, 5000);
});
});
}
// Unit and integration testing tasks.
//
// Some (eg. a11y) tests rely on CSS bundles. We assume that JS will always take
// longer to build than CSS, so build in parallel.
gulp.task('test', gulp.parallel('build-css', buildAndRunTests));
gulp.task(
'test',
gulp.parallel('build-css', () =>
runTests({
bootstrapFile: 'src/sidebar/test/bootstrap.js',
karmaConfig: 'src/karma.config.js',
rollupConfig: 'rollup-tests.config.mjs',
testsPattern: 'src/**/*-test.js',
})
)
);
......@@ -12,6 +12,7 @@
"@babel/core": "^7.1.6",
"@babel/preset-env": "^7.1.6",
"@babel/preset-react": "^7.0.0",
"@hypothesis/frontend-build": "^1.0.1",
"@hypothesis/frontend-shared": "3.13.0",
"@octokit/rest": "^18.0.0",
"@rollup/plugin-alias": "^3.1.2",
......
......@@ -1122,6 +1122,15 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
"@hypothesis/frontend-build@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@hypothesis/frontend-build/-/frontend-build-1.0.1.tgz#44d0c0f7eda19cb02a171f4b1b896741728c60dd"
integrity sha512-vhuc41FMrZQ13UzmH1zYqL52imrumlOv/lXaaRy7qiiu+aO2BWSwPAAiceg9Z0MCTCF/cg45fvb5hnF09rzUtQ==
dependencies:
commander "^8.2.0"
fancy-log "^1.3.3"
glob "^7.2.0"
"@hypothesis/frontend-shared@3.13.0":
version "3.13.0"
resolved "https://registry.yarnpkg.com/@hypothesis/frontend-shared/-/frontend-shared-3.13.0.tgz#3411b3c099a99fc84b3462f03b2df7a44bf19436"
......@@ -2438,7 +2447,7 @@ commander@^6.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
commander@^8.0.0:
commander@^8.0.0, commander@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8"
integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==
......@@ -3898,6 +3907,18 @@ glob@7.1.7, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-modules@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment