uglify.js 5.8 KB

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