UNPKG

4.96 kBJavaScriptView Raw
1var path = require('path');
2var mkdirp = require('mkdirp');
3var fs = require('fs');
4var Promise = require('bluebird');
5var asp = require('bluebird').promisify;
6var extend = require('./utils').extend;
7
8var fromFileURL = require('./utils').fromFileURL;
9var toFileURL = require('./utils').toFileURL;
10
11function countLines(str) {
12 return str.split(/\r\n|\r|\n/).length;
13}
14
15// Process compiler outputs, gathering:
16//
17// concatOutputs: list of source strings to concatenate
18// sourceMapsWithOffsets: list of [absolute offset,
19// source map string] pairs
20//
21// Takes lists as empty references and populates via push.
22function processOutputs(outputs) {
23 var removeSourceMaps = require('./sourcemaps').removeSourceMaps;
24
25 var offset = 0;
26
27 var outputObj = {};
28
29 var sources = outputObj.sources = [];
30 var sourceMapsWithOffsets = outputObj.sourceMapsWithOffsets = [];
31
32 outputs.forEach(function(output) {
33 var source;
34 if (typeof output == 'object') {
35 source = output.source || '';
36 var offset_ = output.sourceMapOffset || 0;
37 var map = output.sourceMap;
38 if (map) {
39 sourceMapsWithOffsets.push([offset + offset_, map]);
40 }
41 }
42 // NB perhaps we should enforce output is always an object down the chain?
43 else if (typeof output == 'string') {
44 source = output;
45 }
46 else {
47 var format = output ? output.toString() : typeof output;
48 throw new Error("Unexpected output format: " + format);
49 }
50 source = removeSourceMaps(source || '');
51 offset += countLines(source);
52 sources.push(source);
53 });
54
55 return outputObj;
56}
57
58function createOutput(outFile, outputs, basePath, sourceMaps, sourceMapContents) {
59 var concatenateSourceMaps = require('./sourcemaps').concatenateSourceMaps;
60
61 var outputObj = processOutputs(outputs);
62
63 if (sourceMaps)
64 var sourceMap = concatenateSourceMaps(outFile, outputObj.sourceMapsWithOffsets, basePath, sourceMapContents);
65
66 var output = outputObj.sources.join('\n');
67
68 return {
69 source: output,
70 sourceMap: sourceMap
71 };
72}
73
74function minify(output, fileName, mangle, uglifyOpts) {
75 var uglify = require('uglify-js');
76 var ast;
77 try{
78 ast = uglify.parse(output.source, { filename: fileName });
79 } catch(e){
80 throw new Error(e);
81 }
82 ast.figure_out_scope();
83
84 ast = ast.transform(uglify.Compressor(uglifyOpts.compress));
85 ast.figure_out_scope();
86 if (mangle !== false)
87 ast.mangle_names();
88
89 var sourceMap;
90 if (output.sourceMap) {
91 if (typeof output.sourceMap === 'string')
92 output.sourceMap = JSON.parse(output.sourceMap);
93
94 var sourceMapIn = output.sourceMap;
95 sourceMap = uglify.SourceMap({
96 file: fileName,
97 orig: sourceMapIn
98 });
99
100 if (uglifyOpts.sourceMapIncludeSources && sourceMapIn && Array.isArray(sourceMapIn.sourcesContent)) {
101 sourceMapIn.sourcesContent.forEach(function(content, idx) {
102 sourceMap.get().setSourceContent(sourceMapIn.sources[idx], content);
103 });
104 }
105 }
106
107 var outputOptions = uglifyOpts.beautify;
108 // keep first comment
109 outputOptions.comments = outputOptions.comments || function(node, comment) {
110 return comment.line === 1 && comment.col === 0;
111 };
112 outputOptions.source_map = sourceMap;
113
114 output.source = ast.print_to_string(outputOptions);
115 output.sourceMap = sourceMap;
116
117 return output;
118}
119
120function writeOutputFile(outFile, source, sourceMap) {
121 var outDir = path.dirname(outFile);
122
123 return asp(mkdirp)(path.dirname(outFile))
124 .then(function() {
125 if (!sourceMap)
126 return;
127
128 var sourceMapFileName = path.basename(outFile) + '.map';
129 source += '\n//# sourceMappingURL=' + sourceMapFileName;
130
131 return asp(fs.writeFile)(path.resolve(outDir, sourceMapFileName), sourceMap);
132 })
133 .then(function() {
134 return asp(fs.writeFile)(outFile, source);
135 });
136}
137
138exports.inlineSourceMap = inlineSourceMap;
139function inlineSourceMap(source, sourceMap) {
140 if (!sourceMap)
141 throw new Error('NOTHING TO INLINE');
142 return source + '\n//# sourceMappingURL=data:application/json;base64,'
143 + new Buffer(sourceMap.toString()).toString('base64');
144}
145
146exports.writeOutputs = function(outputs, baseURL, outputOpts) {
147 var outFile = outputOpts.outFile && path.resolve(outputOpts.outFile);
148 var basePath = fromFileURL(baseURL);
149 var fileName = outFile && path.basename(outFile) || 'output.js';
150
151 var output = createOutput(outFile || path.resolve(basePath, fileName), outputs, basePath, outputOpts.sourceMaps, outputOpts.sourceMapContents);
152
153 if (outputOpts.minify)
154 output = minify(output, fileName, outputOpts.mangle, outputOpts.uglify);
155
156 if (outputOpts.sourceMaps == 'inline') {
157 output.source = inlineSourceMap(output.source, output.sourceMap);
158 output.sourceMap = undefined;
159 }
160
161 if (!outputOpts.outFile)
162 return Promise.resolve(output);
163
164 return writeOutputFile(outFile, output.source, output.sourceMap).then(function() {
165 return output;
166 });
167};