|
|
|
@ -2,28 +2,27 @@ const path = require('path');
|
|
|
|
|
const {exec} = require('child_process');
|
|
|
|
|
const {lstatSync, readdirSync, readFileSync, writeFileSync} = require('fs');
|
|
|
|
|
|
|
|
|
|
const {ensureDirSync} = require('fs-extra');
|
|
|
|
|
const gulp = require('gulp');
|
|
|
|
|
const htmlmin = require('gulp-htmlmin');
|
|
|
|
|
const svgmin = require('gulp-svgmin');
|
|
|
|
|
const {series, parallel, src, dest} = require('gulp');
|
|
|
|
|
const babel = require('gulp-babel');
|
|
|
|
|
const postcss = require('gulp-postcss');
|
|
|
|
|
const gulpif = require('gulp-if');
|
|
|
|
|
const del = require('del');
|
|
|
|
|
const jsonMerge = require('gulp-merge-json');
|
|
|
|
|
const jsonmin = require('gulp-jsonmin');
|
|
|
|
|
const svg2png = require('svg2png');
|
|
|
|
|
const htmlmin = require('gulp-htmlmin');
|
|
|
|
|
const imagemin = require('gulp-imagemin');
|
|
|
|
|
const del = require('del');
|
|
|
|
|
const {ensureDirSync} = require('fs-extra');
|
|
|
|
|
const sharp = require('sharp');
|
|
|
|
|
|
|
|
|
|
const targetEnv = process.env.TARGET_ENV || 'firefox';
|
|
|
|
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
|
|
|
const distDir = path.join('dist', targetEnv);
|
|
|
|
|
|
|
|
|
|
gulp.task('clean', function() {
|
|
|
|
|
function clean() {
|
|
|
|
|
return del([distDir]);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('js:webpack', function(done) {
|
|
|
|
|
function jsWebpack(done) {
|
|
|
|
|
exec('webpack-cli --display-error-details --bail --colors', function(
|
|
|
|
|
err,
|
|
|
|
|
stdout,
|
|
|
|
@ -33,79 +32,85 @@ gulp.task('js:webpack', function(done) {
|
|
|
|
|
console.log(stderr);
|
|
|
|
|
done(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('js:babel', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src(['src/content/**/*.js'], {base: '.'})
|
|
|
|
|
function jsBabel() {
|
|
|
|
|
return src(['src/content/**/*.js'], {base: '.'})
|
|
|
|
|
.pipe(babel())
|
|
|
|
|
.pipe(gulp.dest(distDir));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
.pipe(dest(distDir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('js', gulp.parallel('js:webpack', 'js:babel'));
|
|
|
|
|
const js = parallel(jsWebpack, jsBabel);
|
|
|
|
|
|
|
|
|
|
gulp.task('html', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src('src/**/*.html', {base: '.'})
|
|
|
|
|
function html() {
|
|
|
|
|
return src('src/**/*.html', {base: '.'})
|
|
|
|
|
.pipe(gulpif(isProduction, htmlmin({collapseWhitespace: true})))
|
|
|
|
|
.pipe(gulp.dest(distDir));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
.pipe(dest(distDir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('css', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src(['src/solve/style.css'], {
|
|
|
|
|
function css() {
|
|
|
|
|
return src(['src/solve/style.css'], {
|
|
|
|
|
base: '.'
|
|
|
|
|
})
|
|
|
|
|
.pipe(postcss())
|
|
|
|
|
.pipe(gulp.dest(distDir));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
.pipe(dest(distDir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('icons', async function(done) {
|
|
|
|
|
ensureDirSync(`${distDir}/src/icons/app`);
|
|
|
|
|
const iconSvg = readFileSync('src/icons/app/icon.svg');
|
|
|
|
|
async function images(done) {
|
|
|
|
|
ensureDirSync(path.join(distDir, 'src/icons/app'));
|
|
|
|
|
const appIconSvg = readFileSync('src/icons/app/icon.svg');
|
|
|
|
|
const appIconSizes = [16, 19, 24, 32, 38, 48, 64, 96, 128];
|
|
|
|
|
for (const size of appIconSizes) {
|
|
|
|
|
const pngBuffer = await svg2png(iconSvg, {width: size, height: size});
|
|
|
|
|
writeFileSync(`${distDir}/src/icons/app/icon-${size}.png`, pngBuffer);
|
|
|
|
|
await sharp(appIconSvg, {density: (72 * size) / 24})
|
|
|
|
|
.resize(size)
|
|
|
|
|
.toFile(path.join(distDir, `src/icons/app/icon-${size}.png`));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isProduction) {
|
|
|
|
|
gulp
|
|
|
|
|
.src(`${distDir}/src/icons/**/*.png`, {base: '.'})
|
|
|
|
|
// Chrome Web Store does not correctly display optimized icons
|
|
|
|
|
if (isProduction && targetEnv !== 'chrome') {
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
src(path.join(distDir, 'src/icons/app/*.png'), {base: '.'})
|
|
|
|
|
.pipe(imagemin())
|
|
|
|
|
.pipe(gulp.dest('.'));
|
|
|
|
|
.pipe(dest('.'))
|
|
|
|
|
.on('error', done)
|
|
|
|
|
.on('finish', resolve);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp
|
|
|
|
|
.src('node_modules/ext-contribute/src/assets/*.svg')
|
|
|
|
|
.pipe(gulpif(isProduction, svgmin()))
|
|
|
|
|
.pipe(gulp.dest(`${distDir}/src/contribute/assets`));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
src('node_modules/ext-contribute/src/assets/*.@(jpg|png|svg)')
|
|
|
|
|
.pipe(gulpif(isProduction, imagemin()))
|
|
|
|
|
.pipe(dest(path.join(distDir, 'src/contribute/assets')))
|
|
|
|
|
.on('error', done)
|
|
|
|
|
.on('finish', resolve);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('fonts', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src('src/fonts/roboto.css', {base: '.'})
|
|
|
|
|
async function fonts(done) {
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
src('src/fonts/roboto.css', {base: '.'})
|
|
|
|
|
.pipe(postcss())
|
|
|
|
|
.pipe(gulp.dest(distDir));
|
|
|
|
|
gulp
|
|
|
|
|
.src('node_modules/typeface-roboto/files/roboto-latin-@(400|500|700).woff2')
|
|
|
|
|
.pipe(gulp.dest(`${distDir}/src/fonts/files`));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
gulp.task('locale', function(done) {
|
|
|
|
|
.pipe(dest(distDir))
|
|
|
|
|
.on('error', done)
|
|
|
|
|
.on('finish', resolve);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
src('node_modules/fontsource-roboto/files/roboto-latin-@(400|500|700)-normal.woff2')
|
|
|
|
|
.pipe(dest(path.join(distDir, 'src/fonts/files')))
|
|
|
|
|
.on('error', done)
|
|
|
|
|
.on('finish', resolve);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function locale(done) {
|
|
|
|
|
const localesRootDir = path.join(__dirname, 'src/_locales');
|
|
|
|
|
const localeDirs = readdirSync(localesRootDir).filter(function(file) {
|
|
|
|
|
return lstatSync(path.join(localesRootDir, file)).isDirectory();
|
|
|
|
|
});
|
|
|
|
|
localeDirs.forEach(function(localeDir) {
|
|
|
|
|
for (const localeDir of localeDirs) {
|
|
|
|
|
const localePath = path.join(localesRootDir, localeDir);
|
|
|
|
|
gulp
|
|
|
|
|
.src(
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
src(
|
|
|
|
|
[
|
|
|
|
|
path.join(localePath, 'messages.json'),
|
|
|
|
|
path.join(localePath, `messages-${targetEnv}.json`)
|
|
|
|
@ -128,14 +133,15 @@ gulp.task('locale', function(done) {
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
.pipe(gulpif(isProduction, jsonmin()))
|
|
|
|
|
.pipe(gulp.dest(path.join(distDir, '_locales', localeDir)));
|
|
|
|
|
.pipe(dest(path.join(distDir, '_locales', localeDir)))
|
|
|
|
|
.on('error', done)
|
|
|
|
|
.on('finish', resolve);
|
|
|
|
|
});
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('manifest', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src('src/manifest.json')
|
|
|
|
|
function manifest() {
|
|
|
|
|
return src('src/manifest.json')
|
|
|
|
|
.pipe(
|
|
|
|
|
jsonMerge({
|
|
|
|
|
fileName: 'manifest.json',
|
|
|
|
@ -163,13 +169,12 @@ gulp.task('manifest', function(done) {
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
.pipe(gulpif(isProduction, jsonmin()))
|
|
|
|
|
.pipe(gulp.dest(distDir));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
.pipe(dest(distDir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('license', function(done) {
|
|
|
|
|
let year = 2018;
|
|
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
|
function license() {
|
|
|
|
|
let year = '2018';
|
|
|
|
|
const currentYear = new Date().getFullYear().toString();
|
|
|
|
|
if (year !== currentYear) {
|
|
|
|
|
year = `${year}-${currentYear}`;
|
|
|
|
|
}
|
|
|
|
@ -181,48 +186,22 @@ This software is released under the terms of the GNU General Public License v3.0
|
|
|
|
|
See the LICENSE file for further information.
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
writeFileSync(`${distDir}/NOTICE`, notice);
|
|
|
|
|
gulp.src(['LICENSE']).pipe(gulp.dest(distDir));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
gulp.task('copy', function(done) {
|
|
|
|
|
gulp
|
|
|
|
|
.src('node_modules/ext-contribute/src/assets/*.@(jpg|png)')
|
|
|
|
|
.pipe(gulp.dest(`${distDir}/src/contribute/assets`));
|
|
|
|
|
done();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
gulp.task(
|
|
|
|
|
'build',
|
|
|
|
|
gulp.series(
|
|
|
|
|
'clean',
|
|
|
|
|
gulp.parallel(
|
|
|
|
|
'js',
|
|
|
|
|
'html',
|
|
|
|
|
'css',
|
|
|
|
|
'icons',
|
|
|
|
|
'fonts',
|
|
|
|
|
'locale',
|
|
|
|
|
'manifest',
|
|
|
|
|
'license'
|
|
|
|
|
),
|
|
|
|
|
'copy'
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
writeFileSync(path.join(distDir, 'NOTICE'), notice);
|
|
|
|
|
return src(['LICENSE']).pipe(dest(distDir));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('zip', function(done) {
|
|
|
|
|
function zip(done) {
|
|
|
|
|
exec(
|
|
|
|
|
`web-ext build -s dist/${targetEnv} -a artifacts/${targetEnv} --overwrite-dest`,
|
|
|
|
|
`web-ext build -s dist/${targetEnv} -a artifacts/${targetEnv} -n '{name}-{version}-${targetEnv}.zip' --overwrite-dest`,
|
|
|
|
|
function(err, stdout, stderr) {
|
|
|
|
|
console.log(stdout);
|
|
|
|
|
console.log(stderr);
|
|
|
|
|
done(err);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('inspect', function(done) {
|
|
|
|
|
function inspect(done) {
|
|
|
|
|
exec(
|
|
|
|
|
`webpack --profile --json > report.json && webpack-bundle-analyzer report.json dist/firefox/src && sleep 10 && rm report.{json,html}`,
|
|
|
|
|
function(err, stdout, stderr) {
|
|
|
|
@ -231,6 +210,11 @@ gulp.task('inspect', function(done) {
|
|
|
|
|
done(err);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gulp.task('default', gulp.series('build'));
|
|
|
|
|
exports.build = series(
|
|
|
|
|
clean,
|
|
|
|
|
parallel(js, html, css, images, fonts, locale, manifest, license)
|
|
|
|
|
);
|
|
|
|
|
exports.zip = zip;
|
|
|
|
|
exports.inspect = inspect;
|
|
|
|
|