helper.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /**
  2. * Both used by zrender and echarts.
  3. */
  4. const assert = require('assert');
  5. const rollup = require('rollup');
  6. const path = require('path');
  7. const fs = require('fs');
  8. const fsExtra = require('fs-extra');
  9. const babel = require('@babel/core');
  10. const esm2cjsPlugin = require('./babel-plugin-transform-modules-commonjs-ec');
  11. const removeDEVPlugin = require('./babel-plugin-transform-remove-dev');
  12. /**
  13. * @param {Array.<Object>} configs A list of rollup configs:
  14. * See: <https://rollupjs.org/#big-list-of-options>
  15. * For example:
  16. * [
  17. * {
  18. * ...inputOptions,
  19. * output: [outputOptions],
  20. * watch: {chokidar, include, exclude}
  21. * },
  22. * ...
  23. * ]
  24. * @return {Promise}
  25. */
  26. exports.build = function (configs) {
  27. return new Promise(function (promiseResolve, promiseReject) {
  28. let index = 0;
  29. buildSingle();
  30. function buildSingle() {
  31. let singleConfig = configs[index++];
  32. if (!singleConfig) {
  33. promiseResolve();
  34. return;
  35. }
  36. console.log(
  37. color('fgCyan', 'dim')('\nBundles '),
  38. color('fgCyan')(singleConfig.input),
  39. color('fgCyan', 'dim')('=>'),
  40. color('fgCyan')(singleConfig.output.file),
  41. color('fgCyan', 'dim')(' ...')
  42. );
  43. rollup
  44. .rollup(singleConfig)
  45. .then(function (bundle) {
  46. return bundle.write(singleConfig.output);
  47. })
  48. .then(function () {
  49. console.log(
  50. color('fgGreen', 'dim')('Created '),
  51. color('fgGreen')(singleConfig.output.file),
  52. color('fgGreen', 'dim')(' successfully.')
  53. );
  54. buildSingle();
  55. })
  56. .catch(function (err) {
  57. console.log(color('fgRed')(err));
  58. promiseReject();
  59. });
  60. }
  61. });
  62. };
  63. /**
  64. * @param {Object} singleConfig A single rollup config:
  65. * See: <https://rollupjs.org/#big-list-of-options>
  66. * For example:
  67. * {
  68. * ...inputOptions,
  69. * output: [outputOptions],
  70. * watch: {chokidar, include, exclude}
  71. * }
  72. */
  73. exports.watch = function (singleConfig) {
  74. let watcher = rollup.watch(singleConfig);
  75. watcher.on('event', function (event) {
  76. // event.code can be one of:
  77. // START — the watcher is (re)starting
  78. // BUNDLE_START — building an individual bundle
  79. // BUNDLE_END — finished building a bundle
  80. // END — finished building all bundles
  81. // ERROR — encountered an error while bundling
  82. // FATAL — encountered an unrecoverable error
  83. if (event.code !== 'START' && event.code !== 'END') {
  84. console.log(
  85. color('fgBlue')('[' + getTimeString() + ']'),
  86. color('dim')('build'),
  87. event.code.replace(/_/g, ' ').toLowerCase()
  88. );
  89. }
  90. if (event.code === 'ERROR' || event.code === 'FATAL') {
  91. printCodeError(event.error);
  92. }
  93. if (event.code === 'BUNDLE_END') {
  94. printWatchResult(event);
  95. }
  96. });
  97. };
  98. /**
  99. * @param {string} srcDir Absolute directory path.
  100. * @param {Function} [cb] Params: {
  101. * fileName: like 'some.js', without dir path.
  102. * relativePath: relative to srcDir.
  103. * absolutePath
  104. * }
  105. */
  106. exports.travelSrcDir = function (srcDir, cb) {
  107. assert(fs.statSync(srcDir).isDirectory());
  108. const regDir = /^[^.].*$/;
  109. const regSrc = /^[^.].*[.]js$/;
  110. doTravelSrcDir('.');
  111. function doTravelSrcDir(relativePath) {
  112. const absolutePath = path.resolve(srcDir, relativePath);
  113. fs.readdirSync(absolutePath).forEach(fileName => {
  114. const childAbsolutePath = path.resolve(absolutePath, fileName);
  115. const stat = fs.statSync(childAbsolutePath);
  116. if (stat.isDirectory()) {
  117. if (regDir.test(fileName)) {
  118. doTravelSrcDir(path.join(relativePath, fileName));
  119. }
  120. }
  121. else if (stat.isFile()) {
  122. if (regSrc.test(fileName)) {
  123. cb({fileName, relativePath, absolutePath: childAbsolutePath});
  124. }
  125. }
  126. });
  127. }
  128. };
  129. /**
  130. * @param {string} [opt]
  131. * @param {string} [opt.inputPath] Absolute input path.
  132. * @param {string} [opt.outputPath] Absolute output path.
  133. * @param {Function} [opt.transform]
  134. * @param {Function} [opt.reserveDEV]
  135. */
  136. exports.prePulishSrc = function ({inputPath, outputPath, transform, reserveDEV}) {
  137. assert(inputPath && outputPath);
  138. console.log(
  139. color('fgGreen', 'dim')('[transform] '),
  140. color('fgGreen')(inputPath),
  141. color('fgGreen', 'dim')('...')
  142. );
  143. let plugins = [];
  144. !reserveDEV && plugins.push(removeDEVPlugin);
  145. plugins.push(esm2cjsPlugin);
  146. let {code} = babel.transformFileSync(inputPath, {
  147. plugins: plugins
  148. });
  149. !reserveDEV && removeDEVPlugin.recheckDEV(code);
  150. if (transform) {
  151. code = transform({code, inputPath, outputPath});
  152. }
  153. fsExtra.ensureFileSync(outputPath);
  154. fs.writeFileSync(outputPath, code, {encoding:'utf-8'});
  155. };
  156. function printWatchResult(event) {
  157. console.log(
  158. color('fgGreen', 'dim')('Created'),
  159. color('fgGreen')(event.output.join(', ')),
  160. color('fgGreen', 'dim')('in'),
  161. color('fgGreen')(event.duration),
  162. color('fgGreen', 'dim')('ms.')
  163. );
  164. }
  165. function printCodeError(error) {
  166. console.log('\n' + color()(error.code));
  167. if (error.code === 'PARSE_ERROR') {
  168. console.log(
  169. color()('line'),
  170. color('fgCyan')(error.loc.line),
  171. color()('column'),
  172. color('fgCyan')(error.loc.column),
  173. color()('in'),
  174. color('fgCyan')(error.loc.file)
  175. );
  176. }
  177. if (error.frame) {
  178. console.log('\n' + color('fgRed')(error.frame));
  179. }
  180. console.log(color('dim')('\n' + error.stack));
  181. }
  182. function getTimeString() {
  183. return (new Date()).toLocaleString();
  184. }
  185. const COLOR_RESET = '\x1b[0m';
  186. const COLOR_MAP = {
  187. bright: '\x1b[1m',
  188. dim: '\x1b[2m',
  189. underscore: '\x1b[4m',
  190. blink: '\x1b[5m',
  191. reverse: '\x1b[7m',
  192. hidden: '\x1b[8m',
  193. fgBlack: '\x1b[30m',
  194. fgRed: '\x1b[31m',
  195. fgGreen: '\x1b[32m',
  196. fgYellow: '\x1b[33m',
  197. fgBlue: '\x1b[34m',
  198. fgMagenta: '\x1b[35m',
  199. fgCyan: '\x1b[36m',
  200. fgWhite: '\x1b[37m',
  201. bgBlack: '\x1b[40m',
  202. bgRed: '\x1b[41m',
  203. bgGreen: '\x1b[42m',
  204. bgYellow: '\x1b[43m',
  205. bgBlue: '\x1b[44m',
  206. bgMagenta: '\x1b[45m',
  207. bgCyan: '\x1b[46m',
  208. bgWhite: '\x1b[47m'
  209. };
  210. /**
  211. * Print colored text with `console.log`.
  212. *
  213. * Usage:
  214. * let color = require('colorConsole');
  215. * color('fgCyan')('some text'); // cyan text.
  216. * color('fgCyan', 'bright')('some text'); // bright cyan text.
  217. * color('fgCyan', 'bgRed')('some text') // cyan text and red background.
  218. */
  219. let color = exports.color = function () {
  220. let prefix = [];
  221. for (let i = 0; i < arguments.length; i++) {
  222. let color = COLOR_MAP[arguments[i]];
  223. color && prefix.push(color);
  224. }
  225. prefix = prefix.join('');
  226. return function (text) {
  227. return prefix + text + COLOR_RESET;
  228. };
  229. };