webpack/lib/buildDeps.js

750 lines
22 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 parse = require("./parse");
2012-08-13 22:50:42 +08:00
var resolve = require("enhanced-resolve");
var execLoaders = require("enhanced-require/lib/execLoaders");
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 buildModule = require("./buildModule");
2012-03-10 20:11:23 +08:00
var fs = require("fs");
var path = require("path");
2012-05-02 20:06:42 +08:00
var assert = require("assert");
2012-03-10 20:11:23 +08:00
/**
2012-05-12 22:43:37 +08:00
* @param context: current directory
* @param mainModule: the entrance module
* @param options: options
* @param callback: function(err, result)
2012-03-10 20:11:23 +08:00
*/
module.exports = function buildDeps(context, mainModule, options, callback) {
if(!callback) {
callback = options;
options = {};
}
2012-05-12 22:43:37 +08:00
// options.events mock for tests
2012-03-10 20:11:23 +08:00
if(!options) options = {};
2012-05-02 03:33:59 +08:00
if(!options.events) options.events = { emit: function() {} };
2012-03-10 20:11:23 +08:00
2012-05-12 22:43:37 +08:00
// create data structure
2012-03-10 20:11:23 +08:00
var depTree = {
warnings: [],
2012-04-03 22:26:08 +08:00
errors: [],
2012-03-10 20:11:23 +08:00
modules: {},
modulesById: {},
chunks: {},
nextModuleId: 0,
2012-05-17 18:45:48 +08:00
nextChunkId: 1,
2012-03-10 20:11:23 +08:00
chunkModules: {} // used by checkObsolete
}
2012-05-12 22:43:37 +08:00
// some progress info
2012-05-02 20:06:42 +08:00
options.events.emit("task", "build modules");
options.events.emit("task", "build chunks");
options.events.emit("task", "optimize");
options.events.emit("task", "cleanup");
2012-05-12 22:43:37 +08:00
// add the entrance file as module
// all other stuff is added recursivly
2012-03-15 07:05:29 +08:00
addModule(depTree, context, mainModule, options, {type: "main"}, function(err, id) {
2012-03-10 20:11:23 +08:00
if(err) {
callback(err);
return;
}
2012-05-12 22:43:37 +08:00
buildTree(id);
2012-03-10 20:11:23 +08:00
});
2012-05-12 22:43:37 +08:00
// enhance the tree
function buildTree(mainModuleId) {
2012-05-02 20:06:42 +08:00
options.events.emit("task-end", "build modules");
2012-05-02 03:33:59 +08:00
2012-05-12 22:43:37 +08:00
// split the modules into chunks
2012-05-17 18:45:48 +08:00
depTree.modulesById[mainModuleId].name = "main";
2012-03-10 20:11:23 +08:00
addChunk(depTree, depTree.modulesById[mainModuleId], options);
2012-05-12 22:43:37 +08:00
// rename the module ids after a defined sheme
createRealIds(depTree, options);
2012-05-02 20:06:42 +08:00
options.events.emit("task-end", "build chunks");
2012-05-02 03:33:59 +08:00
2012-03-10 20:11:23 +08:00
for(var chunkId in depTree.chunks) {
2012-05-12 22:43:37 +08:00
// remove modules which are included in parent chunk
2012-03-10 20:11:23 +08:00
removeParentsModules(depTree, depTree.chunks[chunkId]);
2012-05-12 22:43:37 +08:00
// remove the chunk if it is empty
2012-03-10 20:11:23 +08:00
removeChunkIfEmpty(depTree, depTree.chunks[chunkId]);
2012-05-12 22:43:37 +08:00
// remove duplicate chunks
2012-03-10 20:11:23 +08:00
checkObsolete(depTree, depTree.chunks[chunkId]);
}
2012-05-13 22:19:11 +08:00
createRealChunkIds(depTree, options);
2012-05-02 20:06:42 +08:00
options.events.emit("task-end", "optimize");
2012-05-02 03:33:59 +08:00
2012-05-12 22:43:37 +08:00
// cleanup temporary stuff
2012-03-15 07:05:29 +08:00
delete depTree.chunkModules;
depTree.modulesByFile = depTree.modules;
depTree.modules = depTree.modulesById;
delete depTree.modulesById;
delete depTree.nextModuleId;
delete depTree.nextChunkId;
2012-05-12 22:43:37 +08:00
2012-03-15 07:05:29 +08:00
// return
2012-05-02 20:06:42 +08:00
options.events.emit("task-end", "cleanup");
2012-03-10 20:11:23 +08:00
callback(null, depTree);
}
}
2012-05-02 03:33:59 +08:00
function addModule(depTree, context, modu, options, reason, finalCallback) {
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 profile = options.profile && {
start: new Date()
};
2012-05-02 03:33:59 +08:00
options.events.emit("task");
function callback(err, result) {
options.events.emit("task-end");
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(profile && profile.module) {
profile.end = new Date();
2012-09-26 01:23:05 +08:00
if(profile.buildModule) {
profile.module.profile = {
time: profile.end - profile.start,
timeResolve: profile.resolveEnd - profile.start,
timeResolvePrePostLoaders: profile.resolvePrePostLoadersEnd - profile.resolveEnd,
timeLoadersCheck: profile.loadersCheckEnd - profile.resolvePrePostLoadersEnd,
timeBuildWaiting: (profile.buildModuleEnd - profile.loadersCheckEnd) - (profile.buildModule.end - profile.buildModule.start),
timeBuildModule: profile.buildModule.end - profile.buildModule.start,
timeBuildModuleRead: profile.buildModule.readEnd - profile.buildModule.start,
timeBuildModulePreLoaders: profile.buildModule.preLoadersEnd - profile.buildModule.readEnd,
timeBuildModuleLoaders: profile.buildModule.loadersEnd - profile.buildModule.preLoadersEnd,
timeBuildModulePostLoaders: profile.buildModule.postLoadersEnd - profile.buildModule.loadersEnd,
timeBuildModuleParse: profile.buildModule.end - profile.buildModule.postLoadersEnd,
timeChildren: profile.end - profile.buildModuleEnd
}
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-05-02 03:33:59 +08:00
finalCallback(err, result);
}
2012-05-12 22:43:37 +08:00
// resolve the filename of the required module
var resolveFunc = !options.workersNoResolve && options.workers && options.workers.ready() ?
seperateResolve :
resolve;
2012-09-26 18:28:23 +08:00
resolveFunc(context = context || path.dirname(modu), modu, options.resolve, resolved);
2012-03-12 04:37:18 +08:00
function resolved(err, filename) {
2012-03-10 20:11:23 +08:00
if(err) {
callback(err);
return;
}
2012-05-12 22:43:37 +08:00
// check if the module is already included
2012-03-10 20:11:23 +08:00
if(depTree.modules[filename]) {
2012-03-15 07:05:29 +08:00
depTree.modules[filename].reasons.push(reason);
2012-03-10 20:11:23 +08:00
callback(null, depTree.modules[filename].id);
} else {
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
profile && (profile.resolveEnd = new Date());
2012-05-12 22:43:37 +08:00
// create a new module
2012-04-03 22:26:08 +08:00
var modu = depTree.modules[filename] = {
2012-03-10 20:11:23 +08:00
id: depTree.nextModuleId++,
2012-03-15 07:05:29 +08:00
filename: filename,
reasons: [reason]
2012-03-10 20:11:23 +08:00
};
2012-04-03 22:26:08 +08:00
depTree.modulesById[modu.id] = modu;
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
profile && (profile.module = modu);
2012-05-12 22:43:37 +08:00
// split the loaders from the require
2012-03-27 06:00:32 +08:00
var filenameWithLoaders = filename;
var loaders = filename.split(/!/g);
filename = loaders.pop();
2012-05-12 22:43:37 +08:00
2012-05-21 06:09:30 +08:00
if(options.cache) {
2012-07-11 00:22:42 +08:00
options.cache.get(filenameWithLoaders, function(err, cachedData) {
2012-05-21 06:09:30 +08:00
if(err) return readFile();
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(profile) {
profile.buildModuleEnd = profile.loadersCheckEnd = profile.resolvePrePostLoadersEnd = new Date()
}
2012-06-30 03:52:03 +08:00
modu.fromCache = true;
2012-07-11 00:22:42 +08:00
cachedData = JSON.parse(cachedData);
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
modu.dependencies = cachedData.dependencies;
modu.loaders = cachedData.loaders;
2012-07-11 00:22:42 +08:00
processParsedJs(cachedData.source, cachedData.deps);
2012-05-21 06:09:30 +08:00
});
} else
readFile();
2012-05-12 22:43:37 +08:00
2012-05-21 06:09:30 +08:00
// Read the file and process it with loaders
2012-07-11 00:22:42 +08:00
// [this step is cached]
2012-05-21 06:09:30 +08:00
function readFile() {
// read file 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
var preLoaders = options.preLoaders ? matchLoadersList(options.preLoaders) : "";
var postLoaders = options.postLoaders ? matchLoadersList(options.postLoaders) : "";
2012-07-11 18:18:31 +08:00
2012-09-26 18:28:23 +08:00
var resolveLoadersFunc = !options.workersNoResolve && options.workers && options.workers.ready() ?
seperateResolveLoaders :
2012-09-26 18:28:23 +08:00
resolve.loaders;
if(preLoaders) resolveLoadersFunc(context, preLoaders, options.resolve, onPreLoadersResolved);
else onPreLoadersResolved(null, []);
function onPreLoadersResolved(err, preLoaders) {
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(err) return callback(err);
2012-09-26 19:02:27 +08:00
if(postLoaders) resolveLoadersFunc(context, postLoaders, options.resolve, onPostLoadersResolved);
else onPostLoadersResolved(null, []);
2012-09-26 18:28:23 +08:00
function onPostLoadersResolved(err, postLoaders) {
2012-07-11 18:18:31 +08:00
if(err) return callback(err);
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
profile && (profile.resolvePrePostLoadersEnd = new Date());
var allLoaders = [];
allLoaders.push.apply(allLoaders, preLoaders);
allLoaders.push.apply(allLoaders, loaders);
allLoaders.push.apply(allLoaders, postLoaders);
modu.loaders = allLoaders;
modu.dependencies = [filename];
var seperate = !!(options.workers &&
options.workers.ready() &&
allLoaders.length >= (options.workerMinLoaders || 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
try {
for(var i = 0; i < allLoaders.length && seperate; i++) {
var loaderFilename = allLoaders[i];
2012-09-26 18:28:23 +08:00
var loader = require(loaderFilename);
if(!loader.seperable && (!loader.seperableIfResolve || options.workersNoResolve))
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 = false;
}
} catch(e) {
return callback(e);
}
modu.seperate = seperate;
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 buildModuleStart = new Date();
profile && (profile.loadersCheckEnd = buildModuleStart);
2012-09-26 19:02:27 +08:00
(seperate ? seperateBuildModule : buildModule)(
context, filenameWithLoaders,
preLoaders, loaders, postLoaders,
filename,
options, function(err, source, deps, dependencyInfo, profileBuild) {
if(dependencyInfo) modu.dependencies = dependencyInfo.files; // It my be also supplied if err is set.
if(err) {
modu.error = err;
return callback(err);
}
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(profile) {
profile.buildModule = profileBuild;
profile.buildModuleEnd = new Date();
}
if(dependencyInfo.cacheable && options.cache) {
modu.toCache = true;
options.cache.store(filenameWithLoaders, dependencyInfo.files, buildModuleStart, JSON.stringify({
deps: deps,
source: source,
dependencies: dependencyInfo.files,
loaders: allLoaders
}));
}
return processParsedJs(source, deps);
2012-07-11 18:18:31 +08:00
});
2012-09-26 18:28:23 +08:00
}
}
2012-05-21 06:09:30 +08:00
}
2012-05-12 22:43:37 +08:00
2012-07-11 18:18:31 +08:00
function matchLoadersList(list) {
return list.filter(function(item) {
var regExp = item.test;
if(typeof regExp == "string") regExp = new RegExp(regExp);
return (regExp.test(filename));
2012-07-11 18:18:31 +08:00
}).map(function(item) {
return item.loader;
}).join("!");
}
2012-07-11 00:22:42 +08:00
// process the final parsed javascript code
function processParsedJs(source, deps) {
2012-05-21 06:09:30 +08:00
modu.requires = deps.requires || [];
modu.asyncs = deps.asyncs || [];
modu.contexts = deps.contexts || [];
modu.source = source;
var requires = {}, directRequire = {};
var contexts = [], directContexts = {};
function add(r) {
2012-08-07 03:43:57 +08:00
if(!r.name) return;
2012-05-21 06:09:30 +08:00
requires[r.name] = requires[r.name] || [];
requires[r.name].push(r);
}
function addContext(m) {
return function(c) {
contexts.push({context: c, module: m});
}
}
if(modu.requires) {
modu.requires.forEach(add);
modu.requires.forEach(function(r) {
2012-08-07 03:43:57 +08:00
if(!r.name) return;
2012-05-21 06:09:30 +08:00
directRequire[r.name] = true;
});
}
if(modu.contexts) {
modu.contexts.forEach(addContext(modu));
modu.contexts.forEach(function(c) {
directContexts[c.name] = true;
});
}
if(modu.asyncs)
modu.asyncs.forEach(function addAsync(c) {
if(c.requires)
c.requires.forEach(add);
if(c.asyncs)
c.asyncs.forEach(addAsync);
if(c.contexts)
c.contexts.forEach(addContext(c));
});
var requiresNames = Object.keys(requires);
2012-05-21 06:09:30 +08:00
var count = requiresNames.length + contexts.length + 1;
var errors = [];
if(requiresNames.length)
requiresNames.forEach(function(moduleName) {
var reason = {
type: directRequire[moduleName] ? "require" : "async require",
count: requires[moduleName].length,
filename: filename
};
2012-05-12 22:43:37 +08:00
2012-05-21 06:09:30 +08:00
// create or get the module for each require
addModule(depTree, path.dirname(filename), moduleName, options, reason, function(err, moduleId) {
if(err) {
depTree.errors.push("Cannot find module '" + moduleName + "'\n " + err +
"\n @ " + filename + " (line " + requires[moduleName][0].line + ", column " + requires[moduleName][0].column + ")");
} else {
requires[moduleName].forEach(function(requireItem) {
requireItem.id = moduleId;
});
2012-03-10 20:11:23 +08:00
}
2012-05-21 06:09:30 +08:00
endOne();
2012-03-12 04:37:18 +08:00
});
2012-05-21 06:09:30 +08:00
});
if(contexts) {
contexts.forEach(function(contextObj) {
var context = contextObj.context;
var module = contextObj.module;
var reason = {
type: directContexts[context.name] ? "context" : "async context",
filename: filename
};
// create of get the context module for each require.context
addContextModule(depTree, path.dirname(filename), context.name, options, reason, function(err, contextModuleId) {
if(err) {
depTree.errors.push("Cannot find context '"+context.name+"'\n " + err +
"\n @ " + filename + " (line " + context.line + ", column " + context.column + ")");
2012-03-12 04:37:18 +08:00
} else {
2012-05-21 06:09:30 +08:00
context.id = contextModuleId;
module.requires.push({id: context.id});
2012-03-12 04:37:18 +08:00
}
2012-05-21 06:09:30 +08:00
endOne();
});
if(context.warn) {
depTree.warnings.push(filename + " (line " + context.line + ", column " + context.column + "): " +
"implicit use of require.context(\".\") is not recommended.");
}
});
}
endOne();
function endOne() {
count--;
assert(count >= 0);
if(count === 0) {
if(errors.length) {
callback(errors.join("\n"));
} else {
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.emit("module", modu, filename);
2012-05-21 06:09:30 +08:00
callback(null, modu.id);
2012-03-12 04:37:18 +08:00
}
}
}
2012-05-21 06:09:30 +08:00
}
2012-03-12 04:37:18 +08:00
}
}
function seperateBuildModule(context, filenameWithLoaders,
preLoaders, loaders, postLoaders,
filename, options, callback) {
var opt = {};
Object.keys(options).forEach(function(name) {
if(name == "internal") return;
if(name == "events") return;
if(name == "workers") return;
opt[name] = options[name];
});
options.workers.run("buildModule", context, filenameWithLoaders,
preLoaders, loaders, postLoaders,
filename, opt, function(err, source, deps, cacheInfo, profileBuild) {
if(err) err = {
message: err.message,
stack: err.stack,
_toString: err._toString,
toString: function() {
return this._toString
}
}
callback(err, source, deps, cacheInfo, profileBuild);
});
}
function seperateResolve() {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift("resolve");
var callback = args.pop();
args.push(function(err, filename) {
if(err) err = {
message: err.message,
stack: err.stack,
_toString: err._toString,
toString: function() {
return this._toString
}
}
callback(err, filename);
});
options.workers.run.apply(options.workers, args);
}
function seperateResolveLoaders() {
var args = Array.prototype.slice.call(arguments, 0);
var workers = args[0];
args.unshift("resolve.loaders");
var callback = args.pop();
args.push(function(err, loaders) {
if(err) err = {
message: err.message,
stack: err.stack,
_toString: err._toString,
toString: function() {
return this._toString
}
}
callback(err, loaders);
});
workers.run.apply(workers, args);
}
2012-03-12 04:37:18 +08:00
}
2012-05-02 03:33:59 +08:00
function addContextModule(depTree, context, contextModuleName, options, reason, finalCallback) {
options.events.emit("task");
function callback(err, result) {
options.events.emit("task-end");
finalCallback(err, result);
}
2012-05-12 22:43:37 +08:00
// resolve the filename of the required context
2012-03-12 04:37:18 +08:00
resolve.context(context, contextModuleName, options.resolve, resolved);
function resolved(err, dirname) {
if(err) {
callback(err);
return;
}
2012-05-12 22:43:37 +08:00
// check if the context is already included
2012-03-12 04:37:18 +08:00
if(depTree.modules[dirname]) {
2012-03-15 07:05:29 +08:00
depTree.modules[dirname].reasons.push(reason);
2012-03-12 04:37:18 +08:00
callback(null, depTree.modules[dirname].id);
} else {
2012-05-12 22:43:37 +08:00
// create a new context
2012-03-12 04:37:18 +08:00
var contextModule = depTree.modules[dirname] = {
name: contextModuleName,
2012-03-15 07:05:29 +08:00
dirname: dirname,
2012-03-12 04:37:18 +08:00
id: depTree.nextModuleId++,
requireMap: {},
2012-03-15 07:05:29 +08:00
requires: [],
reasons: [reason]
2012-03-12 04:37:18 +08:00
};
depTree.modulesById[contextModule.id] = contextModule;
2012-05-12 22:43:37 +08:00
// split the loaders from the require
2012-04-03 22:26:08 +08:00
var contextModuleNameWithLoaders = dirname;
var loaders = dirname.split(/!/g);
dirname = loaders.pop();
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.emit("context-enum", contextModule, dirname);
2012-04-03 22:26:08 +08:00
var prependLoaders = loaders.length === 0 ? "" : loaders.join("!") + "!";
var extensions = (options.resolve && options.resolve.extensions) || [".web.js", ".js"];
2012-05-13 22:19:11 +08:00
2012-05-12 22:43:37 +08:00
// iterate all files in directory
2012-03-12 04:37:18 +08:00
function doDir(dirname, moduleName, done) {
fs.readdir(dirname, function(err, list) {
if(err) {
done(err);
} else {
var count = list.length + 1;
var errors = [];
function endOne(err) {
if(err) {
errors.push(err);
}
2012-03-10 20:11:23 +08:00
count--;
2012-05-02 20:06:42 +08:00
assert(count >= 0);
2012-03-12 04:37:18 +08:00
if(count == 0) {
if(errors.length > 0)
done(errors.join("\n"));
else
done();
}
}
list.forEach(function(file) {
var filename = path.join(dirname, file);
fs.stat(filename, function(err, stat) {
if(err) {
errors.push(err);
endOne();
2012-03-10 20:11:23 +08:00
} else {
2012-03-12 04:37:18 +08:00
if(stat.isDirectory()) {
2012-05-12 22:43:37 +08:00
// node_modules and web_modules directories are excluded
2012-03-15 07:05:29 +08:00
if(file === "node_modules" || file === "web_modules")
endOne();
else
doDir(filename, moduleName + "/" + file, endOne);
2012-03-12 04:37:18 +08:00
} else {
2012-04-03 22:26:08 +08:00
var match = false;
if(loaders.length === 0)
extensions.forEach(function(ext) {
if(file.substr(file.length - ext.length) === ext)
match = true;
if(options.resolve && options.resolve.loaders)
options.resolve.loaders.forEach(function(loader) {
2012-09-26 18:28:23 +08:00
var test = loader.test;
if(typeof test == "string") test = new RegExp(test);
if(test.test(filename))
2012-04-03 22:26:08 +08:00
match = true;
});
});
if(!match && loaders.length === 0) {
endOne();
return;
}
2012-03-15 07:05:29 +08:00
var modulereason = {
type: "context",
filename: reason.filename
};
2012-05-12 22:43:37 +08:00
// add each file as module
2012-04-03 22:26:08 +08:00
addModule(depTree, dirname, prependLoaders + filename, options, reason, function(err, moduleId) {
2012-03-12 04:37:18 +08:00
if(err) {
depTree.warnings.push("A file in context was excluded because of error: " + err);
endOne();
2012-03-12 04:37:18 +08:00
} else {
contextModule.requires.push({id: moduleId});
2012-05-13 22:19:11 +08:00
2012-05-12 22:43:37 +08:00
// store the module id in a require map
// when generating the source it is included
2012-03-12 04:37:18 +08:00
contextModule.requireMap[moduleName + "/" + file] = moduleId;
endOne();
}
});
}
2012-03-10 20:11:23 +08:00
}
2012-03-12 04:37:18 +08:00
});
2012-03-10 20:11:23 +08:00
});
2012-03-12 04:37:18 +08:00
endOne();
}
});
}
doDir(dirname, ".", function(err) {
if(err) {
callback(err);
return;
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
options.events.emit("context", contextModule, dirname);
2012-03-12 04:37:18 +08:00
callback(null, contextModule.id);
2012-03-10 20:11:23 +08:00
});
}
2012-03-12 04:37:18 +08:00
}
2012-03-10 20:11:23 +08:00
}
2012-05-12 22:43:37 +08:00
// rename the module ids after a defined sheme
function createRealIds(depTree, options) {
var sortedModules = [];
for(var id in depTree.modulesById) {
if(""+id === "0") continue;
var modu = depTree.modulesById[id];
var usages = 1;
modu.reasons.forEach(function(reason) {
usages += reason.count ? reason.count : 1;
});
modu.usages = usages;
sortedModules.push(modu);
}
depTree.modulesById[0].realId = 0;
sortedModules.sort(function(a, b) {
if(a.chunks && b.chunks &&
2012-05-18 07:15:53 +08:00
(a.chunks.indexOf("main") !== -1 || b.chunks.indexOf("main") !== -1)) {
if(a.chunks.indexOf("main") === -1)
return 1;
2012-05-18 07:15:53 +08:00
if(b.chunks.indexOf("main") === -1)
return -1;
}
var diff = b.usages - a.usages;
if(diff !== 0) return diff;
if(typeof a.filename === "string" || typeof b.filename === "string") {
if(typeof a.filename !== "string")
return -1;
if(typeof b.filename !== "string")
return 1;
if(a.filename === b.filename)
return 0;
return (a.filename < b.filename) ? -1 : 1;
}
if(a.dirname === b.dirname)
return 0;
return (a.dirname < b.dirname) ? -1 : 1;
});
sortedModules.forEach(function(modu, idx) {
modu.realId = idx + 1;
});
}
2012-05-12 22:43:37 +08:00
// add a chunk
2012-03-10 20:11:23 +08:00
function addChunk(depTree, chunkStartpoint, options) {
2012-05-17 18:45:48 +08:00
var chunk;
if(chunkStartpoint && chunkStartpoint.name) {
chunk = depTree.chunks[chunkStartpoint.name];
if(chunk) {
chunk.usages++;
chunk.contexts.push(chunkStartpoint);
}
}
if(!chunk) {
chunk = {
id: (chunkStartpoint && chunkStartpoint.name) || depTree.nextChunkId++,
modules: {},
contexts: chunkStartpoint ? [chunkStartpoint] : [],
usages: 1
};
depTree.chunks[chunk.id] = chunk;
}
2012-03-10 20:11:23 +08:00
if(chunkStartpoint) {
chunkStartpoint.chunkId = chunk.id;
addModuleToChunk(depTree, chunkStartpoint, chunk.id, options);
}
return chunk;
}
function addModuleToChunk(depTree, context, chunkId, options) {
context.chunks = context.chunks || [];
if(context.chunks.indexOf(chunkId) === -1) {
context.chunks.push(chunkId);
if(context.id !== undefined)
depTree.chunks[chunkId].modules[context.id] = "include";
if(context.requires) {
context.requires.forEach(function(requireItem) {
if(requireItem.id)
addModuleToChunk(depTree, depTree.modulesById[requireItem.id], chunkId, options);
2012-03-10 20:11:23 +08:00
});
}
if(context.asyncs) {
context.asyncs.forEach(function(context) {
2012-06-30 02:54:24 +08:00
if(options.single) {
addModuleToChunk(depTree, context, chunkId, options);
2012-03-10 20:11:23 +08:00
} else {
2012-06-30 02:54:24 +08:00
var subChunk;
if(context.chunkId) {
subChunk = depTree.chunks[context.chunkId];
subChunk.usages++;
} else {
subChunk = addChunk(depTree, context, options);
}
subChunk.parents = subChunk.parents || [];
subChunk.parents.push(chunkId);
2012-03-10 20:11:23 +08:00
}
});
}
}
}
function removeParentsModules(depTree, chunk) {
if(!chunk.parents) return;
for(var moduleId in chunk.modules) {
2012-03-12 04:37:18 +08:00
var inParent = true;
2012-05-01 21:42:01 +08:00
var checkedParents = {};
chunk.parents.forEach(function checkParent(parentId) {
2012-05-01 22:09:33 +08:00
if(!inParent) return;
2012-05-01 21:42:01 +08:00
if(checkedParents[parentId]) return;
checkedParents[parentId] = true;
2012-05-01 22:09:33 +08:00
if(!depTree.chunks[parentId].modules[moduleId]) {
var parents = depTree.chunks[parentId].parents;
if(parents && parents.length > 0)
parents.forEach(checkParent);
else
inParent = false;
}
2012-03-10 20:11:23 +08:00
});
if(inParent) {
chunk.modules[moduleId] = "in-parent";
}
}
}
function removeChunkIfEmpty(depTree, chunk) {
var hasModules = false;
for(var moduleId in chunk.modules) {
if(chunk.modules[moduleId] === "include") {
hasModules = true;
break;
}
}
if(!hasModules) {
2012-05-17 18:45:48 +08:00
chunk.contexts.forEach(function(c) { c.chunkId = null; });
2012-03-10 20:11:23 +08:00
chunk.empty = true;
}
}
function checkObsolete(depTree, chunk) {
var modules = [];
for(var moduleId in chunk.modules) {
if(chunk.modules[moduleId] === "include") {
modules.push(moduleId);
}
}
if(modules.length === 0) return;
modules.sort();
var moduleString = modules.join(" ");
if(depTree.chunkModules[moduleString]) {
chunk.equals = depTree.chunkModules[moduleString];
2012-05-17 18:45:48 +08:00
chunk.contexts.forEach(function(c) {
c.chunkId = chunk.equals;
});
2012-03-10 20:11:23 +08:00
} else
depTree.chunkModules[moduleString] = chunk.id;
2012-05-13 22:19:11 +08:00
}
// rename the chunk ids after a defined sheme
function createRealChunkIds(depTree, options) {
var sortedChunks = [];
for(var id in depTree.chunks) {
2012-05-17 18:45:48 +08:00
if(id === "main") continue;
2012-05-13 22:19:11 +08:00
var chunk = depTree.chunks[id];
if(chunk.empty) continue;
if(chunk.equals !== undefined) continue;
sortedChunks.push(chunk);
}
2012-05-17 18:45:48 +08:00
depTree.chunks["main"].realId = 0;
2012-05-13 22:19:11 +08:00
sortedChunks.sort(function(a, b) {
if(a.usages < b.usages)
return -1;
if(a.usages > b.usages)
return 1;
var aCount = Object.keys(a.modules).length;
var bCount = Object.keys(b.modules).length;
2012-05-13 22:26:58 +08:00
if(aCount != bCount)
return aCount - bCount;
function genModulesString(modules) {
2012-05-13 22:37:35 +08:00
var moduleIds = [];
for(var id in modules) {
if(modules[id] === "include") {
var m = depTree.modulesById[id];
moduleIds.push(m.realId);
}
}
return moduleIds.sort().join("-");
2012-05-13 22:26:58 +08:00
}
var aModules = genModulesString(a.modules);
var bModules = genModulesString(b.modules);
if(aModules == bModules)
return 0;
return aModules < bModules ? -1 : 1;
2012-05-13 22:19:11 +08:00
});
sortedChunks.forEach(function(chunk, idx) {
chunk.realId = idx + 1;
});
2012-03-10 20:11:23 +08:00
}