assetgraph
Version:
An auto discovery dependency graph based optimization framework for web pages and applications
170 lines (161 loc) • 5.14 kB
JavaScript
const _ = require('lodash');
const os = require('os');
const Promise = require('bluebird');
const errors = require('../errors');
const compressorByName = {};
for (const compressorName of ['uglifyJs', 'terser']) {
const compressorModule = require(compressorName.replace(
'uglifyJs',
'uglify-js'
));
compressorByName[compressorName] = async (
assetGraph,
javaScript,
compressorOptions
) => {
compressorOptions = compressorOptions || {};
const sourceMaps = compressorOptions.sourceMaps;
compressorOptions = Object.assign(
{},
_.omit(compressorOptions, 'sourceMaps')
);
const mangleOptions = compressorOptions.mangleOptions;
delete compressorOptions.mangleOptions;
_.defaults(
compressorOptions,
_.pick(javaScript.serializationOptions, ['side_effects']),
_.pick(assetGraph.javaScriptSerializationOptions, ['side_effects'])
);
let ie8;
if (
javaScript.serializationOptions &&
typeof javaScript.serializationOptions.ie8 !== 'undefined'
) {
ie8 = !!javaScript.serializationOptions.ie8;
} else if (
javaScript.serializationOptions &&
typeof javaScript.serializationOptions.screw_ie8 !== 'undefined'
) {
ie8 = !javaScript.serializationOptions.screw_ie8;
} else if (
assetGraph.javaScriptSerializationOptions &&
typeof assetGraph.javaScriptSerializationOptions.ie8 !== 'undefined'
) {
ie8 = !!assetGraph.javaScriptSerializationOptions.ie8;
} else if (
assetGraph.javaScriptSerializationOptions &&
typeof assetGraph.javaScriptSerializationOptions.screw_ie8 !== 'undefined'
) {
ie8 = !assetGraph.javaScriptSerializationOptions.screw_ie8;
}
let text;
let sourceMap;
if (sourceMaps) {
({ text, sourceMap } = javaScript.textAndSourceMap);
} else {
text = javaScript.text;
}
const { error, code, map } = await compressorModule.minify(text, {
sourceMap: { content: sourceMap },
compress: compressorOptions,
mangle: mangleOptions,
output: { comments: true, source_map: true, ast: true },
ie8,
});
if (error) {
throw new errors.ParseError({
message: `Parse error in ${javaScript.urlOrDescription}\n${
error.message
} (line ${error.line}, column ${error.col + 1})`,
line: error.line,
column: error.col + 1,
pos: error.pos,
asset: javaScript,
});
}
return {
type: 'JavaScript',
lastKnownByteLength: javaScript.lastKnownByteLength, // I know, I know
copyrightNoticeComments: javaScript.copyrightNoticeComments,
text: code,
isDirty: true,
_toBeMinified: javaScript._toBeMinified,
isPretty: javaScript.isPretty,
sourceMap: map,
};
};
}
compressorByName.yuicompressor = async (
assetGraph,
javaScript,
compressorOptions
) => {
let yuicompressor;
try {
yuicompressor = require('yui-compressor');
} catch (e) {
throw new Error(
"transforms.compressJavaScript: node-yui-compressor not found. Please run 'npm install yui-compressor' and try again (tested with version 0.1.3)."
);
}
compressorOptions = compressorOptions || {};
return {
type: 'JavaScript',
copyrightNoticeComments: javaScript.copyrightNoticeComments,
text: await Promise.fromNode((cb) =>
yuicompressor.compile(javaScript.text, compressorOptions, cb)
),
};
};
compressorByName.closurecompiler = async (
assetGraph,
javaScript,
compressorOptions
) => {
let closurecompiler;
try {
closurecompiler = require('closure-compiler');
} catch (e) {
throw new Error(
"transforms.compressJavaScript: node-closure-compiler not found. Please run 'npm install closure-compiler' and try again (tested with version 0.1.1)."
);
}
compressorOptions = compressorOptions || {};
return {
type: 'JavaScript',
copyrightNoticeComments: javaScript.copyrightNoticeComments,
text: await Promise.fromNode((cb) =>
closurecompiler.compile(javaScript.text, compressorOptions, cb)
),
};
};
module.exports = (queryObj, compressorName = 'terser', compressorOptions) => {
if (!compressorByName[compressorName]) {
throw new Error(
`transforms.compressJavaScript: Unknown compressor: ${compressorName}`
);
}
return async function compressJavaScript(assetGraph) {
await Promise.map(
assetGraph.findAssets({ type: 'JavaScript', ...queryObj }),
async (javaScript) => {
try {
const compressedJavaScript = await compressorByName[compressorName](
assetGraph,
javaScript,
compressorOptions
);
javaScript.replaceWith(compressedJavaScript);
compressedJavaScript.serializationOptions = {
...javaScript.serializationOptions,
};
compressedJavaScript.initialComments = javaScript.initialComments;
javaScript.unload();
} catch (err) {
assetGraph.warn(err);
}
},
{ concurrency: os.cpus().length + 1 }
);
};
};