function generateSyntaxTree(js, filePath) { uglify.base54.reset(); return uglify.parse(js, { filename: filePath }); }
compress.js = function(source){ if (!f.exists(source)) {return;} var sourceContent = f.read(source); //sourceContent = compress.addJsDepends(sourceContent); var options = { except: ['require','define'], ascii_only: true, copyright: true, beautify: false//美化代码 todo debug模式 //,mangle: false//是否压缩 失效的参数 }; var result = ''; try { //parse UglifyJS.base54.reset(); var toplevel = UglifyJS.parse(sourceContent); toplevel.figure_out_scope(); toplevel.mangle_names({except:options.except}); //output, has /*$ */ comments var stream = UglifyJS.OutputStream({ comments: function(scope, comment){ if(comment.type == 'comment2' && comment.value.charAt(0) === '$' && options.copyright) { return comment; } return false; }, beautify : options.beautify, ascii_only : options.ascii_only }); toplevel.print(stream); result += stream; result = compress.addJsDepends(source, result); //增加前缀banner result = compress.setPrefixBanner() + result; }catch (e) { if (e && e.message) { console.log('jdf error [compress.js] - '+source +' , line:'+e.line +', ' +e.message ); } } return result; };
filterdFiles.forEach((file) => { const oldWarnFunction = uglify.AST_Node.warn_function; const warnings = []; let sourceMap; try { const asset = compilation.assets[file]; if(asset.__UglifyJsPlugin) { compilation.assets[file] = asset.__UglifyJsPlugin; return; } let input; let inputSourceMap; if(options.sourceMap) { if(asset.sourceAndMap) { const sourceAndMap = asset.sourceAndMap(); inputSourceMap = sourceAndMap.map; input = sourceAndMap.source; } else { inputSourceMap = asset.map(); input = asset.source(); } sourceMap = new SourceMapConsumer(inputSourceMap); uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); const line = +match[1]; const column = +match[2]; const original = sourceMap.originalPositionFor({ line: line, column: column }); if(!original || !original.source || original.source === file) return; if(!warningsFilter(original.source)) return; warnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); }; } else { input = asset.source(); uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase warnings.push(warning); }; } uglify.base54.reset(); let ast = uglify.parse(input, { filename: file }); if(options.compress !== false) { ast.figure_out_scope(); const compress = uglify.Compressor(options.compress || { warnings: false }); // eslint-disable-line new-cap ast = ast.transform(compress); } if(options.mangle !== false) { ast.figure_out_scope(options.mangle || {}); ast.compute_char_frequency(options.mangle || {}); ast.mangle_names(options.mangle || {}); if(options.mangle && options.mangle.props) { uglify.mangle_properties(ast, options.mangle.props); } } const output = {}; output.comments = Object.prototype.hasOwnProperty.call(options, "comments") ? options.comments : /^\**!|@preserve|@license/; output.beautify = options.beautify; for(let k in options.output) { output[k] = options.output[k]; } const extractedComments = []; if(options.extractComments) { const condition = {}; if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { // extractComments specifies the extract condition and output.comments specifies the preserve condition condition.preserve = output.comments; condition.extract = options.extractComments; } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { // Extract condition is given in extractComments.condition condition.preserve = output.comments; condition.extract = options.extractComments.condition; } else { // No extract condition is given. Extract comments that match output.comments instead of preserving them condition.preserve = false; condition.extract = output.comments; } // Ensure that both conditions are functions ["preserve", "extract"].forEach(key => { switch(typeof condition[key]) { case "boolean": var b = condition[key]; condition[key] = () => b; break; case "function": break; case "string": if(condition[key] === "all") { condition[key] = () => true; break; } var regex = new RegExp(condition[key]); condition[key] = (astNode, comment) => regex.test(comment.value); break; default: regex = condition[key]; condition[key] = (astNode, comment) => regex.test(comment.value); } }); // Redefine the comments function to extract and preserve // comments according to the two conditions output.comments = (astNode, comment) => { if(condition.extract(astNode, comment)) { extractedComments.push( comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value ); } return condition.preserve(astNode, comment); }; } let map; if(options.sourceMap) { map = uglify.SourceMap({ // eslint-disable-line new-cap file: file, root: "" }); output.source_map = map; // eslint-disable-line camelcase } const stream = uglify.OutputStream(output); // eslint-disable-line new-cap ast.print(stream); if(map) map = map + ""; const stringifiedStream = stream + ""; let outputSource = (map ? new SourceMapSource(stringifiedStream, file, JSON.parse(map), input, inputSourceMap) : new RawSource(stringifiedStream)); if(extractedComments.length > 0) { let commentsFile = options.extractComments.filename || file + ".LICENSE"; if(typeof commentsFile === "function") { commentsFile = commentsFile(file); } // Write extracted comments to commentsFile const commentsSource = new RawSource(extractedComments.join("\n\n") + "\n"); if(commentsFile in compilation.assets) { // commentsFile already exists, append new comments... if(compilation.assets[commentsFile] instanceof ConcatSource) { compilation.assets[commentsFile].add("\n"); compilation.assets[commentsFile].add(commentsSource); } else { compilation.assets[commentsFile] = new ConcatSource( compilation.assets[commentsFile], "\n", commentsSource ); } } else { compilation.assets[commentsFile] = commentsSource; } // Add a banner to the original file if(options.extractComments.banner !== false) { let banner = options.extractComments.banner || "For license information please see " + commentsFile; if(typeof banner === "function") { banner = banner(commentsFile); } if(banner) { outputSource = new ConcatSource( "/*! " + banner + " */\n", outputSource ); } } } asset.__UglifyJsPlugin = compilation.assets[file] = outputSource; if(warnings.length > 0) { compilation.warnings.push(new Error(file + " from UglifyJs\n" + warnings.join("\n"))); } } catch(err) { if(err.line) { const original = sourceMap && sourceMap.originalPositionFor({ line: err.line, column: err.col }); if(original && original.source) { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]")); } else { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]")); } } else if(err.msg) { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.msg)); } else compilation.errors.push(new Error(file + " from UglifyJs\n" + err.stack)); } finally { uglify.AST_Node.warn_function = oldWarnFunction; // eslint-disable-line camelcase } });
files.forEach(function(file) { var oldWarnFunction = uglify.AST_Node.warn_function; var warnings = []; try { var asset = compilation.assets[file]; if(asset.__UglifyJsPlugin) { compilation.assets[file] = asset.__UglifyJsPlugin; return; } var input; if(options.sourceMap) { var inputSourceMap; if(asset.sourceAndMap) { var sourceAndMap = asset.sourceAndMap(); inputSourceMap = sourceAndMap.map; input = sourceAndMap.source; } else { inputSourceMap = asset.map(); input = asset.source(); } var sourceMap = new SourceMapConsumer(inputSourceMap); uglify.AST_Node.warn_function = function(warning) { // eslint-disable-line camelcase var match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); var line = +match[1]; var column = +match[2]; var original = sourceMap.originalPositionFor({ line: line, column: column }); if(!original || !original.source || original.source === file) return; warnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); }; } else { input = asset.source(); uglify.AST_Node.warn_function = function(warning) { // eslint-disable-line camelcase warnings.push(warning); }; } uglify.base54.reset(); var ast = uglify.parse(input, { filename: file }); if(options.compress !== false) { ast.figure_out_scope(); var compress = uglify.Compressor(options.compress || { warnings: false }); // eslint-disable-line new-cap ast = ast.transform(compress); } if(options.mangle !== false) { ast.figure_out_scope(); ast.compute_char_frequency(options.mangle || {}); ast.mangle_names(options.mangle || {}); if(options.mangle && options.mangle.props) { uglify.mangle_properties(ast, options.mangle.props); } } var output = {}; output.comments = Object.prototype.hasOwnProperty.call(options, "comments") ? options.comments : /^\**!|@preserve|@license/; output.beautify = options.beautify; for(var k in options.output) { output[k] = options.output[k]; } if(options.sourceMap) { var map = uglify.SourceMap({ // eslint-disable-line new-cap file: file, root: "" }); output.source_map = map; // eslint-disable-line camelcase } var stream = uglify.OutputStream(output); // eslint-disable-line new-cap ast.print(stream); if(map) map = map + ""; stream = stream + ""; asset.__UglifyJsPlugin = compilation.assets[file] = (map ? new SourceMapSource(stream, file, JSON.parse(map), input, inputSourceMap) : new RawSource(stream)); if(warnings.length > 0) { compilation.warnings.push(new Error(file + " from UglifyJs\n" + warnings.join("\n"))); } } catch(err) { if(err.line) { var original = sourceMap && sourceMap.originalPositionFor({ line: err.line, column: err.col }); if(original && original.source) { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]")); } else { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]")); } } else if(err.msg) { compilation.errors.push(new Error(file + " from UglifyJs\n" + err.msg)); } else compilation.errors.push(new Error(file + " from UglifyJs\n" + err.stack)); } finally { uglify.AST_Node.warn_function = oldWarnFunction; // eslint-disable-line camelcase } });
return new FileTransform(function (file) { switch (path.extname(file.path)) { case ".js": codeFile = file; break; case ".map": sourceMapFile = file; break; } if (codeFile !== null && sourceMapFile !== null) { UglifyJS.base54.reset(); // Parse var root = null; root = UglifyJS.parse(codeFile.contents.toString(), { filename: path.basename(codeFile.path), toplevel: root }); root.figure_out_scope({ screw_ie8: true }); // Warnings root.scope_warnings({ func_arguments: false }); // Compress var compressor = UglifyJS.Compressor({ warnings: true, screw_ie8: true }); root = root.transform(compressor); // Mangle root.figure_out_scope({ screw_ie8: true }); root.compute_char_frequency(); root.mangle_names({ screw_ie8: true }); // Mangle private members var occurrences = Object.create(null); root.walk(new UglifyJS.TreeWalker(function (node, descend) { if ( node instanceof UglifyJS.AST_PropAccess && typeof node.property === "string" && node.property[0] === "_" && node.property[1] !== "_" && // Doesn't start with two leading underscores node.property !== "_classTag" // webworker serializer uses this property by name, so it shouldn't be changed. ) { var occurrence = occurrences[node.property]; if (occurrence === undefined) { occurrences[node.property] = 1; } else { occurrences[node.property]++; } } })); var identifiers = Object.keys(occurrences); identifiers.sort(function (first, second) { return occurrences[second] - occurrences[first]; }); var generatedIdentifiers = occurrences; var validIdentifierCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; var toIdentifier = function (index) { var result = validIdentifierCharacters[(index % validIdentifierCharacters.length)]; index = (index / validIdentifierCharacters.length) | 0; while (index > 0) { index--; result = validIdentifierCharacters[index % validIdentifierCharacters.length] + result; index = (index / validIdentifierCharacters.length) | 0; } return "_" + result; }; identifiers.forEach(function (identifier, index) { generatedIdentifiers[identifier] = toIdentifier(index); }); root.walk(new UglifyJS.TreeWalker(function (node, descend) { if ( node instanceof UglifyJS.AST_PropAccess && typeof node.property === "string" && node.property in generatedIdentifiers ) { node.property = generatedIdentifiers[node.property]; } })); // Output var firstLicenseHeaderFound = false; // To detect and preserve the first license header var output = { source_map: UglifyJS.SourceMap({ file: path.basename(sourceMapFile.path), orig: sourceMapFile.contents.toString() }), comments: function (node, comment) { if (!firstLicenseHeaderFound && comment.value.indexOf("Copyright") !== -1) { firstLicenseHeaderFound = true; return true; } return false; }, screw_ie8: true }; var stream = UglifyJS.OutputStream(output); root.print(stream); codeFile.path = codeFile.path.replace(/\.js$/, ".min.js"); sourceMapFile.path = sourceMapFile.path.replace(/\.js\.map$/, ".min.js.map"); codeFile.contents = Buffer.concat([new Buffer(stream.toString()), new Buffer("\n//# sourceMappingURL="), new Buffer(sourceMapFile.path)]); this.push(codeFile); var inputSourceMapObject = JSON.parse(sourceMapFile.contents.toString()); var outputSourceMapObject = output.source_map.get(); outputSourceMapObject._sources.toArray().forEach(function (filename, i) { outputSourceMapObject.setSourceContent(filename, inputSourceMapObject.sourcesContent[i]); }); sourceMapFile.contents = new Buffer(output.source_map.toString()); this.push(sourceMapFile); codeFile = null; sourceMapFile = null; } });
process.on('message', function(msg) { var oldWarnFunction = uglify.AST_Node.warn_function; var warnings = []; var errors = []; var stream = ''; var map = ''; try { if (msg.options.sourceMap !== false) { var sourceMap = new SourceMapConsumer(msg.inputSourceMap); uglify.AST_Node.warn_function = function(warning) { // eslint-disable-line camelcase var match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); var line = +match[1]; var column = +match[2]; var original = sourceMap.originalPositionFor({ line: line, column: column }); if (!original || !original.source || original.source === msg.file) return; warnings.push({ message: warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, ''), original: original.source, line: original.line, column: original.column }); }; } else { uglify.AST_Node.warn_function = function(warning) { // eslint-disable-line camelcase warnings.push(warning); }; } uglify.base54.reset(); var ast = uglify.parse(msg.input, { filename: msg.file }); if (msg.options.compress !== false) { ast.figure_out_scope(); var compress = uglify.Compressor(msg.options.compress); // eslint-disable-line new-cap ast = ast.transform(compress); } if (msg.options.mangle !== false) { ast.figure_out_scope(); ast.compute_char_frequency(msg.options.mangle || {}); ast.mangle_names(msg.options.mangle || {}); if (msg.options.mangle && msg.options.mangle.props) { uglify.mangle_properties(ast, msg.options.mangle.props); } } var output = {}; output.comments = Object.prototype.hasOwnProperty.call(msg.options, 'comments') ? msg.options.comments : /^\**!|@preserve|@license/; output.beautify = msg.options.beautify; for (var k in msg.options.output) { output[k] = msg.options.output[k]; } if (msg.options.sourceMap !== false) { var map = uglify.SourceMap({ // eslint-disable-line new-cap file: msg.file, root: '' }); output.source_map = map; // eslint-disable-line camelcase } var stream = uglify.OutputStream(output); // eslint-disable-line new-cap ast.print(stream); if (map) { map = map + ''; } else { msg.input = ''; msg.inputSourceMap = ''; } stream = stream + ''; } catch (err) { if (err.line) { var original = sourceMap && sourceMap.originalPositionFor({ line: err.line, column: err.col }); if (original && original.source) { errors.push({ original: original.source, line: original.line, column: original.column }); } else { errors.push({ message: err.message, line: err.line, col: err.col }); } } else if (err.msg) { errors.push({ msg: err.msg }); } else { errors.push({ stack: err.stack }); } } finally { uglify.AST_Node.warn_function = oldWarnFunction; // eslint-disable-line camelcase process.send({ file: msg.file, errors: errors, warnings: warnings, source: stream, map: map, input: msg.input, inputSourceMap: msg.inputSourceMap }); } });
compress.js = function(source, isdebug){ var isdebug = isdebug || false; if (!f.exists(source)) { return; } var sourceContent = f.read(source); //sourceContent = compress.addJsDepends(sourceContent); var options = { remove: [],// except: ['require','define'],//不压缩的字符名 ascii_only: true,//输出Unicode characters beautify: false,//美化代码 warnings: false//显示压缩报错 //,mangle: false//是否压缩 失效的参数 }; if(jdf.config.output.jsRemove){ options.remove = jdf.config.output.jsRemove; } var result = sourceContent; try { if (!isdebug){ //parse UglifyJS.base54.reset(); var toplevel = UglifyJS.parse(sourceContent); toplevel.figure_out_scope(); var compressorOption = { hoist_funs : false, //函数声明至顶端 //fromString: true, //说明代码源的格式是否为字符串 //mangle: true, //是否压缩,只要配置就不压缩了 warnings: false, //显示压缩报错 join_vars: false } if (options.warnings) { compressorOption.warnings = options.warnings; } //remove console.log var matchRemoveOption = function(host, method){ return !options.remove.every(function(element){ if(element.indexOf(".") == -1){ return element != host; } return element != host + '.' + method; }); } var removeConsoleTransformer = new UglifyJS.TreeTransformer(function(node, descend){ if(node instanceof UglifyJS.AST_Call){ var host, method; try{ host = node.expression.start.value; method = node.expression.end.value; }catch(err){ } if(host && method){ if(matchRemoveOption(host, method)){ return new UglifyJS.AST_Atom(); } } } descend(node, this); return node; }); toplevel = toplevel.transform(removeConsoleTransformer); var compressor = UglifyJS.Compressor(compressorOption); toplevel = toplevel.transform(compressor); toplevel.mangle_names({except:options.except}); //output, has /*$ */ comments var stream = UglifyJS.OutputStream({ comments: function(scope, comment){ if ( isdebug ){ return true; }else{ if(comment.type == 'comment2' && comment.value.charAt(0) === '$' && options.copyright){ return comment; } return false; } }, space_colon : false, //quote_keys: true, object keys加引号 beautify: options.beautify, ascii_only: options.ascii_only }); toplevel.print(stream); result = stream.get(); } //增加前缀banner if(!isdebug){ result = compress.setPrefixBanner(jdf.config.output.hasBanner, source, result) + result + '\r\n'; } }catch (e) { if (e && e.message) { console.log('jdf error [compress.js] - '+source +' , line:'+e.line +', ' +e.message ); } } return result; };