mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			272 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| /*
 | |
| 	MIT License http://www.opensource.org/licenses/mit-license.php
 | |
| 	Author Tobias Koppers @sokra
 | |
| */
 | |
| var Module = require("./Module");
 | |
| var NormalModuleMixin = require("webpack-core/lib/NormalModuleMixin");
 | |
| var SourceMapSource = require("webpack-core/lib/SourceMapSource");
 | |
| var OriginalSource = require("webpack-core/lib/OriginalSource");
 | |
| var RawSource = require("webpack-core/lib/RawSource");
 | |
| var ReplaceSource = require("webpack-core/lib/ReplaceSource");
 | |
| var ModuleParseError = require("./ModuleParseError");
 | |
| var TemplateArgumentDependency = require("./dependencies/TemplateArgumentDependency");
 | |
| var path = require("path");
 | |
| 
 | |
| function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) {
 | |
| 	Module.call(this);
 | |
| 	this.request = request;
 | |
| 	this.userRequest = userRequest;
 | |
| 	this.rawRequest = rawRequest;
 | |
| 	this.parser = parser;
 | |
| 	NormalModuleMixin.call(this, loaders, resource);
 | |
| 	this.meta = {};
 | |
| 	this.assets = {};
 | |
| 	this.built = false;
 | |
| 	this._cachedSource = null;
 | |
| }
 | |
| module.exports = NormalModule;
 | |
| 
 | |
| NormalModule.prototype = Object.create(Module.prototype);
 | |
| NormalModuleMixin.mixin(NormalModule.prototype);
 | |
| 
 | |
