blob: fc4fffe0a183fcf3f05254b9df2478b92e034422 [file]
/**
* @license
* Copyright 2017 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// A wrapper around terser-js that can handle minifying an entire
// directory. If the input is a directory then terser is run on
// each .js file in that folder and outputs to a specified output
// folder. If the input is a file then terser is just run
// one that individual file.
const fs = require('fs');
const path = require('path');
const tmp = require('tmp');
const child_process = require('child_process');
const DEBUG = false;
// capture the inputs and output options
const argv = require('minimist')(process.argv.slice(2));
const inputs = argv._;
const output = argv.output || argv.o;
const debug = argv.debug;
const configFile = argv['config-file'];
// delete the properties extracted above as the remaining
// arguments are forwarded to terser in execFileSync below
delete argv._;
delete argv.output;
delete argv.o;
delete argv.debug;
delete argv['config-file'];
if (DEBUG)
console.error(`
terser: running with
cwd: ${process.cwd()}
argv: ${process.argv.slice(2).join(' ')}
inputs: ${JSON.stringify(inputs)}
output: ${output}
debug: ${debug}
`);
if (inputs.length != 1) {
throw new Error(`Only one input file supported: ${inputs}`);
}
const input = inputs[0];
function runterser(inputFile, outputFile, sourceMapFile) {
if (DEBUG) console.error(`Minifying ${inputFile} -> ${outputFile} (sourceMap ${sourceMapFile})`);
const terserConfig = {
'sourceMap': {'filename': sourceMapFile},
'compress': {
'pure_getters': true,
'passes': 3,
'global_defs': {'ngDevMode': false, 'ngI18nClosureMode': false},
'keep_fnames': !debug,
'reduce_funcs': !debug,
'reduce_vars': !debug,
'sequences': !debug,
},
'mangle': !debug,
};
let config = configFile;
if (!config) {
config = tmp.fileSync({keep: false, postfix: '.json'}).name;
}
fs.writeFileSync(config, JSON.stringify(terserConfig));
const args = [
require.resolve('build_bazel_rules_nodejs_rollup_deps/node_modules/terser/bin/uglifyjs'),
inputFile, '--output', outputFile, '--config-file', config
];
for (arg in argv) {
const prefix = arg.length == 1 ? '-' : '--';
const value = argv[arg];
args.push(prefix + arg);
if (value && value !== true) {
args.push(value);
}
}
if (DEBUG) console.error(`Running node ${args.join(' ')}`);
const isWindows = /^win/i.test(process.platform);
child_process.execFileSync(
isWindows ? 'node.exe' : 'node', args,
{stdio: [process.stdin, process.stdout, process.stderr]});
}
const isDirectory = fs.lstatSync(path.join(process.cwd(), input)).isDirectory();
if (!isDirectory) {
runterser(input, output, output + '.map');
} else {
if (!fs.existsSync(output)) {
fs.mkdirSync(output);
}
const dir = fs.readdirSync(input);
dir.forEach(f => {
if (f.endsWith('.js')) {
const inputFile = path.join(input, path.basename(f));
const outputFile = path.join(output, path.basename(f));
// TODO(gregmagolan): parallelize this into multiple processes?
runterser(inputFile, outputFile, outputFile + '.map');
}
});
}