webpack/lib/ContextModule.js

236 lines
6.5 KiB
JavaScript
Raw Normal View History

2013-01-31 01:49:25 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2017-02-18 17:12:09 +08:00
"use strict";
const path = require("path");
const Module = require("./Module");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
2013-01-31 01:49:25 +08:00
2017-02-18 17:12:09 +08:00
class ContextModule extends Module {
constructor(resolveDependencies, context, recursive, regExp, addon, async) {
super();
this.resolveDependencies = resolveDependencies;
this.context = context;
this.recursive = recursive;
this.regExp = regExp;
this.addon = addon;
this.async = !!async;
this.cacheable = true;
this.contextDependencies = [context];
this.built = false;
}
2013-01-31 01:49:25 +08:00
prettyRegExp(regexString) {
// remove the "/" at the front and the beginning
// "/foo/" -> "foo"
return regexString.substring(1, regexString.length - 1);
2017-02-18 17:12:09 +08:00
}
2013-01-31 01:49:25 +08:00
contextify(context, request) {
return request.split("!").map(function(subrequest) {
let rp = path.relative(context, subrequest);
2017-02-18 17:12:09 +08:00
if(path.sep === "\\")
rp = rp.replace(/\\/g, "/");
if(rp.indexOf("../") !== 0)
rp = "./" + rp;
return rp;
}).join("!");
}
2013-01-31 01:49:25 +08:00
2017-02-18 17:29:21 +08:00
identifier() {
let identifier = this.context;
if(this.async)
identifier += " async";
if(!this.recursive)
identifier += " nonrecursive";
if(this.addon)
identifier += ` ${this.addon}`;
if(this.regExp)
identifier += ` ${this.regExp}`;
return identifier;
}
readableIdentifier(requestShortener) {
let identifier = requestShortener.shorten(this.context);
if(this.async)
identifier += " async";
if(!this.recursive)
identifier += " nonrecursive";
if(this.addon)
identifier += ` ${requestShortener.shorten(this.addon)}`;
if(this.regExp)
identifier += ` ${this.prettyRegExp(this.regExp + "")}`;
return identifier;
}
2017-02-18 17:12:09 +08:00
libIdent(options) {
2017-02-18 17:29:21 +08:00
let identifier = this.contextify(options.context, this.context);
2017-02-18 17:12:09 +08:00
if(this.async)
2017-02-18 17:29:21 +08:00
identifier += " async";
2017-02-18 17:12:09 +08:00
if(this.recursive)
2017-02-18 17:29:21 +08:00
identifier += " recursive";
2017-02-18 17:12:09 +08:00
if(this.addon)
2017-02-18 17:29:21 +08:00
identifier += ` ${this.contextify(options.context, this.addon)}`;
2017-02-18 17:12:09 +08:00
if(this.regExp)
2017-02-18 17:29:21 +08:00
identifier += ` ${this.prettyRegExp(this.regExp + "")}`;
return identifier;
2017-02-18 17:12:09 +08:00
}
2016-12-14 19:03:24 +08:00
2017-02-18 17:12:09 +08:00
needRebuild(fileTimestamps, contextTimestamps) {
const ts = contextTimestamps[this.context];
if(!ts) {
return true;
}
2017-02-18 17:12:09 +08:00
return ts >= this.builtTime;
}
2016-12-14 19:03:24 +08:00
2017-02-18 17:12:09 +08:00
unbuild() {
this.built = false;
super.unbuild();
}
2013-01-31 01:49:25 +08:00
2017-02-18 17:12:09 +08:00
build(options, compilation, resolver, fs, callback) {
this.built = true;
this.builtTime = new Date().getTime();
this.resolveDependencies(fs, this.context, this.recursive, this.regExp, (err, dependencies) => {
if(err) return callback(err);
2013-02-01 01:00:22 +08:00
if(!dependencies) {
callback();
return;
}
// enhance dependencies
dependencies.forEach(dep => {
dep.loc = dep.userRequest;
dep.request = this.addon + dep.request;
});
// if these we are not a async context
// add dependencies and continue
if(!this.async) {
2017-02-18 17:12:09 +08:00
this.dependencies = dependencies;
callback();
return;
}
// if we are async however create a new async dependency block
// and add that block to this context
dependencies.forEach(dep => {
const block = new AsyncDependenciesBlock(null, dep.module, dep.loc);
block.addDependency(dep);
this.addBlock(block);
});
2017-02-18 17:12:09 +08:00
callback();
});
2014-07-26 20:48:42 +08:00
}
2017-02-18 17:12:09 +08:00
source() {
let str;
const map = {};
if(this.dependencies && this.dependencies.length > 0) {
this.dependencies.slice().sort(function(a, b) {
if(a.userRequest === b.userRequest) return 0;
return a.userRequest < b.userRequest ? -1 : 1;
}).forEach(function(dep) {
if(dep.module)
map[dep.userRequest] = dep.module.id;
});
str = [
"var map = ", JSON.stringify(map, null, "\t"), ";\n",
"function webpackContext(req) {\n",
"\treturn __webpack_require__(webpackContextResolve(req));\n",
"};\n",
"function webpackContextResolve(req) {\n",
"\tvar id = map[req];\n",
"\tif(!(id + 1)) // check for number\n",
"\t\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n",
"\treturn id;\n",
"};\n",
"webpackContext.keys = function webpackContextKeys() {\n",
"\treturn Object.keys(map);\n",
"};\n",
"webpackContext.resolve = webpackContextResolve;\n",
"module.exports = webpackContext;\n",
"webpackContext.id = " + JSON.stringify(this.id) + ";\n"
];
} else if(this.blocks && this.blocks.length > 0) {
const items = this.blocks.map(function(block) {
return {
dependency: block.dependencies[0],
block: block,
userRequest: block.dependencies[0].userRequest
};
}).filter(function(item) {
return item.dependency.module;
});
let hasMultipleChunks = false;
items.sort(function(a, b) {
if(a.userRequest === b.userRequest) return 0;
return a.userRequest < b.userRequest ? -1 : 1;
}).forEach(function(item) {
if(item.dependency.module) {
const chunks = item.block.chunks || [];
if(chunks.length !== 1)
hasMultipleChunks = true;
map[item.userRequest] = [item.dependency.module.id].concat(chunks.map(function(chunk) {
return chunk.id;
}));
}
});
str = [
"var map = ", JSON.stringify(map, null, "\t"), ";\n",
"function webpackAsyncContext(req) {\n",
"\tvar ids = map[req];",
"\tif(!ids)\n",
"\t\treturn Promise.reject(new Error(\"Cannot find module '\" + req + \"'.\"));\n",
"\treturn ",
hasMultipleChunks ?
"Promise.all(ids.slice(1).map(__webpack_require__.e))" :
"__webpack_require__.e(ids[1])",
".then(function() {\n",
"\t\treturn __webpack_require__(ids[0]);\n",
"\t});\n",
"};\n",
"webpackAsyncContext.keys = function webpackAsyncContextKeys() {\n",
"\treturn Object.keys(map);\n",
"};\n",
"module.exports = webpackAsyncContext;\n",
"webpackAsyncContext.id = " + JSON.stringify(this.id) + ";\n"
];
} else {
str = [
"function webpackEmptyContext(req) {\n",
"\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n",
"}\n",
"webpackEmptyContext.keys = function() { return []; };\n",
"webpackEmptyContext.resolve = webpackEmptyContext;\n",
"module.exports = webpackEmptyContext;\n",
"webpackEmptyContext.id = " + JSON.stringify(this.id) + ";\n"
];
}
if(this.useSourceMap) {
return new OriginalSource(str.join(""), this.identifier());
} else {
return new RawSource(str.join(""));
}
2013-10-14 19:59:44 +08:00
}
2013-01-31 01:49:25 +08:00
2017-02-18 17:12:09 +08:00
size() {
return this.dependencies.map(function(dep) {
return dep.userRequest.length + 5;
}).reduce(function(a, b) {
return a + b;
}, 160);
}
}
module.exports = ContextModule;