UNPKG

4.39 kBJavaScriptView Raw
1var _ = require('underscore'),
2 async = require('async'),
3 FileMap = require('./util/file-map'),
4 fu = require('./fileUtil'),
5 ChildPool = require('child-pool');
6
7var uglify = new ChildPool(__dirname + '/uglify-worker', {logId: 'uglify-worker'});
8
9exports.combine = function(context, files, output, minimize, noSeparator, callback) {
10
11 function outputIfCompleted() {
12 if (completed >= files.length) {
13 var lastEl,
14 map = new FileMap(output),
15 warnings = [],
16
17 tasks = [];
18
19 _.each(content, function(el) {
20 var content = el.content.toString();
21
22 if (!noSeparator && (!lastEl || !lastEl.noSeparator) && map.content()) {
23 map.add(undefined, '\n;;\n');
24 }
25
26 map.add(el.name, content, el, el.generated);
27
28 lastEl = el;
29 }, '');
30
31 var inputs = [];
32 content.forEach(function(el) {
33 if (el.inputs) {
34 inputs.push.apply(inputs, el.inputs);
35 } else if (el.name) {
36 inputs.push(el.name);
37 }
38 });
39 inputs = _.unique(inputs);
40
41 // "Serialize" the data in the map
42 tasks.push(function(callback) {
43 callback(undefined, map.content());
44 });
45
46 // Minimize the content if flagged
47 if (minimize) {
48 var uglifyConfig = context.config.attributes.uglify || {};
49
50 tasks.push(function(data, callback) {
51 uglify.send({
52 output: output,
53 data: data,
54 compressorOptions: uglifyConfig.compressor,
55 manglerOptions: uglifyConfig.mangler,
56 outputOptions: uglifyConfig.output,
57 sourceMap: context.options.sourceMap ? map.sourceMap() : undefined
58 },
59 function(err, data) {
60 if (err) {
61 return callback(err);
62 }
63
64 _.each(data.warnings, function(msg) {
65 var match = /(.*?)\s*\[.*:(\d+),(\d+)/.exec(msg);
66 if (match) {
67 var msg = match[1],
68 line = parseInt(match[2], 10),
69 column = match[3],
70 context = map.context(line, column);
71
72 if (context && (!context.fileContext || !context.fileContext.ignoreWarnings)) {
73 context.msg = msg;
74 warnings.push(context);
75 }
76 } else {
77 warnings.push({msg: msg});
78 }
79 });
80
81 if (data.sourceMap) {
82 // Remap the sourcemap output for the point that it is actually used for output
83 // We need to restore the source map here as uglify will remove the original
84 // Declaration
85 map.sourceMap = function() { return data.sourceMap; };
86 }
87
88 callback(err, data.data);
89 });
90 });
91 }
92
93 // Output the source map if requested
94 var sourceMap = context.options.sourceMap;
95 if (sourceMap) {
96 var inlineSourceMap = sourceMap === true;
97
98 tasks.push(function(data, callback) {
99 map.writeSourceMap({
100 mapDestination: !inlineSourceMap && (sourceMap + '/' + context.buildPath),
101 outputSource: inlineSourceMap,
102 callback: function(err) {
103 if (inlineSourceMap) {
104 data += '\n' + map.sourceMapToken();
105 }
106 callback(err, data);
107 }
108 });
109 });
110 }
111
112 // Output step
113 tasks.push(function(data, callback) {
114 fu.writeFile(output, data, callback);
115 });
116
117 // Excute everything and return to the caller
118 async.waterfall(tasks, function(err) {
119 if (err) {
120 callback(new Error('Combined output "' + output + '" failed\n\t' + err));
121 return;
122 }
123
124 callback(undefined, {
125 fileName: output,
126 inputs: inputs,
127 warnings: warnings
128 });
129 });
130 }
131 }
132 var completed = 0,
133 content = [];
134
135 files.forEach(function(resource) {
136 var fileInfo = context.loadResource(resource, function(err) {
137 if (err && callback) {
138 callback(err);
139 callback = undefined;
140 return;
141 }
142
143 if (callback) {
144 completed++;
145 outputIfCompleted();
146 }
147 });
148 content.push(fileInfo);
149 });
150};