better loader support
This commit is contained in:
parent
41f36de302
commit
97ed773cb1
|
@ -0,0 +1,5 @@
|
|||
/node_modules
|
||||
/test/js
|
||||
/test/browsertest/js
|
||||
/examples
|
||||
README.md
|
92
README.md
92
README.md
|
@ -2,6 +2,7 @@
|
|||
|
||||
As developer you want to reuse existing code.
|
||||
As with node.js and web all file are already in the same language, but it is extra work to use your code with the node.js module system and the browser.
|
||||
|
||||
The goal of `webpack` is to bundle CommonJs modules into javascript files which can be loaded by `<script>`-tags.
|
||||
Simply concating all required files has a disadvantage: many code to download (and execute) on page load.
|
||||
Therefore `webpack` uses the `require.ensure` function ([CommonJs/Modules/Async/A](http://wiki.commonjs.org/wiki/Modules/Async/A)) to split your code automatically into multiple bundles which are loaded on demand.
|
||||
|
@ -12,16 +13,16 @@ The result is a smaller inital code download which results in faster page load.
|
|||
|
||||
* bundle CommonJs modules for browser
|
||||
* reuse server-side code (node.js) on client-side
|
||||
* create multiple files which are loaded on demand (faster page load in big webapps)
|
||||
* dependencies managed for you, on compile time
|
||||
* create multiple files which are loaded on demand (faster page load in big webapps or on mobile connections)
|
||||
* dependencies managed for you, on compile time (no resolution on runtime needed)
|
||||
|
||||
## Goals
|
||||
|
||||
* minimize code size
|
||||
* make node.js and browser development similar
|
||||
* minimize code size (mobile connection)
|
||||
* minimize code size on inital download
|
||||
* download code only on demand
|
||||
* hide development details, like module names and folder structure
|
||||
* require minimal configuration
|
||||
* require minimal configuration, but offer a maximum
|
||||
* load polyfills for node-specific things if used
|
||||
* offer replacements for node buildin libaries
|
||||
|
||||
|
@ -83,6 +84,10 @@ File 2: 1.web.js
|
|||
- code of module d and dependencies
|
||||
```
|
||||
|
||||
Initially only `web.js` is included (and loaded) by your application.
|
||||
`1.web.js` is loaded when the call to `require.ensure` happens.
|
||||
After the second bundle (`1.web.js`) is loaded, the callback function will be invoked.
|
||||
|
||||
See [details](modules-webpack/tree/master/examples/code-splitting) for exact output.
|
||||
|
||||
## Reusing node.js code
|
||||
|
@ -143,7 +148,7 @@ function getTemplate(templateName) {
|
|||
// which compiles to: return require(123)("./"+templateName)
|
||||
```
|
||||
|
||||
See [details](modules-webpack/tree/master/examples/require.context) for complete example.
|
||||
See [details](/sokra/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 compatible.
|
||||
|
@ -168,7 +173,7 @@ The `raw` loader plugin is looked up at modules `raw-webpack-web-loader`, `raw-w
|
|||
and the following files are looked up: `index.webpack-web-loader.js`, `index.webpack-loader.js`, `index.web-loader.js`, `index.loader.js`, `index`, `index.js`.
|
||||
Note that the `web-` versions are omitted if loaders are used in node.js.
|
||||
|
||||
See [example](modules-webpack/tree/master/examples/loader).
|
||||
See [example](/sokra/modules-webpack/tree/master/examples/loader).
|
||||
|
||||
The following loaders are included as optional dependencies:
|
||||
|
||||
|
@ -218,7 +223,7 @@ try `--min` to minimize with `uglify-js`.
|
|||
|
||||
### `require`-function
|
||||
|
||||
* `require` should not be overwritten
|
||||
* `require` should not be overwritten, except from polyfill
|
||||
* `require.ensure` should not be overwritten or called indirect
|
||||
* `require.context` should not be overwritten or called indirect
|
||||
* the argument to `require.context` should be a literal or addition of multiple literals
|
||||
|
@ -226,21 +231,22 @@ try `--min` to minimize with `uglify-js`.
|
|||
|
||||
The following cases could result in **too much code** in result file if used wrong:
|
||||
|
||||
* indirect call of `require`: `var r = require; r("./file");`
|
||||
* indirect call of `require`: `var r = require; r("./file");`. It includes the whole directory.
|
||||
* `require.context`. It includes the whole directory.
|
||||
* expressions in require arguments: `require(variable)` (but `webpack` is smart enough for this `require(condition ? "a" : "b")`)
|
||||
* the function passed to `require.ensure` is not inlined in the call.
|
||||
* expressions in require arguments: `require(variable)`. It includes the whole directory. (except from `?:`-operator `require(condition ? "a" : "b")`)
|
||||
* the function passed to `require.ensure` is not inlined in the call. Only requires in inlined function move into the second bundle.
|
||||
|
||||
|
||||
### node.js specific modules
|
||||
|
||||
As node.js specific modules like `fs` will not work in browser they are not included and cause an error.
|
||||
As node.js specific modules like `fs` will not work in browser they are not included (by default) and cause an exception.
|
||||
You should replace them by own modules if you want to use them.
|
||||
For some modules are replacements included in `webpack`.
|
||||
Some credit goes to the browserify contributors, as I took some replacements from them.
|
||||
For some simple modules are replacements included in `webpack`.
|
||||
Expensive replacements are not needed by everyone, so that are not included by default.
|
||||
You need to specify `--alias [module]=[replacement]` to use them.
|
||||
A warning saying that some module is missing is emitted in the case you use it.
|
||||
A warning saying that some module is missing is emitted in the case you use it without providing a replacement.
|
||||
|
||||
Some credit goes to the browserify contributors, you can use replacements provided by them.
|
||||
|
||||
Included simple replacements:
|
||||
|
||||
|
@ -289,32 +295,76 @@ webpack(absoluteModulePath, [options], callback)
|
|||
|
||||
#### `options`
|
||||
|
||||
you can save this options object in a JSON file and use it with the shell command.
|
||||
You can also save this options object in a JSON file and use it with the shell command.
|
||||
|
||||
`outputJsonpFunction`
|
||||
|
||||
JSONP function used to load chunks
|
||||
|
||||
`scriptSrcPrefix`
|
||||
|
||||
Path from where chunks are loaded
|
||||
|
||||
`outputDirectory`
|
||||
|
||||
write files to this directory (absolute path)
|
||||
|
||||
`output`
|
||||
|
||||
write first chunk to this file
|
||||
|
||||
`outputPostfix`
|
||||
|
||||
write chunks to files named chunkId plus outputPostfix
|
||||
|
||||
`libary`
|
||||
|
||||
exports of input file are stored in this variable
|
||||
|
||||
`minimize`
|
||||
|
||||
minimize outputs with uglify-js
|
||||
|
||||
`includeFilenames`
|
||||
|
||||
add absolute filenames of input files as comments
|
||||
|
||||
`resolve.alias` (object)
|
||||
|
||||
replace a module. ex. `{"old-module": "new-module"}`
|
||||
|
||||
`resolve.paths` (array)
|
||||
|
||||
search paths
|
||||
|
||||
`resolve.extensions` (object)
|
||||
|
||||
possible extensions for files
|
||||
|
||||
default: `["", ".webpack.js", ".web.js", ".js"]`
|
||||
|
||||
`resolve.loaders` (array)
|
||||
|
||||
extension to loader mappings. ex. `[{test: /\.extension$/, loader: "myloader"}]`
|
||||
|
||||
loads files that matches the RegExp to the loader if no other loader set
|
||||
|
||||
`resolve.loaderExtensions` (array)
|
||||
|
||||
possible extensions for loaders
|
||||
|
||||
default: `[".webpack-web-loader.js", ".webpack-loader.js", ".web-loader.js", ".loader.js", "", ".js"]`
|
||||
|
||||
`resolve.loaderPostfixes` (array)
|
||||
|
||||
possible postfixes for loaders
|
||||
|
||||
default: `["-webpack-web-loader", "-webpack-loader", "-web-loader", "-loader", ""]`
|
||||
|
||||
`parse.overwrites` (object)
|
||||
|
||||
free module variables which are replaced with a module. ex. `{ "$": "jquery" }`
|
||||
|
||||
#### `callback`
|
||||
|
||||
`function(err, source / stats)`
|
||||
|
@ -439,13 +489,13 @@ else `stats` as json see [example](modules-webpack/tree/master/examples/code-spl
|
|||
<code>require("http");</code>
|
||||
</td>
|
||||
<td>
|
||||
some
|
||||
some optional
|
||||
</td>
|
||||
<td>
|
||||
no
|
||||
</td>
|
||||
<td>
|
||||
many
|
||||
many by default
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -559,7 +609,7 @@ else `stats` as json see [example](modules-webpack/tree/master/examples/code-spl
|
|||
require JSON
|
||||
</td>
|
||||
<td>
|
||||
yes **NEW**
|
||||
yes <em>NEW</em>
|
||||
</td>
|
||||
<td>
|
||||
no
|
||||
|
@ -589,7 +639,7 @@ else `stats` as json see [example](modules-webpack/tree/master/examples/code-spl
|
|||
loaders
|
||||
</td>
|
||||
<td>
|
||||
yes **NEW**
|
||||
yes <em>NEW</em>
|
||||
</td>
|
||||
<td>
|
||||
no
|
||||
|
@ -604,7 +654,7 @@ else `stats` as json see [example](modules-webpack/tree/master/examples/code-spl
|
|||
compile coffee script
|
||||
</td>
|
||||
<td>
|
||||
yes **NEW**
|
||||
yes <em>NEW</em>
|
||||
</td>
|
||||
<td>
|
||||
no
|
||||
|
|
|
@ -39,10 +39,14 @@ var argv = require("optimist")
|
|||
.boolean("json")
|
||||
.describe("json", "Output Stats as JSON")
|
||||
.default("json", false)
|
||||
|
||||
|
||||
.string("alias")
|
||||
.describe("alias", "Set a alias name for a module. ex. http=http-browserify")
|
||||
|
||||
.boolean("debug")
|
||||
.describe("debug", "Prints debug info to output files")
|
||||
.default("debug", false)
|
||||
|
||||
.demand(1)
|
||||
.argv;
|
||||
|
||||
|
@ -70,6 +74,10 @@ if(argv.min) {
|
|||
options.minimize = true;
|
||||
}
|
||||
|
||||
if(argv.debug) {
|
||||
options.debug = true;
|
||||
}
|
||||
|
||||
if(argv.filenames) {
|
||||
options.includeFilenames = true;
|
||||
}
|
||||
|
@ -161,6 +169,11 @@ if(argv.single) {
|
|||
console.log("\033[1m\033[33mWARNING: " + warning + "\033[39m\033[22m");
|
||||
});
|
||||
}
|
||||
if(stats.errors) {
|
||||
stats.errors.forEach(function(error) {
|
||||
console.log("\033[1m\033[31mERROR: " + error + "\033[39m\033[22m");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
167
lib/buildDeps.js
167
lib/buildDeps.js
|
@ -22,6 +22,7 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
|
|||
|
||||
var depTree = {
|
||||
warnings: [],
|
||||
errors: [],
|
||||
modules: {},
|
||||
modulesById: {},
|
||||
chunks: {},
|
||||
|
@ -57,11 +58,71 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function addModule(depTree, context, module, options, reason, callback) {
|
||||
if(context)
|
||||
resolve(context, module, options.resolve, resolved);
|
||||
else
|
||||
resolved(null, module);
|
||||
function execLoaders(request, loaders, filenames, contents, options, callback) {
|
||||
if(loaders.length === 0)
|
||||
callback(null, contents[0]);
|
||||
else {
|
||||
var loaderFunctions = [];
|
||||
try {
|
||||
loaders.forEach(function(name) {
|
||||
var loader = require(name);
|
||||
loaderFunctions.push(loader);
|
||||
});
|
||||
} catch(e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
function nextLoader() {
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
var err = args.shift();
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if(loaderFunctions.length > 0) {
|
||||
try {
|
||||
var async = false;
|
||||
var context = {
|
||||
request: request,
|
||||
filenames: filenames,
|
||||
exec: function(code, filename) {
|
||||
var Module = require("module");
|
||||
var m = new Module("exec in " + request, module);
|
||||
m._compile(code, filename);
|
||||
return m.exports;
|
||||
},
|
||||
async: function() {
|
||||
async = true;
|
||||
return nextLoader;
|
||||
},
|
||||
callback: function() {
|
||||
async = true;
|
||||
nextLoader.apply(null, arguments);
|
||||
},
|
||||
web: true,
|
||||
debug: options.debug,
|
||||
values: undefined,
|
||||
options: options
|
||||
};
|
||||
var retVal = loaderFunctions.pop().apply(context, args);
|
||||
if(!async)
|
||||
nextLoader(retVal === undefined ? new Error("loader did not return a value") : null, retVal);
|
||||
} catch(e) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
callback(null, args[0]);
|
||||
}
|
||||
}
|
||||
contents.unshift(null);
|
||||
nextLoader.apply(null, contents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addModule(depTree, context, modu, options, reason, callback) {
|
||||
resolve(context || path.dirname(modu), modu, options.resolve, resolved);
|
||||
function resolved(err, filename) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
|
@ -71,12 +132,12 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
depTree.modules[filename].reasons.push(reason);
|
||||
callback(null, depTree.modules[filename].id);
|
||||
} else {
|
||||
var module = depTree.modules[filename] = {
|
||||
var modu = depTree.modules[filename] = {
|
||||
id: depTree.nextModuleId++,
|
||||
filename: filename,
|
||||
reasons: [reason]
|
||||
};
|
||||
depTree.modulesById[module.id] = module;
|
||||
depTree.modulesById[modu.id] = modu;
|
||||
var filenameWithLoaders = filename;
|
||||
var loaders = filename.split(/!/g);
|
||||
filename = loaders.pop();
|
||||
|
@ -85,41 +146,12 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
callback(err);
|
||||
return;
|
||||
}
|
||||
if(loaders.length === 0)
|
||||
processJs(content);
|
||||
else {
|
||||
var loaderFunctions = [];
|
||||
try {
|
||||
loaders.forEach(function(name) {
|
||||
var loader = require(name);
|
||||
loaderFunctions.push(loader);
|
||||
});
|
||||
} catch(e) {
|
||||
callback(e);
|
||||
execLoaders(filenameWithLoaders, loaders, [filename], [content], options, processJs);
|
||||
function processJs(err, source) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
function nextLoader(err, content) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if(loaderFunctions.length > 0) {
|
||||
try {
|
||||
loaderFunctions.pop()([content], {
|
||||
request: filenameWithLoaders,
|
||||
filename: filename
|
||||
}, nextLoader);
|
||||
} catch(e) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
processJs(content);
|
||||
}
|
||||
}
|
||||
nextLoader(null, content);
|
||||
}
|
||||
function processJs(source) {
|
||||
var deps;
|
||||
try {
|
||||
deps = parse(source, options.parse);
|
||||
|
@ -127,10 +159,10 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
callback("File \"" + filenameWithLoaders + "\" parsing failed: " + e);
|
||||
return;
|
||||
}
|
||||
module.requires = deps.requires || [];
|
||||
module.asyncs = deps.asyncs || [];
|
||||
module.contexts = deps.contexts || [];
|
||||
module.source = source;
|
||||
modu.requires = deps.requires || [];
|
||||
modu.asyncs = deps.asyncs || [];
|
||||
modu.contexts = deps.contexts || [];
|
||||
modu.source = source;
|
||||
|
||||
var requires = {}, directRequire = {};
|
||||
var contexts = [], directContexts = {};
|
||||
|
@ -143,20 +175,20 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
contexts.push({context: c, module: m});
|
||||
}
|
||||
}
|
||||
if(module.requires) {
|
||||
module.requires.forEach(add);
|
||||
module.requires.forEach(function(r) {
|
||||
if(modu.requires) {
|
||||
modu.requires.forEach(add);
|
||||
modu.requires.forEach(function(r) {
|
||||
directRequire[r.name] = true;
|
||||
});
|
||||
}
|
||||
if(module.contexts) {
|
||||
module.contexts.forEach(addContext(module));
|
||||
module.contexts.forEach(function(c) {
|
||||
if(modu.contexts) {
|
||||
modu.contexts.forEach(addContext(modu));
|
||||
modu.contexts.forEach(function(c) {
|
||||
directContexts[c.name] = true;
|
||||
});
|
||||
}
|
||||
if(module.asyncs)
|
||||
module.asyncs.forEach(function addAsync(c) {
|
||||
if(modu.asyncs)
|
||||
modu.asyncs.forEach(function addAsync(c) {
|
||||
if(c.requires)
|
||||
c.requires.forEach(add);
|
||||
if(c.asyncs)
|
||||
|
@ -176,7 +208,7 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
};
|
||||
addModule(depTree, path.dirname(filename), moduleName, options, reason, function(err, moduleId) {
|
||||
if(err) {
|
||||
depTree.warnings.push("Cannot find module '" + moduleName + "'\n " + 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) {
|
||||
|
@ -196,7 +228,8 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
};
|
||||
addContextModule(depTree, path.dirname(filename), context.name, options, reason, function(err, contextModuleId) {
|
||||
if(err) {
|
||||
errors.push(err+"\n @ " + filename + " (line " + context.line + ", column " + context.column + ")");
|
||||
depTree.errors.push("Cannot find context '"+context.name+"'\n " + err +
|
||||
"\n @ " + filename + " (line " + context.line + ", column " + context.column + ")");
|
||||
} else {
|
||||
context.id = contextModuleId;
|
||||
module.requires.push({id: context.id});
|
||||
|
@ -216,7 +249,7 @@ function addModule(depTree, context, module, options, reason, callback) {
|
|||
if(errors.length) {
|
||||
callback(errors.join("\n"));
|
||||
} else {
|
||||
callback(null, module.id);
|
||||
callback(null, modu.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,6 +279,10 @@ function addContextModule(depTree, context, contextModuleName, options, reason,
|
|||
reasons: [reason]
|
||||
};
|
||||
depTree.modulesById[contextModule.id] = contextModule;
|
||||
var contextModuleNameWithLoaders = dirname;
|
||||
var loaders = dirname.split(/!/g);
|
||||
dirname = loaders.pop();
|
||||
var prependLoaders = loaders.length === 0 ? "" : loaders.join("!") + "!";
|
||||
var extensions = (options.resolve && options.resolve.extensions) || [".web.js", ".js"];
|
||||
function doDir(dirname, moduleName, done) {
|
||||
fs.readdir(dirname, function(err, list) {
|
||||
|
@ -279,12 +316,18 @@ function addContextModule(depTree, context, contextModuleName, options, reason,
|
|||
else
|
||||
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) {
|
||||
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) {
|
||||
if(loader.test.test(filename))
|
||||
match = true;
|
||||
});
|
||||
});
|
||||
if(!match && loaders.length === 0) {
|
||||
endOne();
|
||||
return;
|
||||
}
|
||||
|
@ -292,7 +335,7 @@ function addContextModule(depTree, context, contextModuleName, options, reason,
|
|||
type: "context",
|
||||
filename: reason.filename
|
||||
};
|
||||
addModule(depTree, null, filename, options, reason, function(err, moduleId) {
|
||||
addModule(depTree, dirname, prependLoaders + filename, options, reason, function(err, moduleId) {
|
||||
if(err) {
|
||||
depTree.warnings.push("A file in context was excluded because of error: " + err);
|
||||
endOne();
|
||||
|
|
147
lib/resolve.js
147
lib/resolve.js
|
@ -28,26 +28,33 @@ function resolve(context, identifier, options, type, callback) {
|
|||
}
|
||||
if(identArray[0] === "." || identArray[0] === ".." || identArray[0] === "" || identArray[0].match(/^[A-Z]:$/i)) {
|
||||
var pathname = identArray[0][0] === "." ? join(contextArray, identArray) : path.join.apply(path, identArray);
|
||||
loadAsFile(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
loadAsDirectory(pathname, options, type, finalResult);
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
if(type === "context") {
|
||||
fs.stat(pathname, function(err, stat) {
|
||||
if(err) {
|
||||
finalResult(err);
|
||||
return;
|
||||
}
|
||||
if(!stat.isDirectory()) {
|
||||
finalResult("Context \"" + identifier + "\" in not a directory");
|
||||
return;
|
||||
}
|
||||
callback(null, pathname);
|
||||
});
|
||||
} else {
|
||||
loadAsFile(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
loadAsDirectory(pathname, options, type, finalResult);
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
loadNodeModules(contextArray, identArray, options, type, finalResult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* context: absolute filename of current file
|
||||
* identifier: module to find
|
||||
* options:
|
||||
* paths: array of lookup paths
|
||||
* callback: function(err, absoluteFilename)
|
||||
*/
|
||||
module.exports = function(context, identifier, options, callback) {
|
||||
function doResolve(context, identifier, options, type, callback) {
|
||||
if(!callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
|
@ -93,7 +100,7 @@ module.exports = function(context, identifier, options, callback) {
|
|||
}
|
||||
}
|
||||
identifiers.forEach(function(ident, index) {
|
||||
resolve(context, ident, options, index === identifiers.length - 1 ? "normal" : "loader", function(err, filename) {
|
||||
resolve(context, ident, options, index === identifiers.length - 1 ? type : "loader", function(err, filename) {
|
||||
if(err) {
|
||||
errors.push(err);
|
||||
} else {
|
||||
|
@ -108,42 +115,22 @@ module.exports = function(context, identifier, options, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
module.exports.context = function(context, identifier, options, callback) {
|
||||
if(!callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
if(!options)
|
||||
options = {};
|
||||
if(!options.paths)
|
||||
options.paths = [];
|
||||
function finalResult(err, absoluteFilename) {
|
||||
if(err) {
|
||||
callback("Context \"" + identifier + "\" not found in context \"" + context + "\"");
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
}
|
||||
var identArray = identifier.split("/");
|
||||
var contextArray = split(context);
|
||||
if(identArray[0] === "." || identArray[0] === ".." || identArray[0] === "") {
|
||||
var pathname = join(contextArray, identArray);
|
||||
fs.stat(pathname, function(err, stat) {
|
||||
if(err) {
|
||||
finalResult(err);
|
||||
return;
|
||||
}
|
||||
if(!stat.isDirectory()) {
|
||||
finalResult("Context \"" + identifier + "\" in not a directory");
|
||||
return;
|
||||
}
|
||||
callback(null, pathname);
|
||||
});
|
||||
} else {
|
||||
loadNodeModulesAsContext(contextArray, identArray, options, finalResult);
|
||||
}
|
||||
/**
|
||||
* context: absolute filename of current file
|
||||
* identifier: module to find
|
||||
* options:
|
||||
* paths: array of lookup paths
|
||||
* callback: function(err, absoluteFilename)
|
||||
*/
|
||||
module.exports = function(context, identifier, options, callback) {
|
||||
return doResolve(context, identifier, options, "normal", callback);
|
||||
}
|
||||
|
||||
module.exports.context = function(context, identifier, options, callback) {
|
||||
return doResolve(context, identifier, options, "context", callback);
|
||||
}
|
||||
|
||||
|
||||
function split(a) {
|
||||
return a.split(/[\/\\]/g);
|
||||
}
|
||||
|
@ -214,43 +201,37 @@ function loadNodeModules(context, identifier, options, type, callback) {
|
|||
});
|
||||
function tryDir(dir) {
|
||||
var pathname = join(split(dir), identifier);
|
||||
loadAsFile(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
loadAsDirectory(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
if(dirs.length === 0) {
|
||||
callback("no module in any path of paths");
|
||||
return;
|
||||
}
|
||||
tryDir(dirs.shift());
|
||||
if(type === "context") {
|
||||
fs.stat(pathname, function(err, stat) {
|
||||
if(err || !stat.isDirectory()) {
|
||||
if(dirs.length === 0) {
|
||||
callback("no directory in any path of paths");
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
}
|
||||
tryDir(dirs.shift());
|
||||
});
|
||||
}
|
||||
|
||||
function loadNodeModulesAsContext(context, identifier, options, callback) {
|
||||
nodeModulesPaths(context, options, function(err, dirs) {
|
||||
function tryDir(dir) {
|
||||
var pathname = join(split(dir), identifier);
|
||||
fs.stat(pathname, function(err, stat) {
|
||||
if(err || !stat.isDirectory()) {
|
||||
if(dirs.length === 0) {
|
||||
callback(true);
|
||||
tryDir(dirs.shift());
|
||||
return;
|
||||
}
|
||||
tryDir(dirs.shift());
|
||||
return;
|
||||
}
|
||||
callback(null, pathname);
|
||||
});
|
||||
callback(null, pathname);
|
||||
});
|
||||
} else {
|
||||
loadAsFile(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
loadAsDirectory(pathname, options, type, function(err, absoluteFilename) {
|
||||
if(err) {
|
||||
if(dirs.length === 0) {
|
||||
callback("no module in any path of paths");
|
||||
return;
|
||||
}
|
||||
tryDir(dirs.shift());
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback(null, absoluteFilename);
|
||||
});
|
||||
}
|
||||
}
|
||||
tryDir(dirs.shift());
|
||||
});
|
||||
|
|
|
@ -80,7 +80,7 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
options.resolve.paths.push(path.join(path.dirname(__dirname), "buildin", "node_modules"));
|
||||
options.resolve.paths.push(path.join(path.dirname(__dirname), "node_modules"));
|
||||
options.resolve.alias = options.resolve.alias || {};
|
||||
options.resolve.loaders = options.loaders || [];
|
||||
options.resolve.loaders = options.resolve.loaders || [];
|
||||
options.resolve.loaders.push({test: /\.coffee$/, loader: "coffee"});
|
||||
options.resolve.loaders.push({test: /\.json$/, loader: "json"});
|
||||
options.resolve.loaders.push({test: /\.jade$/, loader: "jade"});
|
||||
|
@ -121,11 +121,11 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
if(Object.keys(depTree.chunks).length > 1) {
|
||||
buffer.push(templateAsync);
|
||||
buffer.push("/******/({a:");
|
||||
buffer.push(stringify(options.outputPostfix));
|
||||
buffer.push(JSON.stringify(options.outputPostfix));
|
||||
buffer.push(",b:");
|
||||
buffer.push(stringify(options.outputJsonpFunction));
|
||||
buffer.push(JSON.stringify(options.outputJsonpFunction));
|
||||
buffer.push(",c:");
|
||||
buffer.push(stringify(options.scriptSrcPrefix));
|
||||
buffer.push(JSON.stringify(options.scriptSrcPrefix));
|
||||
buffer.push(",\n");
|
||||
} else {
|
||||
buffer.push(templateSingle);
|
||||
|
@ -183,6 +183,7 @@ module.exports = function(context, moduleName, options, callback) {
|
|||
buffer.modulesFirstChunk = sum;
|
||||
buffer.fileSizes = fileSizeMap;
|
||||
buffer.warnings = depTree.warnings;
|
||||
buffer.errors = depTree.errors;
|
||||
buffer.fileModules = fileModulesMap;
|
||||
callback(null, buffer);
|
||||
} else {
|
||||
|
@ -218,8 +219,4 @@ function uglify(input, filename) {
|
|||
return input;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
|
@ -2,10 +2,6 @@
|
|||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
||||
|
||||
module.exports = function(module, options) {
|
||||
if(!module.source) {
|
||||
if(module.requireMap) {
|
||||
|
@ -54,19 +50,19 @@ module.exports = function(module, options) {
|
|||
replaces.push({
|
||||
from: contextItem.calleeRange[0],
|
||||
to: contextItem.calleeRange[1],
|
||||
value: "require(" + prefix + ((contextItem.id || "throw new Error('there is not id for this')") + "") + ")"
|
||||
value: "require(" + prefix + ((contextItem.id || JSON.stringify("context: " + contextItem.name || "context failed")) + "") + ")"
|
||||
});
|
||||
if(contextItem.replace)
|
||||
replaces.push({
|
||||
from: contextItem.replace[0][0],
|
||||
to: contextItem.replace[0][1],
|
||||
value: stringify(contextItem.replace[1])
|
||||
value: JSON.stringify(contextItem.replace[1])
|
||||
});
|
||||
} else {
|
||||
replaces.push({
|
||||
from: contextItem.expressionRange[0],
|
||||
to: contextItem.expressionRange[1],
|
||||
value: "require(" + prefix + ((contextItem.id || "throw new Error('there is not id for this')") + "") + ")" + postfix
|
||||
value: "require(" + prefix + ((contextItem.id || JSON.stringify("context: " + contextItem.name || "context failed")) + "") + ")" + postfix
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -109,5 +105,28 @@ module.exports = function(module, options) {
|
|||
remSource.substr(repl.to+1)
|
||||
);
|
||||
});
|
||||
if(options.debug) {
|
||||
if(options.minimize) {
|
||||
result = [uglify(result.join(""), module.filename)];
|
||||
}
|
||||
result.push("\n\n// WEBPACK FOOTER //\n"+
|
||||
"// module.id = " + module.id + "\n" +
|
||||
"//@ sourceURL=webpack-module://" + encodeURI(module.filename).replace(/%5C|%2F/g, "/"));
|
||||
return "eval(" + JSON.stringify(result.join("")) + ")";
|
||||
}
|
||||
return result.join("");
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new Error(filename + " @ Line " + e.line + ", Col " + e.col + ", " + e.message);
|
||||
return input;
|
||||
}
|
||||
return source;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// Polyfill for node.js
|
||||
// - adds require.ensure
|
||||
// - adds require.context
|
||||
// call it like this:
|
||||
// call it like this:
|
||||
// require = require("webpack/require-polyfill")(require.valueOf());
|
||||
// This is only required when you want to use the special require.xxx methods
|
||||
// in server-side code which should be so only in rar cases.
|
||||
|
@ -60,13 +60,40 @@ module.exports = function(req) {
|
|||
if(cacheEntry)
|
||||
return cacheEntry;
|
||||
var content = [require("fs").readFileSync(resource, "utf-8")];
|
||||
var values;
|
||||
function exec(code, filename) {
|
||||
var Module = require("module");
|
||||
var m = new Module("exec in " + cacheLine, module);
|
||||
m._compile(code, filename);
|
||||
return m.exports;
|
||||
}
|
||||
resolved.forEach(function(loader) {
|
||||
content = oldReq(loader)(content, {
|
||||
var set = false, err = null;
|
||||
var context = {
|
||||
request: cacheLine,
|
||||
filename: resource
|
||||
});
|
||||
filenames: [resource],
|
||||
exec: exec,
|
||||
async: function() { return false; },
|
||||
callback: function() {
|
||||
set = true;
|
||||
content = Array.prototype.slice.apply(arguments);
|
||||
err = content.shift();
|
||||
values = context.values;
|
||||
},
|
||||
inputValues: values,
|
||||
values: undefined
|
||||
};
|
||||
var retVal = oldReq(loader).apply(context, content);
|
||||
if(set) {
|
||||
if(err) throw err;
|
||||
} else {
|
||||
content = [retVal];
|
||||
values = context.values;
|
||||
}
|
||||
});
|
||||
return content;
|
||||
if(values !== undefined)
|
||||
return values[0];
|
||||
return exec(content[0], cacheLine);
|
||||
} else
|
||||
return oldReq(name);
|
||||
};
|
||||
|
|
|
@ -121,3 +121,9 @@ window.test(require("json!../../../package.json").name === "webpack", "Buildin '
|
|||
window.test(require("../../../package.json").name === "webpack", "Buildin 'json' loader, by ext");
|
||||
window.test(require("coffee!../resources/script.coffee") === "coffee test", "Buildin 'coffee' loader");
|
||||
window.test(require("../resources/script.coffee") === "coffee test", "Buildin 'coffee' loader, by ext");
|
||||
|
||||
// Loader & Context
|
||||
var abc = "abc", scr = "script.coffee";
|
||||
window.test(require("../resources/" + scr) === "coffee test", "context should process extensions");
|
||||
window.test(require("raw!../resources/" + abc + ".txt") === "abc", "raw loader with context");
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function(contents, options, callback) {
|
||||
callback(null, contents[0].split("").reverse().join(""));
|
||||
module.exports = function(content) {
|
||||
return content.split("").reverse().join("");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
module.exports = function(contents, options, callback) {
|
||||
module.exports = function(content) {
|
||||
var content = contents[0];
|
||||
callback(null, "module.exports=" + stringify(content));
|
||||
callback(null, "module.exports=" + JSON.stringify(content));
|
||||
}
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
module.exports = function(contents, options, callback) {
|
||||
var content = contents[0];
|
||||
callback(null, "module.exports=" + stringify(content+"loader"));
|
||||
module.exports = function(content) {
|
||||
var callback = this.async();
|
||||
callback(null, "module.exports=" + JSON.stringify(content+"loader"));
|
||||
}
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
|
@ -1,7 +1,3 @@
|
|||
module.exports = function(contents, options, callback) {
|
||||
var content = contents[0];
|
||||
callback(null, "module.exports=" + stringify(content+"web"));
|
||||
module.exports = function(content) {
|
||||
this.callback(null, "module.exports=" + JSON.stringify(content+"web"));
|
||||
}
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
|
@ -1,7 +1,3 @@
|
|||
module.exports = function(contents, options, callback) {
|
||||
var content = contents[0];
|
||||
callback(null, "module.exports=" + stringify(content+"webpack"));
|
||||
module.exports = function(content) {
|
||||
return "module.exports=" + JSON.stringify(content+"webpack");
|
||||
}
|
||||
function stringify(str) {
|
||||
return '"' + str.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"") + '"';
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
<title>webpack tests</title>
|
||||
<script>
|
||||
window.test = function(ok, message) {
|
||||
document.write("<p>" + (ok?"OK: ":"FAILED: ")+message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</p>");
|
||||
document.write("<p " + (ok?">OK: ":"style='color: red; font-weight: bold;'>FAILED: ")+message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + "</p>");
|
||||
};
|
||||
window.onerror = function(error) {
|
||||
window.test(false, "Shouldn't throw error: " + error);
|
||||
|
@ -17,6 +17,8 @@
|
|||
window.test = function(ok, message) {
|
||||
var p = document.createElement("p");
|
||||
p.appendChild(document.createTextNode((ok?"OK: ":"FAILED: ")+message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")));
|
||||
if(!ok)
|
||||
p.style = "color: red; font-weight: bold;";
|
||||
document.body.appendChild(p);
|
||||
};
|
||||
window.writing = false;
|
||||
|
|
|
@ -19,6 +19,17 @@ function testResolve(context, moduleName, result) {
|
|||
}
|
||||
}
|
||||
}
|
||||
function testResolveContext(context, moduleName, result) {
|
||||
return {
|
||||
topic: function() {
|
||||
resolve.context(context, moduleName, {}, this.callback);
|
||||
},
|
||||
|
||||
"correct filename": function(filename) {
|
||||
assert.equal(filename, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
vows.describe("resolve").addBatch({
|
||||
|
||||
"resolve simple 1": testResolve(fixtures, "./main1.js", path.join(fixtures, "main1.js")),
|
||||
|
@ -31,6 +42,7 @@ vows.describe("resolve").addBatch({
|
|||
"resolve complex 2": testResolve(path.join(fixtures, "node_modules", "complexm", "web_modules", "m1"),
|
||||
"m2/b.js", path.join(fixtures, "node_modules", "m2", "b.js")),
|
||||
"resolve loader 1": testResolve(fixtures, "m1/a!./main1.js", path.join(fixtures, "node_modules", "m1", "a.js") + "!" + path.join(fixtures, "main1.js")),
|
||||
"resolve loader context 1": testResolveContext(fixtures, "m1/a!./", path.join(fixtures, "node_modules", "m1", "a.js") + "!" + fixtures),
|
||||
|
||||
|
||||
}).export(module);
|
Loading…
Reference in New Issue