| NormalModule.prototype.identifier = function() {
 | |
| 	return this.request;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.readableIdentifier = function(requestShortener) {
 | |
| 	return requestShortener.shorten(this.userRequest);
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.fillLoaderContext = function fillLoaderContext(loaderContext, options, compilation) {
 | |
| 	loaderContext.webpack = true;
 | |
| 	loaderContext.sourceMap = !!this.useSourceMap;
 | |
| 	loaderContext.emitFile = function(name, content, sourceMap) {
 | |
| 		if(typeof sourceMap === "string") {
 | |
| 			this.assets[name] = new OriginalSource(content, sourceMap);
 | |
| 		} else if(sourceMap) {
 | |
| 			this.assets[name] = new SourceMapSource(content, name, sourceMap);
 | |
| 		} else {
 | |
| 			this.assets[name] = new RawSource(content);
 | |
| 		}
 | |
| 	}.bind(this);
 | |
| 	loaderContext._module = this;
 | |
| 	loaderContext._compilation = compilation;
 | |
| 	loaderContext._compiler = compilation.compiler;
 | |
| 	compilation.applyPlugins("normal-module-loader", loaderContext, this);
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.disconnect = function disconnect() {
 | |
| 	this.built = false;
 | |
| 	Module.prototype.disconnect.call(this);
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.build = function build(options, compilation, resolver, fs, callback) {
 | |
| 	this.buildTimestamp = new Date().getTime();
 | |
| 	this.built = true;
 | |
| 	return this.doBuild(options, compilation, resolver, fs, function(err) {
 | |
| 		if(err) return callback(err);
 | |
| 		this.dependencies.length = 0;
 | |
| 		this.variables.length = 0;
 | |
| 		this.blocks.length = 0;
 | |
| 		this._cachedSource = null;
 | |
| 		if(options.module && options.module.noParse) {
 | |
| 			if(Array.isArray(options.module.noParse)) {
 | |
| 				if(options.module.noParse.some(function(regExp) {
 | |
| 					return typeof regExp === "string" ?
 | |
| 						this.request.indexOf(regExp) === 0 :
 | |
| 						regExp.test(this.request);
 | |
| 				}, this)) return callback();
 | |
| 			} else if(typeof regExp === "string" ?
 | |
| 					this.request.indexOf(options.module.noParse) === 0 :
 | |
| 					options.module.noParse.test(this.request)) {
 | |
| 				return callback();
 | |
| 			}
 | |
| 		}
 | |
| 		try {
 | |
| 			this.parser.parse(this._source.source(), {
 | |
| 				current: this,
 | |
| 				module: this,
 | |
| 				compilation: compilation,
 | |
| 				options: options
 | |
| 			});
 | |
| 		} catch(e) {
 | |
| 			var source = this._source.source();
 | |
| 			this._source = null;
 | |
| 			return callback(new ModuleParseError(this, source, e));
 | |
| 		}
 | |
| 		return callback();
 | |
| 	}.bind(this));
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.source = function(dependencyTemplates, outputOptions, requestShortener) {
 | |
| 	var hash = require("crypto").createHash("md5");
 | |
| 	this.updateHash(hash);
 | |
| 	hash = hash.digest("hex");
 | |
| 	if(this._cachedSource && this._cachedSource.hash === hash) {
 | |
| 		return this._cachedSource.source;
 | |
| 	}
 | |
| 	var _source = this._source;
 | |
| 	if(!_source) return new RawSource("throw new Error('No source availible');");
 | |
| 	var source = new ReplaceSource(_source);
 | |
| 	this._cachedSource = { source: source, hash: hash };
 | |
| 	var topLevelBlock = this;
 | |
| 	function doDep(dep) {
 | |
| 		var template = dependencyTemplates.get(dep.Class);
 | |
| 		if(!template) throw new Error("No template for dependency: " + dep.Class.name);
 | |
| 		template.apply(dep, source, outputOptions, requestShortener, dependencyTemplates);
 | |
| 	}
 | |
| 	function doVariable(vars, variable) {
 | |
| 		var name = variable.name;
 | |
| 		var expr = variable.expressionSource(dependencyTemplates, outputOptions, requestShortener);
 | |
| 		vars.push({name: name, expression: expr});
 | |
| 	}
 | |
| 	function doBlock(block) {
 | |
| 		block.dependencies.forEach(doDep);
 | |
| 		block.blocks.forEach(doBlock);
 | |
| 		if(block.variables.length > 0) {
 | |
| 			var vars = [];
 | |
| 			block.variables.forEach(doVariable.bind(null, vars));
 | |
| 			var varNames = [];
 | |
| 			var varExpressions = [];
 | |
| 			var varStartCode = "";
 | |
| 			var varEndCode = "";
 | |
| 			function emitFunction() {
 | |
| 				if(varNames.length === 0) return;
 | |
| 
 | |
| 				varStartCode += "/* WEBPACK VAR INJECTION */(function(" + varNames.join(", ") + ") {";
 | |
| 				// exports === this in the topLevelBlock, but exports do compress better...
 | |
| 				varEndCode = (topLevelBlock === block ? "}.call(exports, " : "}.call(this, ") +
 | |
| 					varExpressions.map(function(e) {return e.source()}).join(", ") + "))" + varEndCode;
 | |
| 
 | |
| 				varNames.length = 0;
 | |
| 				varExpressions.length = 0;
 | |
| 			}
 | |
| 			vars.forEach(function(v) {
 | |
| 				if(varNames.indexOf(v.name) >= 0) emitFunction();
 | |
| 				varNames.push(v.name);
 | |
| 				varExpressions.push(v.expression);
 | |
| 			});
 | |
| 			emitFunction();
 | |
| 			var start = block.range ? block.range[0] : 0;
 | |
| 			var end = block.range ? block.range[1] : _source.size();
 | |
| 			if(varStartCode) source.insert(start + 0.5, varStartCode);
 | |
| 			if(varEndCode) source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);
 | |
| 		}
 | |
| 	}
 | |
| 	doBlock(this);
 | |
| 	return source;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.needRebuild = function needRebuild(fileTimestamps, contextTimestamps) {
 | |
| 	var timestamp = 0;
 | |
| 	this.fileDependencies.forEach(function(file) {
 | |
| 		var ts = fileTimestamps[file];
 | |
| 		if(!ts) timestamp = Infinity;
 | |
| 		if(ts > timestamp) timestamp = ts;
 | |
| 	});
 | |
| 	this.contextDependencies.forEach(function(context) {
 | |
| 		var ts = contextTimestamps[context];
 | |
| 		if(!ts) timestamp = Infinity;
 | |
| 		if(ts > timestamp) timestamp = ts;
 | |
| 	});
 | |
| 	return timestamp >= this.buildTimestamp;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.size = function() {
 | |
| 	return this._source ? this._source.size() : -1;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.updateHash = function(hash) {
 | |
| 	if(this._source) {
 | |
| 		hash.update("source");
 | |
| 		this._source.updateHash(hash);
 | |
| 	} else
 | |
| 		hash.update("null");
 | |
| 	Module.prototype.updateHash.call(this, hash);
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.getSourceHash = function() {
 | |
| 	if(!this._source) return "";
 | |
| 	var hash = require("crypto").createHash("md5");
 | |
| 	hash.update(this._source.source());
 | |
| 	return hash.digest("hex");
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.getAllModuleDependencies = function() {
 | |
| 	var list = [];
 | |
| 	function doDep(dep) {
 | |
| 		if(dep.module && list.indexOf(dep.module) < 0)
 | |
| 			list.push(dep.module);
 | |
| 	}
 | |
| 	function doVariable(variable) {
 | |
| 		variable.dependencies.forEach(doDep);
 | |
| 	}
 | |
| 	function doBlock(block) {
 | |
| 		block.variables.forEach(doVariable);
 | |
| 		block.dependencies.forEach(doDep);
 | |
| 		block.blocks.forEach(doBlock);
 | |
| 	}
 | |
| 	doBlock(this);
 | |
| 	return list;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.createTemplate = function(keepModules) {
 | |
| 	var template = new NormalModule("", "", "", [], "", null);
 | |
| 	template._source = this._source;
 | |
| 	template.built = this.built;
 | |
| 	template.templateModules = keepModules;
 | |
| 	template._templateOrigin = this;
 | |
| 	template.readableIdentifier = function() {
 | |
| 		return "template of " + this._templateOrigin.id + " referencing " + keepModules.map(function(m) {
 | |
| 			return m.id;
 | |
| 		}).join(", ");
 | |
| 	};
 | |
| 	var args = template.arguments = [];
 | |
| 	function doDeps(deps) {
 | |
| 		return deps.map(function(dep) {
 | |
| 			if(dep.module && keepModules.indexOf(dep.module) < 0) {
 | |
| 				var argName = "__webpack_module_template_argument_" + args.length + "__";
 | |
| 				args.push(argName);
 | |
| 				return new TemplateArgumentDependency(argName, dep);
 | |
| 			} else {
 | |
| 				return dep;
 | |
| 			}
 | |
| 		});
 | |
| 	}
 | |
| 	function doVariable(variable, newVariable) {
 | |
| 		variable.dependencies.forEach(doDep);
 | |
| 	}
 | |
| 	function doBlock(block, newBlock) {
 | |
| 		block.variables.forEach(function(variable) {
 | |
| 			var newDependencies = doDeps(variable.dependencies);
 | |
| 			newBlock.addVariable(variable.name, variable.expression, newDependencies);
 | |
| 		});
 | |
| 		newBlock.dependencies = doDeps(block.dependencies);
 | |
| 		block.blocks.forEach(function(childBlock) {
 | |
| 			var newChildBlock = new AsyncDependenciesBlock(childBlock.name, childBlock.module, childBlock.loc);
 | |
| 			newBlock.addBlock(newChildBlock);
 | |
| 			doBlock(childBlock, newChildBlock);
 | |
| 		});
 | |
| 	}
 | |
| 	doBlock(this, template);
 | |
| 	return template;
 | |
| };
 | |
| 
 | |
| NormalModule.prototype.getTemplateArguments = function(keepModules) {
 | |
| 	var list = [];
 | |
| 	function doDep(dep) {
 | |
| 		if(dep.module && keepModules.indexOf(dep.module) < 0)
 | |
| 			list.push(dep.module);
 | |
| 	}
 | |
| 	function doVariable(variable) {
 | |
| 		variable.dependencies.forEach(doDep);
 | |
| 	}
 | |
| 	function doBlock(block) {
 | |
| 		block.variables.forEach(doVariable);
 | |
| 		block.dependencies.forEach(doDep);
 | |
| 		block.blocks.forEach(doBlock);
 | |
| 	}
 | |
| 	doBlock(this);
 | |
| 	return list;
 | |
| };
 |