webpack
Version:
Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jade, coffee, css, less, ... and your custom stuff.
449 lines (392 loc) • 11.4 kB
JavaScript
var path = require("path");
var fs = require("fs");
fs.existsSync = fs.existsSync || path.existsSync;
var resolve = require("enhanced-resolve");
module.exports = function(optimist, argv, convertOptions) {
var options = {};
// Help
if(argv.help) {
optimist.showHelp();
process.exit(-1);
}
// Shortcuts
if(argv.d) {
argv.debug = true;
argv["output-pathinfo"] = true;
if(!argv.devtool) {
argv.devtool = "sourcemap";
}
}
if(argv.p) {
argv["optimize-minimize"] = true;
argv["optimize-occurence-order"] = true;
}
if(argv.config) {
options = require(path.resolve(argv.config));
} else {
var configPath = path.resolve("webpack.config.js");
if(fs.existsSync(configPath)) {
options = require(configPath);
}
}
if(typeof options !== "object" || options === null) {
console.log("Config did not export a object.");
process.exit(-1);
}
if(Array.isArray(options)) {
options.forEach(processOptions);
} else {
processOptions(options);
}
if(argv.context) {
options.context = path.resolve(argv.context)
}
if(!options.context) {
options.context = process.cwd();
}
if(argv["watch"]) {
options.watch = true;
}
if(argv["watch-delay"]) {
options.watchDelay = +argv["watch-delay"];
}
function processOptions(options) {
function ifArg(name, fn, init, finalize) {
if(Array.isArray(argv[name])) {
if(init) {
init();
}
argv[name].forEach(fn);
if(finalize) {
finalize();
}
} else if(typeof argv[name] != "undefined") {
if(init) {
init();
}
fn(argv[name], -1);
if(finalize) {
finalize();
}
}
}
function ifArgPair(name, fn, init, finalize) {
ifArg(name, function(content, idx) {
var i = content.indexOf("=");
if(i < 0) {
return fn(null, content, idx);
} else {
return fn(content.substr(0, i), content.substr(i+1), idx);
}
}, init, finalize);
}
function ifBooleanArg(name, fn) {
ifArg(name, function(bool) {
if(bool) {
fn();
}
});
}
function mapArgToBoolean(name, optionName) {
ifBooleanArg(name, function() {
options[optionName || name] = true;
});
}
function mapArgToBooleanInverse(name, optionName) {
ifArg(name, function(bool) {
if(!bool) {
options[optionName || name] = false;
}
});
}
function mapArgToPath(name, optionName) {
ifArg(name, function(str) {
options[optionName || name] = path.resolve(str);
});
}
function loadPlugin(name) {
var path;
try {
path = resolve.sync(process.cwd(), name);
} catch(e) {
console.log("Cannot resolve plugin " + name + ".");
process.exit(-1);
}
var Plugin;
try {
Plugin = require(path);
} catch(e) {
console.log("Cannot load plugin " + name + ". (" + path + ")");
throw e;
}
try {
return new Plugin();
} catch(e) {
console.log("Cannot instantiate plugin " + name + ". (" + path + ")");
throw e;
}
}
function ensureObject(parent, name) {
if(typeof parent[name] !== "object" || parent[name] === null) {
parent[name] = {};
}
}
function ensureArray(parent, name) {
if(!Array.isArray(parent[name])) {
parent[name] = [];
}
}
ifArgPair("entry", function(name, entry) {
options.entry[name] = entry;
}, function() {
ensureObject(options, "entry");
});
function bindLoaders(arg, collection) {
ifArgPair(arg, function(name, binding) {
if(name === null) {
name = binding;
}
options.module[collection].push({
test: new RegExp("\\." + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "$"),
loader: binding
});
}, function() {
ensureObject(options, "module");
ensureArray(options.module, collection);
});
}
bindLoaders("module-bind", "loaders");
bindLoaders("module-bind-pre", "preLoaders");
bindLoaders("module-bind-post", "postLoaders");
var defineObject;
ifArgPair("define", function(name, value) {
if(name === null) {
name = value;
value = true;
}
defineObject[name] = value;
}, function() {
defineObject = {};
}, function() {
ensureArray(options, "plugins");
var DefinePlugin = require("../lib/DefinePlugin");
options.plugins.push(new DefinePlugin(defineObject));
});
ifArg("output-path", function(value) {
ensureObject(options, "output");
options.output.path = value;
});
ifArg("output-file", function(value) {
ensureObject(options, "output");
options.output.filename = value;
});
ifArg("output-chunk-file", function(value) {
ensureObject(options, "output");
options.output.chunkFilename = value;
});
ifArg("output-named-chunk-file", function(value) {
ensureObject(options, "output");
options.output.namedChunkFilename = value;
});
ifArg("output-source-map-file", function(value) {
ensureObject(options, "output");
options.output.sourceMapFilename = value;
});
ifArg("output-public-path", function(value) {
ensureObject(options, "output");
options.output.publicPath = value;
});
ifArg("output-jsonp-function", function(value) {
ensureObject(options, "output");
options.output.jsonpFunction = value;
});
ifBooleanArg("output-pathinfo", function() {
ensureObject(options, "output");
options.output.pathinfo = true;
});
ifArg("output-library", function(value) {
ensureObject(options, "output");
options.output.library = value;
});
ifArg("output-library-target", function(value) {
ensureObject(options, "output");
options.output.libraryTarget = value;
});
ifArg("records-input-path", function(value) {
options.recordsInputPath = path.resolve(value);
});
ifArg("records-output-path", function(value) {
options.recordsOutputPath = path.resolve(value);
});
ifArg("records-path", function(value) {
options.recordsPath = path.resolve(value);
});
ifArg("target", function(value) {
options.target = value;
});
mapArgToBooleanInverse("cache");
mapArgToBoolean("watch");
ifArg("watch-delay", function(value) {
options.watchDelay = value;
});
ifBooleanArg("hot", function() {
ensureArray(options, "plugins");
var HotModuleReplacementPlugin = require("../lib/HotModuleReplacementPlugin");
options.plugins.push(new HotModuleReplacementPlugin());
});
mapArgToBoolean("debug");
ifBooleanArg("progress", function() {
var ProgressPlugin = require("../lib/ProgressPlugin");
ensureArray(options, "plugins");
var chars = 0, lastState, lastStateTime;
options.plugins.push(new ProgressPlugin(function(percentage, msg) {
var state = msg;
if(percentage < 1) {
percentage = Math.floor(percentage * 100);
msg = percentage + "% " + msg;
if(percentage < 100) {
msg = " " + msg;
}
if(percentage < 10) {
msg = " " + msg;
}
}
for(; chars > msg.length; chars--) {
process.stderr.write("\b \b");
}
chars = msg.length;
for(var i = 0; i < chars; i++) {
process.stderr.write("\b");
}
if(options.profile) {
state = state.replace(/^\d+\/\d+\s+/, "");
if(percentage === 0) {
lastState = null;
lastStateTime = +new Date();
} else if(state !== lastState || percentage === 1) {
var now = +new Date();
if(lastState) {
process.stderr.write((now - lastStateTime) + "ms " + lastState + "\n");
}
lastState = state;
lastStateTime = now;
}
}
process.stderr.write(msg);
}));
});
ifArg("devtool", function(value) {
options.devtool = value;
});
function processResolveAlias(arg, key) {
ifArgPair(arg, function(name, value) {
if(!name) {
throw new Error("--" + arg + " <string>=<string>");
}
ensureObject(options, key);
ensureObject(options[key], "alias");
options[key].alias[name] = value;
});
}
processResolveAlias("resolve-alias", "resolve");
processResolveAlias("resolve-loader-alias", "resolveLoader");
ifArg("optimize-max-chunks", function(value) {
ensureArray(options, "plugins");
var LimitChunkCountPlugin = require("../lib/optimize/LimitChunkCountPlugin");
options.plugins.push(new LimitChunkCountPlugin({
maxChunks: parseInt(value, 10)
}));
});
ifArg("optimize-min-chunk-size", function(value) {
ensureArray(options, "plugins");
var LimitChunkSizePlugin = require("../lib/optimize/LimitChunkSizePlugin");
options.plugins.push(new LimitChunkSizePlugin(parseInt(value, 10)));
});
ifBooleanArg("optimize-minimize", function() {
ensureArray(options, "plugins");
var UglifyJsPlugin = require("../lib/optimize/UglifyJsPlugin");
options.plugins.push(new UglifyJsPlugin());
});
ifBooleanArg("optimize-occurence-order", function() {
ensureArray(options, "plugins");
var OccurenceOrderPlugin = require("../lib/optimize/OccurenceOrderPlugin");
options.plugins.push(new OccurenceOrderPlugin());
});
ifBooleanArg("optimize-dedupe", function() {
ensureArray(options, "plugins");
var DedupePlugin = require("../lib/optimize/DedupePlugin");
options.plugins.push(new DedupePlugin());
});
ifArg("prefetch", function(request) {
ensureArray(options, "plugins");
var PrefetchPlugin = require("../lib/PrefetchPlugin");
options.plugins.push(new PrefetchPlugin(request));
});
ifArg("provide", function(value) {
ensureArray(options, "plugins");
var idx = value.indexOf("=");
var name;
if(idx >= 0) {
name = value.substr(0, idx);
value = value.substr(idx + 1);
} else {
name = value;
}
var ProvidePlugin = require("../lib/ProvidePlugin");
options.plugins.push(new ProvidePlugin(name, value));
});
ifBooleanArg("labeled-modules", function() {
ensureArray(options, "plugins");
var LabeledModulesPlugin = require("../lib/dependencies/LabeledModulesPlugin");
options.plugins.push(new LabeledModulesPlugin());
});
ifArg("plugin", function(value) {
ensureArray(options, "plugins");
options.plugins.push(loadPlugin(value));
});
mapArgToBoolean("bail");
mapArgToBoolean("profile");
if(!options.output || !options.output.filename) {
ensureObject(options, "output");
if(convertOptions && convertOptions.outputFilename) {
options.output.path = path.dirname(convertOptions.outputFilename);
options.output.filename = path.basename(convertOptions.outputFilename);
} else if(argv._.length > 0) {
options.output.filename = argv._.pop();
options.output.path = path.dirname(options.output.filename);
options.output.filename = path.basename(options.output.filename);
} else {
optimist.showHelp();
process.exit(-1);
}
}
if(argv._.length > 0) {
ensureObject(options, "entry");
function addTo(name, entry) {
if(options.entry[name]) {
if(!Array.isArray(options.entry[name])) {
options.entry[name] = [options.entry[name]];
}
options.entry[name].push(entry);
} else {
options.entry[name] = entry;
}
}
argv._.forEach(function(content) {
var i = content.indexOf("=");
var j = content.indexOf("?");
if(i < 0 || (j >= 0 && j < i)) {
var resolved = path.resolve(content);
if(fs.existsSync(resolved)) {
addTo("main", resolved);
} else {
addTo("main", content);
}
} else {
addTo(content.substr(0, i), content.substr(i+1));
}
});
}
}
return options;
};