uglify.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * grunt-contrib-uglify
  3. * https://gruntjs.com/
  4. *
  5. * Copyright (c) 2017 "Cowboy" Ben Alman, contributors
  6. * Licensed under the MIT license.
  7. */
  8. 'use strict';
  9. // External libs.
  10. var path = require('path');
  11. var UglifyJS = require('uglify-js');
  12. var uriPath = require('uri-path');
  13. var domprops = require('uglify-js/tools/domprops');
  14. // Converts \r\n to \n
  15. function normalizeLf(string) {
  16. return string.replace(/\r\n/g, '\n');
  17. }
  18. function toCache(cache, key) {
  19. if (cache[key]) {
  20. cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props);
  21. } else {
  22. cache[key] = {
  23. cname: -1,
  24. props: new UglifyJS.Dictionary()
  25. };
  26. }
  27. return cache[key];
  28. }
  29. exports.init = function(grunt) {
  30. var exports = {};
  31. // Minify with UglifyJS.
  32. // From https://github.com/mishoo/UglifyJS2
  33. exports.minify = function(files, dest, options) {
  34. options = options || {};
  35. grunt.verbose.write('Minifying with UglifyJS...');
  36. var totalCode = '';
  37. var minifyOptions = {
  38. compress: options.compress,
  39. ie8: options.ie8,
  40. keep_fnames: options.keep_fnames,
  41. mangle: options.mangle,
  42. output: options.output || {},
  43. parse: options.parse || {},
  44. sourceMap: options.sourceMap,
  45. toplevel: options.toplevel,
  46. wrap: options.wrap
  47. };
  48. if (options.banner) {
  49. minifyOptions.output.preamble = normalizeLf(options.banner);
  50. }
  51. if (options.beautify) {
  52. minifyOptions.output.beautify = true;
  53. for (var key in options.beautify) {
  54. minifyOptions.output[key] = options.beautify[key];
  55. }
  56. }
  57. var cache;
  58. if (options.nameCache) {
  59. try {
  60. cache = JSON.parse(grunt.file.read(options.nameCache));
  61. } catch (ex) {
  62. cache = {};
  63. }
  64. }
  65. if (minifyOptions.mangle) {
  66. if (typeof minifyOptions.mangle !== 'object') {
  67. minifyOptions.mangle = {};
  68. }
  69. if (cache) {
  70. minifyOptions.mangle.cache = toCache(cache, 'vars');
  71. }
  72. if (!Array.isArray(minifyOptions.mangle.reserved)) {
  73. minifyOptions.mangle.reserved = [];
  74. }
  75. if (minifyOptions.mangle.properties) {
  76. if (typeof minifyOptions.mangle.properties !== 'object') {
  77. minifyOptions.mangle.properties = {};
  78. }
  79. if (cache) {
  80. minifyOptions.mangle.properties.cache = toCache(cache, 'props');
  81. }
  82. if (!Array.isArray(minifyOptions.mangle.properties.reserved)) {
  83. minifyOptions.mangle.properties.reserved = [];
  84. }
  85. if (options.reserveDOMProperties) {
  86. domprops.forEach(function(name) {
  87. UglifyJS.push_uniq(minifyOptions.mangle.properties.reserved, name);
  88. });
  89. }
  90. }
  91. if (options.exceptionsFiles) {
  92. options.exceptionsFiles.forEach(function(file) {
  93. try {
  94. var obj = JSON.parse(grunt.file.read(file));
  95. if (minifyOptions.mangle && obj.vars) {
  96. obj.vars.forEach(function(name) {
  97. UglifyJS.push_uniq(minifyOptions.mangle.reserved, name);
  98. });
  99. }
  100. if (minifyOptions.mangle.properties && obj.props) {
  101. obj.props.forEach(function(name) {
  102. UglifyJS.push_uniq(minifyOptions.mangle.properties.reserved, name);
  103. });
  104. }
  105. } catch (ex) {
  106. grunt.warn(ex);
  107. }
  108. });
  109. }
  110. }
  111. var result = UglifyJS.minify(files.reduce(function(o, file) {
  112. var code = grunt.file.read(file);
  113. totalCode += code;
  114. // The src file name must be relative to the source map for things to work
  115. var basename = path.basename(file);
  116. var fileDir = path.dirname(file);
  117. var sourceMapDir = path.dirname(options.generatedSourceMapName);
  118. var relativePath = path.relative(sourceMapDir, fileDir);
  119. var pathPrefix = relativePath ? relativePath + path.sep : '';
  120. // Convert paths to use forward slashes for sourcemap use in the browser
  121. o[uriPath(pathPrefix + basename)] = code;
  122. return o;
  123. }, {}), minifyOptions);
  124. if (result.error) {
  125. throw result.error;
  126. }
  127. if (options.nameCache) {
  128. grunt.file.write(options.nameCache, JSON.stringify(cache, function(key, value) {
  129. return value instanceof UglifyJS.Dictionary ? value.toObject() : value;
  130. }));
  131. }
  132. grunt.verbose.ok();
  133. return {
  134. max: totalCode,
  135. min: result.code,
  136. sourceMap: result.map
  137. };
  138. };
  139. return exports;
  140. };