uglify.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * grunt-contrib-uglify
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2016 "Cowboy" Ben Alman, contributors
  6. * Licensed under the MIT license.
  7. */
  8. 'use strict';
  9. var path = require('path');
  10. var chalk = require('chalk');
  11. var maxmin = require('maxmin');
  12. var err;
  13. // Return the relative path from file1 => file2
  14. function relativePath(file1, file2) {
  15. var file1Dirname = path.dirname(file1);
  16. var file2Dirname = path.dirname(file2);
  17. if (file1Dirname !== file2Dirname) {
  18. return path.relative(file1Dirname, file2Dirname) + path.sep;
  19. }
  20. return '';
  21. }
  22. function reportFacility( grunt, options ){
  23. var reporter;
  24. switch( options.report ){
  25. case 'none':
  26. reporter = grunt.verbose;
  27. break;
  28. default:
  29. case 'min':
  30. case 'gzip':
  31. reporter = grunt.log;
  32. }
  33. return reporter;
  34. }
  35. // Converts \r\n to \n
  36. function normalizeLf(string) {
  37. return string.replace(/\r\n/g, '\n');
  38. }
  39. module.exports = function(grunt) {
  40. // Internal lib.
  41. var uglify = require('./lib/uglify').init(grunt);
  42. grunt.registerMultiTask('uglify', 'Minify files with UglifyJS.', function() {
  43. // Merge task-specific and/or target-specific options with these defaults.
  44. var options = this.options({
  45. banner: '',
  46. footer: '',
  47. compress: {
  48. warnings: false
  49. },
  50. mangle: {},
  51. beautify: false,
  52. report: 'min',
  53. expression: false,
  54. maxLineLen: 32000,
  55. ASCIIOnly: false,
  56. screwIE8: false,
  57. quoteStyle: 0
  58. });
  59. var log = reportFacility( grunt, options );
  60. // Process banner.
  61. var banner = normalizeLf(options.banner);
  62. var footer = normalizeLf(options.footer);
  63. var mapNameGenerator, mapInNameGenerator;
  64. var createdFiles = 0;
  65. var createdMaps = 0;
  66. // Iterate over all src-dest file pairs.
  67. this.files.forEach(function (f) {
  68. var src = f.src.filter(function (filepath) {
  69. // Warn on and remove invalid source files (if nonull was set).
  70. if (!grunt.file.exists(filepath)) {
  71. grunt.log.warn('Source file ' + chalk.cyan(filepath) + ' not found.');
  72. return false;
  73. }
  74. return true;
  75. });
  76. if (src.length === 0) {
  77. grunt.log.warn('Destination ' + chalk.cyan(f.dest) + ' not written because src files were empty.');
  78. return;
  79. }
  80. // Warn on incompatible options
  81. if (options.expression && (options.compress || options.mangle)) {
  82. grunt.log.warn('Option ' + chalk.cyan('expression') + ' not compatible with ' + chalk.cyan('compress and mangle'));
  83. options.compress = false;
  84. options.mangle = false;
  85. }
  86. // function to get the name of the sourceMap
  87. if (typeof options.sourceMapName === 'function') {
  88. mapNameGenerator = options.sourceMapName;
  89. }
  90. // function to get the name of the sourceMapIn file
  91. if (typeof options.sourceMapIn === 'function') {
  92. if (src.length !== 1) {
  93. grunt.fail.warn('Cannot generate `sourceMapIn` for multiple source files.');
  94. }
  95. mapInNameGenerator = options.sourceMapIn;
  96. }
  97. // dynamically create destination sourcemap name
  98. if (mapNameGenerator) {
  99. try {
  100. options.generatedSourceMapName = mapNameGenerator(f.dest);
  101. } catch (e) {
  102. err = new Error('SourceMap failed.');
  103. err.origError = e;
  104. grunt.fail.warn(err);
  105. }
  106. // If no name is passed append .map to the filename
  107. } else if (!options.sourceMapName) {
  108. options.generatedSourceMapName = f.dest + '.map';
  109. } else {
  110. options.generatedSourceMapName = options.sourceMapName;
  111. }
  112. // Dynamically create incoming sourcemap names
  113. if (mapInNameGenerator) {
  114. try {
  115. options.sourceMapIn = mapInNameGenerator(src[0]);
  116. } catch (e) {
  117. err = new Error('SourceMapInName failed.');
  118. err.origError = e;
  119. grunt.fail.warn(err);
  120. }
  121. }
  122. // Calculate the path from the dest file to the sourcemap for the
  123. // sourceMappingURL reference
  124. // If sourceMapUrl is defined, use this instead
  125. if(options.sourceMap) {
  126. var destToSourceMapPath, sourceMapBasename;
  127. if (!options.sourceMapUrl) {
  128. destToSourceMapPath = relativePath(f.dest, options.generatedSourceMapName);
  129. sourceMapBasename = path.basename(options.generatedSourceMapName);
  130. options.destToSourceMap = destToSourceMapPath + sourceMapBasename;
  131. } else {
  132. options.destToSourceMap = options.sourceMapUrl;
  133. }
  134. }
  135. // Minify files, warn and fail on error.
  136. var result;
  137. try {
  138. result = uglify.minify(src, f.dest, options);
  139. } catch (e) {
  140. console.log(e);
  141. err = new Error('Uglification failed.');
  142. if (e.message) {
  143. err.message += '\n' + e.message + '. \n';
  144. if (e.line) {
  145. err.message += 'Line ' + e.line + ' in ' + src + '\n';
  146. }
  147. }
  148. err.origError = e;
  149. grunt.log.warn('Uglifying source ' + chalk.cyan(src) + ' failed.');
  150. grunt.fail.warn(err);
  151. }
  152. // Concat minified source + footer
  153. var output = result.min + footer;
  154. // Only prepend banner if uglify hasn't taken care of it as part of the preamble
  155. if (!options.sourceMap) {
  156. output = banner + output;
  157. }
  158. // Write the destination file.
  159. grunt.file.write(f.dest, output);
  160. // Write source map
  161. if (options.sourceMap) {
  162. grunt.file.write(options.generatedSourceMapName, result.sourceMap);
  163. log.writeln('File ' + chalk.cyan(options.generatedSourceMapName) + ' created (source map).');
  164. createdMaps++;
  165. }
  166. var outputSize = maxmin(result.max, output, options.report === 'gzip');
  167. log.writeln('File ' + chalk.cyan(f.dest) + ' created: ' + outputSize);
  168. createdFiles++;
  169. });
  170. if (createdMaps > 0) {
  171. grunt.log.ok(createdMaps + ' source' + grunt.util.pluralize(createdMaps, 'map/maps') + ' created.');
  172. }
  173. if (createdFiles > 0) {
  174. grunt.log.ok(createdFiles + ' ' + grunt.util.pluralize(this.files.length, 'file/files') + ' created.');
  175. } else {
  176. grunt.log.warn('No files created.');
  177. }
  178. });
  179. };