gulpfile.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. const gulp = require('gulp');
  2. const del = require('del');
  3. const log = require('fancy-log');
  4. const gulpFilter = require('gulp-filter');
  5. const uglify = require('gulp-uglify');
  6. const plumber = require('gulp-plumber');
  7. const yaml = require('js-yaml');
  8. const webpack = require('webpack');
  9. const webpackConfig = require('./scripts/webpack.conf');
  10. const webpackTestConfig = require('./scripts/webpack.test.conf');
  11. const i18n = require('./scripts/i18n');
  12. const string = require('./scripts/string');
  13. const { isProd } = require('./scripts/util');
  14. const pkg = require('./package.json');
  15. const DIST = 'dist';
  16. const paths = {
  17. manifest: 'src/manifest.yml',
  18. copy: [
  19. 'src/public/images/**',
  20. 'src/public/lib/**',
  21. ],
  22. locales: [
  23. 'src/_locales/**',
  24. ],
  25. templates: [
  26. 'src/**/*.@(js|html|json|yml|vue)',
  27. ],
  28. };
  29. function webpackCallback(err, stats) {
  30. if (err) {
  31. log('[FATAL]', err);
  32. return;
  33. }
  34. if (stats.hasErrors()) {
  35. log('[ERROR] webpack compilation failed\n', stats.toJson().errors.join('\n'));
  36. return;
  37. }
  38. if (stats.hasWarnings()) {
  39. log('[WARNING] webpack compilation has warnings\n', stats.toJson().warnings.join('\n'));
  40. }
  41. (Array.isArray(stats.stats) ? stats.stats : [stats])
  42. .forEach(stat => {
  43. const timeCost = (stat.endTime - stat.startTime) / 1000;
  44. const chunks = Object.keys(stat.compilation.namedChunks).join(' ');
  45. log(`Webpack built: [${timeCost.toFixed(3)}s] ${chunks}`);
  46. });
  47. }
  48. function clean() {
  49. return del(DIST);
  50. }
  51. function watch() {
  52. gulp.watch(paths.manifest, manifest);
  53. gulp.watch(paths.copy, copyFiles);
  54. gulp.watch(paths.locales.concat(paths.templates), copyI18n);
  55. }
  56. function jsDev(done) {
  57. let firstRun = true;
  58. webpack(webpackConfig).watch({}, (...args) => {
  59. webpackCallback(...args);
  60. if (firstRun) {
  61. firstRun = false;
  62. done();
  63. }
  64. });
  65. }
  66. function jsProd(done) {
  67. webpack(webpackConfig, (...args) => {
  68. webpackCallback(...args);
  69. done();
  70. });
  71. }
  72. function jsTest(done) {
  73. webpack(webpackTestConfig, (...args) => {
  74. webpackCallback(...args);
  75. done();
  76. });
  77. }
  78. function manifest() {
  79. return gulp.src(paths.manifest, { base: 'src' })
  80. .pipe(string((input, file) => {
  81. const data = yaml.safeLoad(input);
  82. // Strip alphabetic suffix
  83. data.version = pkg.version.replace(/-[^.]*/, '');
  84. if (process.env.TARGET === 'firefox') {
  85. data.version += 'f';
  86. data.applications.gecko.update_url = 'https://violentmonkey.top/static/updates.json';
  87. }
  88. file.path = file.path.replace(/\.yml$/, '.json');
  89. return JSON.stringify(data);
  90. }))
  91. .pipe(gulp.dest(DIST));
  92. }
  93. function copyFiles() {
  94. const jsFilter = gulpFilter(['**/*.js'], { restore: true });
  95. let stream = gulp.src(paths.copy, { base: 'src' });
  96. if (isProd) stream = stream
  97. .pipe(jsFilter)
  98. .pipe(uglify())
  99. .pipe(jsFilter.restore);
  100. return stream
  101. .pipe(gulp.dest(DIST));
  102. }
  103. function checkI18n() {
  104. return gulp.src(paths.templates)
  105. .pipe(i18n.extract({
  106. base: 'src/_locales',
  107. extension: '.json',
  108. }));
  109. }
  110. function copyI18n() {
  111. return gulp.src(paths.templates)
  112. .pipe(plumber(logError))
  113. .pipe(i18n.extract({
  114. base: 'src/_locales',
  115. touchedOnly: true,
  116. useDefaultLang: true,
  117. markUntouched: false,
  118. extension: '.json',
  119. }))
  120. .pipe(gulp.dest(`${DIST}/_locales`));
  121. }
  122. /**
  123. * Load locale files (src/_locales/<lang>/message.[json|yml]), and
  124. * update them with keys in template files, then store in `message.yml`.
  125. */
  126. function updateI18n() {
  127. return gulp.src(paths.templates)
  128. .pipe(plumber(logError))
  129. .pipe(i18n.extract({
  130. base: 'src/_locales',
  131. touchedOnly: false,
  132. useDefaultLang: false,
  133. markUntouched: true,
  134. extension: '.yml',
  135. }))
  136. .pipe(gulp.dest('src/_locales'));
  137. }
  138. function logError(err) {
  139. log(err.toString());
  140. return this.emit('end');
  141. }
  142. const pack = gulp.parallel(manifest, copyFiles, copyI18n);
  143. exports.clean = clean;
  144. exports.dev = gulp.series(gulp.parallel(pack, jsDev), watch);
  145. exports.build = gulp.parallel(pack, jsProd);
  146. exports.buildTest = jsTest;
  147. exports.i18n = updateI18n;
  148. exports.check = checkI18n;