minify.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _terser = require('terser');
  6. var _terser2 = _interopRequireDefault(_terser);
  7. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  8. const buildTerserOptions = ({
  9. ecma,
  10. warnings,
  11. parse = {},
  12. compress = {},
  13. mangle,
  14. module,
  15. output,
  16. toplevel,
  17. nameCache,
  18. ie8,
  19. /* eslint-disable camelcase */
  20. keep_classnames,
  21. keep_fnames,
  22. /* eslint-enable camelcase */
  23. safari10
  24. } = {}) => ({
  25. ecma,
  26. warnings,
  27. parse: Object.assign({}, parse),
  28. compress: typeof compress === 'boolean' ? compress : Object.assign({}, compress),
  29. // eslint-disable-next-line no-nested-ternary
  30. mangle: mangle == null ? true : typeof mangle === 'boolean' ? mangle : Object.assign({}, mangle),
  31. output: Object.assign({
  32. shebang: true,
  33. comments: false,
  34. beautify: false,
  35. semicolons: true
  36. }, output),
  37. module,
  38. // Ignoring sourceMap from options
  39. sourceMap: null,
  40. toplevel,
  41. nameCache,
  42. ie8,
  43. keep_classnames,
  44. keep_fnames,
  45. safari10
  46. }); /* eslint-disable
  47. arrow-body-style
  48. */
  49. const buildComments = (options, terserOptions, extractedComments) => {
  50. const condition = {};
  51. const commentsOpts = terserOptions.output.comments;
  52. // Use /^\**!|@preserve|@license|@cc_on/i RegExp
  53. if (typeof options.extractComments === 'boolean') {
  54. condition.preserve = commentsOpts;
  55. condition.extract = /^\**!|@preserve|@license|@cc_on/i;
  56. } else if (typeof options.extractComments === 'string' || options.extractComments instanceof RegExp) {
  57. // extractComments specifies the extract condition and commentsOpts specifies the preserve condition
  58. condition.preserve = commentsOpts;
  59. condition.extract = options.extractComments;
  60. } else if (typeof options.extractComments === 'function') {
  61. condition.preserve = commentsOpts;
  62. condition.extract = options.extractComments;
  63. } else if (Object.prototype.hasOwnProperty.call(options.extractComments, 'condition')) {
  64. // Extract condition is given in extractComments.condition
  65. condition.preserve = commentsOpts;
  66. condition.extract = options.extractComments.condition;
  67. } else {
  68. // No extract condition is given. Extract comments that match commentsOpts instead of preserving them
  69. condition.preserve = false;
  70. condition.extract = commentsOpts;
  71. }
  72. // Ensure that both conditions are functions
  73. ['preserve', 'extract'].forEach(key => {
  74. let regexStr;
  75. let regex;
  76. switch (typeof condition[key]) {
  77. case 'boolean':
  78. condition[key] = condition[key] ? () => true : () => false;
  79. break;
  80. case 'function':
  81. break;
  82. case 'string':
  83. if (condition[key] === 'all') {
  84. condition[key] = () => true;
  85. break;
  86. }
  87. if (condition[key] === 'some') {
  88. condition[key] = (astNode, comment) => {
  89. return comment.type === 'comment2' && /^\**!|@preserve|@license|@cc_on/i.test(comment.value);
  90. };
  91. break;
  92. }
  93. regexStr = condition[key];
  94. condition[key] = (astNode, comment) => {
  95. return new RegExp(regexStr).test(comment.value);
  96. };
  97. break;
  98. default:
  99. regex = condition[key];
  100. condition[key] = (astNode, comment) => regex.test(comment.value);
  101. }
  102. });
  103. // Redefine the comments function to extract and preserve
  104. // comments according to the two conditions
  105. return (astNode, comment) => {
  106. if (condition.extract(astNode, comment)) {
  107. extractedComments.push(comment.type === 'comment2' ? `/*${comment.value}*/` : `//${comment.value}`);
  108. }
  109. return condition.preserve(astNode, comment);
  110. };
  111. };
  112. const minify = options => {
  113. const {
  114. file,
  115. input,
  116. inputSourceMap,
  117. extractComments,
  118. minify: minifyFn
  119. } = options;
  120. if (minifyFn) {
  121. return minifyFn({ [file]: input }, inputSourceMap);
  122. }
  123. // Copy terser options
  124. const terserOptions = buildTerserOptions(options.terserOptions);
  125. // Add source map data
  126. if (inputSourceMap) {
  127. terserOptions.sourceMap = {
  128. content: inputSourceMap
  129. };
  130. }
  131. const extractedComments = [];
  132. if (extractComments) {
  133. terserOptions.output.comments = buildComments(options, terserOptions, extractedComments);
  134. }
  135. const { error, map, code, warnings } = _terser2.default.minify({ [file]: input }, terserOptions);
  136. return { error, map, code, warnings, extractedComments };
  137. };
  138. exports.default = minify;