allow require as identifier to convert to require.context(".")
This commit is contained in:
parent
b675c7f13b
commit
0bc303cbf3
21
README.md
21
README.md
|
@ -119,6 +119,9 @@ function getTemplate(templateName) {
|
|||
|
||||
See [details](modules-webpack/tree/master/examples/require.context) for complete example.
|
||||
|
||||
When try to store the `require` function in another variable or try to pass it as parameter,
|
||||
`webpack` convert it to a `require.context(".")` to be combatible.
|
||||
There is a warning emitted in this case.
|
||||
|
||||
*Warning: The complete code in the directory are included. So use it carefully.*
|
||||
|
||||
|
@ -128,12 +131,19 @@ See [details](modules-webpack/tree/master/examples/require.context) for complete
|
|||
|
||||
As dependencies are resolved before running:
|
||||
|
||||
* `require` should not be overwritten
|
||||
* `require` should not be called indirect as `var r = require; r("./a");`. Use `require.context`?
|
||||
* `require` should not be overwritten by variable declaration (`var require = ...`), by function parameter is allowed `function(require) {...}`.
|
||||
* `require.ensure` should not be overwritten or called indirect
|
||||
* the function passed to `require.ensure` should be inlined in the call.
|
||||
* `require.context` should not be overwritten or called indirect
|
||||
* the argument to `require.context` should be a literal or addition of multiple literals
|
||||
* An indirect call of `require` should access a file in current directory: This throws an exception: `var r = require; r("../file");`
|
||||
|
||||
The following cases could result in too much code in result file if used wrong:
|
||||
|
||||
* indirect call of `require`: `var r = require; r("./file");`
|
||||
* `require.context`. It includes the whole directory.
|
||||
* expressions in require arguments: `require(variable)`, `require(condition ? "a" : "b")` (TODO)
|
||||
* the function passed to `require.ensure` is not inlined in the call.
|
||||
|
||||
|
||||
### node.js specific modules
|
||||
|
||||
|
@ -147,6 +157,8 @@ web_modules
|
|||
...
|
||||
```
|
||||
|
||||
TODO provide some replacements
|
||||
|
||||
## Usage
|
||||
|
||||
### Shell
|
||||
|
@ -167,6 +179,7 @@ Options:
|
|||
--options Options JSON File [string]
|
||||
--script-src-prefix Path Prefix For JavaScript Loading [string]
|
||||
--libary Stores the exports into this variable [string]
|
||||
--colors Output Stats with colors [boolean] [default: false]
|
||||
```
|
||||
|
||||
### Programmatically Usage
|
||||
|
@ -220,7 +233,7 @@ However `webpack` has big differences:
|
|||
`webpack` replaces module names and paths with numbers. `webmake` don't do that and do resolves requires on client-side.
|
||||
This design of `webmake` was intended to support variables as arguments to require calls.
|
||||
`webpack` resolves requires in compile time and have no resolve code on client side. This results in smaller bundles.
|
||||
Variables as argments will be handled different and with more limitations in `webpack`.
|
||||
Variables as arguments will be handled different and with more limitations in `webpack`.
|
||||
|
||||
Another limitation in `webmake` which are based on the previous one is that modules must be in the current package scope.
|
||||
In `webpack` this is not a restriction.
|
||||
|
|
|
@ -30,6 +30,10 @@ var argv = require("optimist")
|
|||
.string("libary")
|
||||
.describe("libary", "Stores the exports into this variable")
|
||||
|
||||
.boolean("colors")
|
||||
.describe("colors", "Output Stats with colors")
|
||||
.default("colors", false)
|
||||
|
||||
.demand(1)
|
||||
.argv;
|
||||
|
||||
|
@ -92,6 +96,6 @@ if(argv.single) {
|
|||
console.error(err);
|
||||
return;
|
||||
}
|
||||
console.log(stats);
|
||||
console.log(require("util").inspect(stats, false, 10, argv.colors));
|
||||
});
|
||||
}
|
|
@ -21,6 +21,7 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
|
|||
if(!options) options = {};
|
||||
|
||||
var depTree = {
|
||||
warnings: [],
|
||||
modules: {},
|
||||
modulesById: {},
|
||||
chunks: {},
|
||||
|
@ -71,7 +72,13 @@ function addModule(depTree, context, module, options, callback) {
|
|||
callback(err);
|
||||
return;
|
||||
}
|
||||
var deps = parse(source);
|
||||
var deps;
|
||||
try {
|
||||
deps = parse(source);
|
||||
} catch(e) {
|
||||
callback("File \"" + filename + "\" parsing failed: " + e);
|
||||
return;
|
||||
}
|
||||
module.requires = deps.requires || [];
|
||||
module.asyncs = deps.asyncs || [];
|
||||
module.contexts = deps.contexts || [];
|
||||
|
@ -129,7 +136,11 @@ function addModule(depTree, context, module, options, callback) {
|
|||
module.requires.push({id: context.id});
|
||||
}
|
||||
endOne();
|
||||
})
|
||||
});
|
||||
if(context.warn) {
|
||||
depTree.warnings.push(filename + " (line " + context.line + ", column " + context.column + "): " +
|
||||
"implicit use of require.context(\".\") is not recommended.");
|
||||
}
|
||||
});
|
||||
}
|
||||
endOne();
|
||||
|
@ -165,6 +176,7 @@ function addContextModule(depTree, context, contextModuleName, options, callback
|
|||
requires: []
|
||||
};
|
||||
depTree.modulesById[contextModule.id] = contextModule;
|
||||
var extensions = (options.resolve && options.resolve.extensions) || [".web.js", ".js"];
|
||||
function doDir(dirname, moduleName, done) {
|
||||
fs.readdir(dirname, function(err, list) {
|
||||
if(err) {
|
||||
|
@ -194,6 +206,15 @@ function addContextModule(depTree, context, contextModuleName, options, callback
|
|||
if(stat.isDirectory()) {
|
||||
doDir(filename, moduleName + "/" + file, endOne);
|
||||
} else {
|
||||
var hasExt = false;
|
||||
extensions.forEach(function(ext) {
|
||||
if(file.substr(file.length - ext.length) === ext)
|
||||
hasExt = true;
|
||||
});
|
||||
if(!hasExt) {
|
||||
endOne();
|
||||
return;
|
||||
}
|
||||
addModule(depTree, null, filename, options, function(err, moduleId) {
|
||||
if(err) {
|
||||
endOne(err);
|
||||
|
@ -217,7 +238,6 @@ function addContextModule(depTree, context, contextModuleName, options, callback
|
|||
return;
|
||||
}
|
||||
var extensionsAccess = [];
|
||||
var extensions = (options.resolve && options.resolve.extensions) || [".web.js", ".js"];
|
||||
extensions.forEach(function(ext) {
|
||||
extensionsAccess.push("||map[name+\"");
|
||||
extensionsAccess.push(ext.replace(/"/g, "\\\""));
|
||||
|
|
73
lib/parse.js
73
lib/parse.js
|
@ -78,10 +78,17 @@ function walkStatement(context, statement) {
|
|||
|
||||
// Declarations
|
||||
case "FunctionDeclaration":
|
||||
var req = functionParamsContainsRequire(statement.params);
|
||||
if(req) {
|
||||
var old = context.requireOverwrite;
|
||||
context.requireOverwrite = true;
|
||||
}
|
||||
if(statement.body.type === "BlockStatement")
|
||||
walkStatement(context, statement.body);
|
||||
else
|
||||
walkExpression(context, statement.body);
|
||||
if(req)
|
||||
context.requireOverwrite = old;
|
||||
break;
|
||||
case "VariableDeclaration":
|
||||
if(statement.declarations)
|
||||
|
@ -135,10 +142,21 @@ function walkExpression(context, expression) {
|
|||
});
|
||||
break;
|
||||
case "FunctionExpression":
|
||||
var req = functionParamsContainsRequire(expression.params);
|
||||
if(context.paramMustRequire) {
|
||||
req = false;
|
||||
context.paramMustRequire = false;
|
||||
}
|
||||
if(req) {
|
||||
var old = context.requireOverwrite;
|
||||
context.requireOverwrite = true;
|
||||
}
|
||||
if(expression.body.type === "BlockStatement")
|
||||
walkStatement(context, expression.body);
|
||||
else
|
||||
walkExpression(context, expression.body);
|
||||
if(req)
|
||||
context.requireOverwrite = old;
|
||||
break;
|
||||
case "SequenceExpression":
|
||||
if(expression.expressions)
|
||||
|
@ -165,7 +183,9 @@ function walkExpression(context, expression) {
|
|||
walkExpressions(context, expression.arguments);
|
||||
break;
|
||||
case "CallExpression":
|
||||
if(expression.callee && expression.arguments &&
|
||||
var noCallee = false;
|
||||
if(!context.requireOverwrite &&
|
||||
expression.callee && expression.arguments &&
|
||||
expression.arguments.length == 1 &&
|
||||
expression.callee.type === "Identifier" &&
|
||||
expression.callee.name === "require") {
|
||||
|
@ -173,13 +193,20 @@ function walkExpression(context, expression) {
|
|||
if(param.code) {
|
||||
// make context
|
||||
var pos = param.value.indexOf("/");
|
||||
context.contexts = context.contexts || [];
|
||||
if(pos === -1) {
|
||||
throw new Error("require a module by variable is not supported");
|
||||
var newContext = {
|
||||
name: ".",
|
||||
require: true,
|
||||
calleeRange: expression.callee.range,
|
||||
line: expression.loc.start.line,
|
||||
column: expression.loc.start.column
|
||||
};
|
||||
context.contexts.push(newContext);
|
||||
} else {
|
||||
var match = /\/[^\/]*$/.exec(param.value);
|
||||
var dirname = param.value.substring(0, match.index);
|
||||
var remainder = "." + param.value.substring(match.index);
|
||||
context.contexts = context.contexts || [];
|
||||
var newContext = {
|
||||
name: dirname,
|
||||
require: true,
|
||||
|
@ -200,8 +227,10 @@ function walkExpression(context, expression) {
|
|||
column: expression.loc.start.column
|
||||
});
|
||||
}
|
||||
noCallee = true;
|
||||
}
|
||||
if(expression.callee && expression.arguments &&
|
||||
if(!context.requireOverwrite &&
|
||||
expression.callee && expression.arguments &&
|
||||
expression.arguments.length >= 1 &&
|
||||
expression.callee.type === "MemberExpression" &&
|
||||
expression.callee.object.type === "Identifier" &&
|
||||
|
@ -214,15 +243,18 @@ function walkExpression(context, expression) {
|
|||
requires: [],
|
||||
namesRange: expression.arguments[0].range,
|
||||
line: expression.loc.start.line,
|
||||
column: expression.loc.start.column
|
||||
column: expression.loc.start.column,
|
||||
paramMustRequire: true
|
||||
};
|
||||
param.forEach(function(r) {
|
||||
newContext.requires.push({name: r});
|
||||
});
|
||||
context.asyncs.push(newContext);
|
||||
context = newContext;
|
||||
noCallee = true;
|
||||
}
|
||||
if(expression.callee && expression.arguments &&
|
||||
if(!context.requireOverwrite &&
|
||||
expression.callee && expression.arguments &&
|
||||
expression.arguments.length == 1 &&
|
||||
expression.callee.type === "MemberExpression" &&
|
||||
expression.callee.object.type === "Identifier" &&
|
||||
|
@ -238,9 +270,10 @@ function walkExpression(context, expression) {
|
|||
column: expression.loc.start.column,
|
||||
};
|
||||
context.contexts.push(newContext);
|
||||
noCallee = true;
|
||||
}
|
||||
|
||||
if(expression.callee)
|
||||
if(expression.callee && !noCallee)
|
||||
walkExpression(context, expression.callee);
|
||||
if(expression.arguments)
|
||||
walkExpressions(context, expression.arguments);
|
||||
|
@ -250,9 +283,35 @@ function walkExpression(context, expression) {
|
|||
if(expression.property.type !== "Identifier")
|
||||
walkExpression(context, expression.property);
|
||||
break;
|
||||
case "Identifier":
|
||||
if(!context.requireOverwrite &&
|
||||
expression.name === "require") {
|
||||
context.contexts = context.contexts || [];
|
||||
var newContext = {
|
||||
name: ".",
|
||||
warn: "Identifier",
|
||||
require: true,
|
||||
calleeRange: [expression.range[0], expression.range[1]],
|
||||
line: expression.loc.start.line,
|
||||
column: expression.loc.start.column,
|
||||
};
|
||||
context.contexts.push(newContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function functionParamsContainsRequire(params) {
|
||||
if(!params) return false;
|
||||
var found = false;
|
||||
params.forEach(function(param) {
|
||||
if(param.type === "Identifier" &&
|
||||
param.name === "require")
|
||||
found = true;
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
function parseString(expression) {
|
||||
switch(expression.type) {
|
||||
case "BinaryExpression":
|
||||
|
|
|
@ -72,6 +72,7 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
options.outputPostfix = "." + options.output;
|
||||
}
|
||||
var fileSizeMap = {};
|
||||
var fileModulesMap = {};
|
||||
var chunksCount = 0;
|
||||
for(var chunkId in depTree.chunks) {
|
||||
var chunk = depTree.chunks[chunkId];
|
||||
|
@ -115,6 +116,12 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
if(err) throw err;
|
||||
});
|
||||
fileSizeMap[path.basename(filename)] = buffer.length;
|
||||
var modulesArray = [];
|
||||
for(var moduleId in chunk.modules) {
|
||||
if(chunk.modules[moduleId] === "include")
|
||||
modulesArray.push({id: moduleId, filename: depTree.modulesById[moduleId].filename});
|
||||
}
|
||||
fileModulesMap[path.basename(filename)] = modulesArray;
|
||||
}
|
||||
buffer = {};
|
||||
buffer.chunkCount = chunksCount;
|
||||
|
@ -135,6 +142,8 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
}
|
||||
buffer.modulesFirstChunk = sum;
|
||||
buffer.fileSizes = fileSizeMap;
|
||||
buffer.warnings = depTree.warnings;
|
||||
buffer.fileModules = fileModulesMap;
|
||||
callback(null, buffer);
|
||||
} else {
|
||||
if(options.libary) {
|
||||
|
|
|
@ -31,11 +31,12 @@ module.exports = function(module) {
|
|||
to: contextItem.calleeRange[1],
|
||||
value: "require(" + prefix + ((contextItem.id || "throw new Error('there is not id for this')") + "") + ")"
|
||||
});
|
||||
replaces.push({
|
||||
from: contextItem.replace[0][0],
|
||||
to: contextItem.replace[0][1],
|
||||
value: stringify(contextItem.replace[1])
|
||||
});
|
||||
if(contextItem.replace)
|
||||
replaces.push({
|
||||
from: contextItem.replace[0][0],
|
||||
to: contextItem.replace[0][1],
|
||||
value: stringify(contextItem.replace[1])
|
||||
});
|
||||
} else {
|
||||
replaces.push({
|
||||
from: contextItem.expressionRange[0],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "webpack",
|
||||
"version": "0.1.6",
|
||||
"version": "0.2.0",
|
||||
"author": "Tobias Koppers @sokra",
|
||||
"description": "Packs CommonJs Modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand.",
|
||||
"dependencies": {
|
||||
|
|
|
@ -9,21 +9,21 @@ argv.shift();
|
|||
argv.shift();
|
||||
var extraArgs = argv.join(" ");
|
||||
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --single --libary libary1 node_modules/libary1 js/libary1.js", function (error, stdout, stderr) {
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --single --libary libary1 node_modules/libary1 js/libary1.js", function (error, stdout, stderr) {
|
||||
console.log('libary1 stdout:\n' + stdout);
|
||||
console.log('libary1 stderr:\n ' + stderr);
|
||||
if (error !== null) {
|
||||
console.log('libary1 error: ' + error);
|
||||
}
|
||||
});
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --script-src-prefix js/ --libary libary2 node_modules/libary2 js/libary2.js", function (error, stdout, stderr) {
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --script-src-prefix js/ --libary libary2 node_modules/libary2 js/libary2.js", function (error, stdout, stderr) {
|
||||
console.log('libary2 stdout:\n' + stdout);
|
||||
console.log('libary2 stderr:\n ' + stderr);
|
||||
if (error !== null) {
|
||||
console.log('libary2 error: ' + error);
|
||||
}
|
||||
});
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --script-src-prefix js/ lib/index js/web.js", function (error, stdout, stderr) {
|
||||
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --script-src-prefix js/ lib/index js/web.js", function (error, stdout, stderr) {
|
||||
console.log('web stdout:\n' + stdout);
|
||||
console.log('web stderr:\n ' + stderr);
|
||||
if (error !== null) {
|
||||
|
|
|
@ -18,8 +18,16 @@ window.test(require("./singluar").value === 2, "exported object is singluar");
|
|||
window.test(require("subfilemodule") === "subfilemodule", "Modules as single file should load");
|
||||
window.test(require.context("../templates")("./tmpl") === "test template", "Context should work");
|
||||
window.test(require . context ( "." + "." + "/" + "templ" + "ates" ) ( "./subdir/tmpl.js" ) === "subdir test template", "Context should work with subdirectories and splitted");
|
||||
var template = "tmpl";
|
||||
var template = "tmpl", templateFull = "./tmpl.js";
|
||||
window.test(require("../templates/" + template) === "test template", "Automatical context should work");
|
||||
window.test(require("../templates/templateLoader")(templateFull) === "test template", "Automatical context without prefix should work");
|
||||
window.test(require("../templates/templateLoaderIndirect")(templateFull) === "test template", "Automatical context should work with require identifier");
|
||||
window.test(function(require) { return require; }(1234) === 1234, "require overwrite in anonymos function");
|
||||
function testFunc(abc, require) {
|
||||
return require;
|
||||
}
|
||||
window.test(testFunc(333, 678) === 678, "require overwrite in named function");
|
||||
|
||||
|
||||
require.ensure([], function(require) {
|
||||
var contextRequire = require.context(".");
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
This is a file!
|
||||
|
||||
with some content
|
||||
|
||||
it should break webpack :)
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = function(name) {
|
||||
return require(name);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module.exports = function(name) {
|
||||
var a = load(require, name);
|
||||
var r = require;
|
||||
var b = r(name);
|
||||
if(a !== b) return "FAIL";
|
||||
return a;
|
||||
}
|
||||
|
||||
function load(requireFunction, name) {
|
||||
return requireFunction(name);
|
||||
}
|
Loading…
Reference in New Issue