UNPKG

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