webpack/lib/webpack.js

532 lines
16 KiB
JavaScript
Raw Normal View History

2012-03-12 04:50:55 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2012-03-10 20:11:23 +08:00
var buildDeps = require("./buildDeps");
var writeChunk = require("./writeChunk");
2012-05-21 06:09:30 +08:00
var Cache = require("./Cache");
var path = require("path");
2012-03-10 20:11:23 +08:00
var fs = require("fs");
2012-07-01 22:55:58 +08:00
var fileExists = fs.exists || path.exists;
2012-03-10 20:11:23 +08:00
2012-05-01 23:46:26 +08:00
var HASH_REGEXP = /\[hash\]/i;
2012-03-10 20:11:23 +08:00
/*
webpack(context, moduleName, options, callback);
webpack(absoluteModulePath, options, callback);
2012-03-12 04:50:55 +08:00
2012-03-10 20:11:23 +08:00
callback: function(err, source / stats)
source if options.output is not set
else stats json
2012-03-12 04:50:55 +08:00
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
options: see README.md
2012-03-10 20:11:23 +08:00
*/
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
module.exports = function webpackMain(context, moduleName, options, callback) {
2012-05-12 22:43:37 +08:00
// Support multiple call signitures
2012-03-10 20:11:23 +08:00
if(typeof moduleName === "object") {
callback = options;
options = moduleName;
2012-07-17 19:25:01 +08:00
context = context.split("!");
var file = context.pop();
context.push("./" + path.basename(file));
moduleName = context.join("!");
context = path.dirname(file);
2012-03-10 20:11:23 +08:00
}
2012-05-12 22:43:37 +08:00
// Defaults
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
// Create a options.events as EventEmitter
if(!options.events) options.events = new (require("events").EventEmitter)();
if(!options.outputJsonpFunction)
options.outputJsonpFunction = "webpackJsonp" + (options.libary || "");
options.publicPrefix = options.publicPrefix || "";
2012-07-11 08:15:39 +08:00
options.context = options.context || context;
2012-08-07 03:49:16 +08:00
options.emitFile = options.emitFile || function(filename, content, toFront) {
options.internal.fileWrites[toFront?"unshift":"push"]([path.join(options.outputDirectory, filename), content]);
}
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
if(options.workers === true) {
options.workers = require("os").cpus().length;
}
if(typeof options.workers == "number") {
2012-09-26 18:28:23 +08:00
options.workers = new (require("./Workers"))(path.join(__dirname, "worker.js"), options.workers);
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
}
if(options.workers && options.closeWorkers !== false) {
if(options.watch) {
options.events.on("watch-end", function() {
if(options.closeWorkers === false) return;
options.workers.close();
});
} else {
options.events.on("bundle", function() {
if(options.closeWorkers === false) return;
options.workers.close();
});
}
}
if(options.output) {
if(!options.outputDirectory) {
options.outputDirectory = path.dirname(options.output);
options.output = path.basename(options.output);
}
if(!options.outputPostfix) {
options.outputPostfix = "." + options.output;
}
} else {
return callback(new Error("options.output is required"));
}
options.parse = options.parse || {};
options.parse.overwrites = options.parse.overwrites || {};
options.parse.overwrites.process = options.parse.overwrites.process || ("__webpack_process");
options.parse.overwrites.module = options.parse.overwrites.module || ("__webpack_module+(module)");
options.parse.overwrites.console = options.parse.overwrites.console || ("__webpack_console");
options.parse.overwrites.global = options.parse.overwrites.global || ("__webpack_global");
options.parse.overwrites.Buffer = options.parse.overwrites.Buffer || ("buffer+.Buffer");
options.parse.overwrites["__dirname"] = options.parse.overwrites["__dirname"] || ("__webpack_dirname");
options.parse.overwrites["__filename"] = options.parse.overwrites["__filename"] || ("__webpack_filename");
options.resolve = options.resolve || {};
options.resolve.paths = options.resolve.paths || [];
options.resolve.paths.push(path.join(path.dirname(__dirname), "buildin"));
options.resolve.paths.push(path.join(path.dirname(__dirname), "buildin", "web_modules"));
options.resolve.paths.push(path.join(path.dirname(__dirname), "node_modules"));
options.resolve.alias = options.resolve.alias || {};
options.resolve.loaders = options.resolve.loaders || [];
2012-09-26 18:28:23 +08:00
options.resolve.loaders.push({test: "\\.coffee$", loader: "coffee"});
options.resolve.loaders.push({test: "\\.json$", loader: "json"});
options.resolve.loaders.push({test: "\\.jade$", loader: "jade"});
options.resolve.loaders.push({test: "\\.css$", loader: "style!css"});
2012-09-26 19:40:00 +08:00
options.resolve.loaders.push({test: "\\.less$", loader: "style!css!val/seperable/cacheable!less"});
2012-08-13 22:50:42 +08:00
if(!options.resolve.extensions)
options.resolve.extensions = ["", ".webpack.js", ".web.js", ".js"];
if(!options.resolve.postfixes)
options.resolve.postfixes = ["", "-webpack", "-web"];
if(!options.resolve.loaderExtensions)
options.resolve.loaderExtensions = [".webpack-web-loader.js", ".webpack-loader.js", ".web-loader.js", ".loader.js", "", ".js"];
if(!options.resolve.loaderPostfixes)
options.resolve.loaderPostfixes = ["-webpack-web-loader", "-webpack-loader", "-web-loader", "-loader", ""];
if(!options.resolve.modulesDirectorys)
options.resolve.modulesDirectorys = ["web_modules", "jam", "node_modules"];
if(!options.resolve.alias)
options.resolve.alias = {};
if(!options.resolve.postprocess)
options.resolve.postprocess = {};
if(!options.resolve.postprocess.normal)
options.resolve.postprocess.normal = [];
if(!options.resolve.postprocess.context)
options.resolve.postprocess.context = [];
2012-07-11 18:18:31 +08:00
options.preLoaders = options.preLoaders || [];
options.postLoaders = options.postLoaders || [];
options.loader = options.loader || {};
options.loader.emitFile = options.loader.emitFile || options.emitFile;
options.loader.emitSubStats = options.loader.emitSubStats || function(stats) {
options.internal.subStats.push(stats);
}
2012-05-12 22:43:37 +08:00
// Register listeners to support watch mode
2012-05-02 03:33:59 +08:00
if(options.watch) {
var fs = require("fs");
var watchers = [];
2012-05-12 22:43:37 +08:00
var timeout;
2012-05-02 03:33:59 +08:00
var isRunning = true;
2012-05-12 22:43:37 +08:00
var isWaiting = false;
2012-05-02 03:33:59 +08:00
var runAgain = false;
var staticChanges = [];
2012-05-12 22:43:37 +08:00
// Start the timeout again
2012-05-02 03:33:59 +08:00
function startAgain() {
if(!isWaiting)
options.events.emit("bundle-invalid");
2012-05-12 22:43:37 +08:00
isWaiting = true;
if(timeout)
clearTimeout(timeout);
timeout = setTimeout(function() {
watchers.forEach(function(watcher) {
watcher.close();
});
watchers.length = 0;
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
if(staticChanges.length > 0) {
callback(new Error(
"Files (" + staticChanges.join(", ") +
") changed. Webpack cannot recompile in this watch step."));
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
return options.events.emit("watch-end");
}
2012-05-02 03:33:59 +08:00
runAgain = false;
2012-05-12 22:43:37 +08:00
isRunning = true;
isWaiting = false;
2012-05-12 22:43:37 +08:00
// compile
2012-05-02 03:33:59 +08:00
webpack(context, moduleName, options, callback);
2012-05-12 22:43:37 +08:00
}, options.watchDelay || 200);
2012-05-02 03:33:59 +08:00
}
2012-05-12 22:43:37 +08:00
// on change
2012-05-02 03:33:59 +08:00
function change() {
if(isRunning)
runAgain = true;
else
startAgain()
}
2012-05-12 22:43:37 +08:00
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
function staticChange(filename) {
if(staticChanges.indexOf(filename) == -1)
staticChanges.push(filename);
change();
}
2012-05-21 06:16:33 +08:00
2012-05-12 22:43:37 +08:00
// on before a context is enumerated
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
options.events.on("context-enum", function(module, dirname) {
2012-05-02 03:33:59 +08:00
if(!dirname) return;
2012-05-12 22:43:37 +08:00
watchers.push(fs.watch(dirname, function() {
2012-05-02 03:33:59 +08:00
change();
2012-05-12 22:43:37 +08:00
}));
2012-05-02 03:33:59 +08:00
});
2012-05-12 22:43:37 +08:00
// on user defines the bundle as invalid
options.events.on("invalid", function() {
change();
});
2012-05-12 22:43:37 +08:00
// on bundle finished compiling
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
var bundleToken = null;
2012-05-02 03:33:59 +08:00
options.events.on("bundle", function(stats) {
isRunning = false;
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
bundleToken = "" + Math.random();
2012-05-02 03:33:59 +08:00
if(runAgain)
startAgain();
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
else {
// Bind watchers
var token = bundleToken;
stats.dependencies.forEach(function(dep) {
watchers.push(fs.watch(dep, change));
fs.stat(dep, function(err, stat) {
if(bundleToken != token) return;
if(err) return change();
if(stat.mtime.getTime() > stats.startTime)
change();
});
});
stats.loaders.forEach(function(dep) {
watchers.push(fs.watch(dep, staticChange.bind(null, dep)));
fs.stat(dep, function(err, stat) {
if(bundleToken != token) return;
if(err) return staticChange(dep);
if(stat.mtime.getTime() > stats.startTime)
staticChange(dep);
});
});
}
2012-05-02 03:33:59 +08:00
});
2012-05-21 06:09:30 +08:00
if(!options.cache)
options.cache = new Cache(options.cacheOptions);
2012-05-02 03:33:59 +08:00
}
2012-05-12 22:43:37 +08:00
// compile
2012-05-02 03:33:59 +08:00
return webpack(context, moduleName, options, callback);
}
2012-05-12 22:43:37 +08:00
function webpack(context, moduleName, options, callback) {
2012-07-11 01:31:22 +08:00
var startTime = new Date();
2012-05-12 22:43:37 +08:00
2012-07-11 01:31:22 +08:00
options.internal = {};
2012-05-12 22:43:37 +08:00
// all writes to files
// items: [filename, content]
var fileWrites = [], subStats = [];
2012-07-11 01:31:22 +08:00
options.internal.fileWrites = fileWrites;
options.internal.subStats = subStats;
2012-05-12 22:43:37 +08:00
// Some status info
if(!options.noWrite) options.events.emit("task", "create ouput directory");
2012-05-02 20:06:42 +08:00
options.events.emit("task", "prepare chunks");
options.events.emit("task", "statistics");
2012-05-12 22:43:37 +08:00
// build up the dependency tree
2012-03-10 20:11:23 +08:00
buildDeps(context, moduleName, options, function(err, depTree) {
if(err) {
callback(err);
return;
}
var buffer = [];
2012-05-12 22:43:37 +08:00
// collect which chunks exists
var chunksCount = 0;
2012-05-12 22:43:37 +08:00
// all ids of the chunks, in desc order
var chunkIds = Object.keys(depTree.chunks);
chunkIds.sort(function(a,b) {
if(typeof depTree.chunks[b].realId !== "number") return 1;
if(typeof depTree.chunks[a].realId !== "number") return -1;
return depTree.chunks[b].realId - depTree.chunks[a].realId;
});
2012-05-12 22:43:37 +08:00
// the template used
var template = getTemplate(options, {chunks: chunkIds.length > 1});
// hash as crypto.Hash instance
// for compution
var hash;
try {
hash = new (require("crypto").Hash)("md5");
hash.update(JSON.stringify(options.libary || ""));
hash.update(JSON.stringify(options.outputPostfix));
hash.update(JSON.stringify(options.outputJsonpFunction));
hash.update(JSON.stringify(options.publicPrefix));
hash.update(template);
hash.update("1");
} catch(e) {
// if this didn't work
// we do not use a hash
hash = null;
}
2012-05-12 22:43:37 +08:00
// for each chunk
for(var i = 0; i < chunkIds.length; i++) {
var chunkId = chunkIds[i];
var chunk = depTree.chunks[chunkId];
// check is chunk is empty or a duplicate
if(chunk.empty) continue;
if(chunk.equals !== undefined) continue;
chunksCount++;
// build filename
var filename = chunk.filename = chunk.realId === 0 ? options.output : chunk.realId + options.outputPostfix;
// get content of chunk
var content = writeChunk(depTree, chunk, options);
if(hash) hash.update(content);
buffer = [];
if(chunk.realId === 0) { // initial chunk
if(hash)
hash = hash.digest("hex");
else
hash = "";
// if it should be a libary, we prepend a variable name
if(options.libary) {
buffer.push("/******/var ");
buffer.push(options.libary);
buffer.push("=\n");
2012-03-10 20:11:23 +08:00
}
2012-05-12 22:43:37 +08:00
// write the template
buffer.push(template);
// write extra info into object
buffer.push("/******/({");
if(chunkIds.length > 1) {
buffer.push("a:");
buffer.push(JSON.stringify(options.outputPostfix.replace(HASH_REGEXP, hash)));
buffer.push(",b:");
buffer.push(JSON.stringify(options.outputJsonpFunction));
buffer.push(",");
2012-03-27 06:00:32 +08:00
}
buffer.push("c:");
buffer.push(JSON.stringify(options.publicPrefix.replace(HASH_REGEXP, hash)));
buffer.push(",\n");
} else { // lazy loaded chunk
// write only jsonp function and chunk id as function call
buffer.push("/******/");
buffer.push(options.outputJsonpFunction);
buffer.push("(");
buffer.push(chunk.realId);
buffer.push(", {\n");
2012-08-23 07:43:29 +08:00
}
// write content of chunk
buffer.push(content);
// and close object
buffer.push("/******/})");
// convert buffer to string
buffer = buffer.join("");
2012-05-12 22:43:37 +08:00
// minimize if wished
try {
if(options.minimize) buffer = uglify(buffer, path.join(options.outputDirectory, filename));
} catch(e) {
return callback(e);
2012-05-01 23:46:26 +08:00
}
2012-05-12 22:43:37 +08:00
// push it as "file write"
options.emitFile(filename, buffer, true);
}
options.events.emit("task-end", "prepare chunks");
if(options.noWrite) return writingFinished();
options.events.emit("start-writing", hash);
// recursive create dir
function createDir(dir, callback) {
fileExists(dir, function(exists) {
if(exists)
callback();
else {
fs.mkdir(dir, function(err) {
if(err) {
var parentDir = path.join(dir, "..");
if(parentDir == dir)
return callback(err);
createDir(parentDir, function(err) {
if(err) return callback(err);
fs.mkdir(dir, function(err) {
if(err) return callback(err);
callback();
});
});
return;
}
callback();
});
}
2012-05-01 23:46:26 +08:00
});
}
2012-05-12 22:43:37 +08:00
// create output directory
var outDir = options.outputDirectory.replace(HASH_REGEXP, hash);
createDir(outDir, function(err) {
options.events.emit("task-end", "create ouput directory");
if(err) return callback(err);
writeFiles();
});
2012-05-12 22:43:37 +08:00
// collect file sizes
var fileSizeMap = {};
// do the writing of all generated files
function writeFiles() {
var remFiles = fileWrites.length;
fileWrites.forEach(function(writeAction) {
var writeActionFileName = writeAction[0].replace(HASH_REGEXP, hash)
options.events.emit("task", "write " + writeActionFileName);
fileSizeMap[path.basename(writeActionFileName)] = writeAction[1].length;
fs.writeFile(writeActionFileName, writeAction[1], "utf-8", function(err) {
options.events.emit("task-end", "write " + writeActionFileName);
if(err) throw err;
remFiles--;
if(remFiles === 0)
writingFinished();
2012-05-13 22:19:11 +08:00
});
});
if(fileWrites.length == 0) writingFinished();
}
// after writing: generate statistics
function writingFinished() {
// Stats
buffer = {};
buffer.hash = hash;
buffer.chunkCount = chunksCount;
buffer.modulesCount = Object.keys(depTree.modules).length;
var sum = 0;
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
// collect which module is in which file
var fileModulesMap = {};
// collect named chunks filenames
var chunkNameMap = {};
chunkIds.reverse().forEach(function(chunkId) {
var chunk = depTree.chunks[chunkId]
if(!chunk.filename) return;
var modulesArray = [];
for(var moduleId in chunk.modules) {
if(chunk.modules[moduleId] === "include") {
var modu = depTree.modules[moduleId];
modulesArray.push({
id: modu.realId,
size: modu.size,
filename: modu.filename,
dirname: modu.dirname,
fromCache: modu.fromCache,
toCache: modu.toCache,
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
seperate: modu.seperate,
profile: modu.profile,
2012-10-09 04:34:26 +08:00
loaders: modu.loaders,
dependencies: modu.dependencies,
reasons: modu.reasons});
2012-03-10 20:11:23 +08:00
sum++;
}
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
2012-03-10 20:11:23 +08:00
}
modulesArray.sort(function(a, b) {
return a.id - b.id;
});
fileModulesMap[path.basename(chunk.filename)] = modulesArray;
2012-09-25 23:20:36 +08:00
chunkNameMap[chunkId] = path.basename(chunk.filename).replace(HASH_REGEXP, hash);
});
buffer.modulesIncludingDuplicates = sum;
sum = 0;
for(var moduleId in depTree.chunks.main.modules) {
if(depTree.chunks.main.modules[moduleId] === "include")
sum++;
2012-03-27 06:00:32 +08:00
}
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
var dependencies = {};
var loaders = {};
var contexts = [];
Object.keys(depTree.modules).forEach(function(moduleId) {
var module = depTree.modules[moduleId];
if(module.dependencies) module.dependencies.forEach(function(dep) {
dependencies[dep] = true;
});
if(module.loaders) module.loaders.forEach(function(loader) {
loaders[loader] = true;
});
if(module.dirname) contexts.push(module.dirname);
});
buffer.dependencies = Object.keys(dependencies);
buffer.loaders = Object.keys(loaders);
buffer.contexts = contexts;
buffer.modulesFirstChunk = sum;
buffer.fileSizes = fileSizeMap;
buffer.warnings = depTree.warnings;
buffer.errors = depTree.errors;
buffer.fileModules = fileModulesMap;
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
buffer.chunkNameFiles = chunkNameMap;
buffer.subStats = subStats;
API: loaderContext.depencency is more relaxed and don't need to be called before reading API: loader.seperable cannot combined with loaderContext.emitFile and loaderContext.emitSubStats loaderContext.options.resolve loaderContext.options.events loaderContext.resolve and .sync API: added profile option (and --profile) API: added workers option (and --workers) API: added closeWorkers option API: if option workers is used: options must be JSON.stringify-able. Except options.resolve and options.events. Any error thrown in loader must be an object (i. e. an Error object). Only message, stack and value of toString is passed to main process. API: The expected Cache object for options.cache has changed. API: event module is emited after the module is finished. API: event context is now named context-enum API: added event context which is emited after the context is finished. API: event dependency is removed. Use stats.dependencies for this. API: event loader is removed. Use stats.loaders for this. API: added stats.contexts as a list of contexts. API: added stats...modules[..].dependencies for as list of files which affect the module's content. API: added stats...modules[..].loaders for as list of loaders which affect the module's content. API: removed stats.modulesPerChunk, it is useless and was deprecated. API: added stats.chunkNameFiles which export the files for named chunks API: added stats.startTime, timestamp as number cmd: more colorful output to indicate caching and timing API: webpack in watch mode emits the event watch-end if watch mode have to end (i. e. loader changed). You may restart it after clearing require.cache. API: added loaderContext.loaderType as one of loader, preLoader or postLoader. API: added loaderContext.currentLoaders as list of all loader of the current type. API: added loaderContext.loaderIndex as index of current loader in loaderContext.currentLoaders. API: added loaderContext.loaders, loaderContext.preLoaders and loaderContext.postLoaders.
2012-09-25 22:45:53 +08:00
buffer.startTime = startTime.getTime();
buffer.time = new Date() - startTime;
options.events.emit("task-end", "statistics");
options.events.emit("bundle", buffer);
callback(null, buffer);
2012-03-10 20:11:23 +08:00
}
});
2012-05-02 03:33:59 +08:00
return options.events;
2012-03-10 20:11:23 +08:00
}
2012-05-12 22:43:37 +08:00
// returns the template for specific options
2012-05-07 15:01:28 +08:00
function getTemplate(options, templateOptions) {
if(options.template) {
if(typeof options.template === "string")
return require(options.template)(options, templateOptions);
else
return options.template(options, templateOptions);
2012-05-12 22:43:37 +08:00
} else
2012-05-07 15:01:28 +08:00
return require("../templates/browser")(options, templateOptions);
}
2012-05-12 22:43:37 +08:00
// minimize it the uglify
2012-03-10 20:11:23 +08:00
function uglify(input, filename) {
var uglify = require("uglify-js");
try {
source = uglify.parser.parse(input);
source = uglify.uglify.ast_mangle(source);
source = uglify.uglify.ast_squeeze(source);
source = uglify.uglify.gen_code(source);
} catch(e) {
2012-03-27 06:00:32 +08:00
throw new Error(filename + " @ Line " + e.line + ", Col " + e.col + ", " + e.message);
2012-03-10 20:11:23 +08:00
return input;
}
return source;
}