241 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var mime = require("mime");
 | 
						|
var parseRange = require("range-parser");
 | 
						|
var pathIsAbsolute = require("path-is-absolute");
 | 
						|
var MemoryFileSystem = require("memory-fs");
 | 
						|
var timestamp = require("time-stamp");
 | 
						|
 | 
						|
var HASH_REGEXP = /[0-9a-f]{10,}/;
 | 
						|
 | 
						|
module.exports = function Shared(context) {
 | 
						|
	var share = {
 | 
						|
		setOptions: function(options) {
 | 
						|
			if(!options) options = {};
 | 
						|
			if(typeof options.reportTime === "undefined") options.reportTime = false;
 | 
						|
			if(typeof options.watchOptions === "undefined") options.watchOptions = {};
 | 
						|
			if(typeof options.reporter !== "function") options.reporter = share.defaultReporter;
 | 
						|
			if(typeof options.log !== "function") options.log = console.log.bind(console);
 | 
						|
			if(typeof options.warn !== "function") options.warn = console.warn.bind(console);
 | 
						|
			if(typeof options.error !== "function") options.error = console.error.bind(console);
 | 
						|
			if(typeof options.watchDelay !== "undefined") {
 | 
						|
				// TODO remove this in next major version
 | 
						|
				options.warn("options.watchDelay is deprecated: Use 'options.watchOptions.aggregateTimeout' instead");
 | 
						|
				options.watchOptions.aggregateTimeout = options.watchDelay;
 | 
						|
			}
 | 
						|
			if(typeof options.watchOptions.aggregateTimeout === "undefined") options.watchOptions.aggregateTimeout = 200;
 | 
						|
			if(typeof options.stats === "undefined") options.stats = {};
 | 
						|
			if(!options.stats.context) options.stats.context = process.cwd();
 | 
						|
			if(options.lazy) {
 | 
						|
				if(typeof options.filename === "string") {
 | 
						|
					var str = options.filename
 | 
						|
						.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
 | 
						|
						.replace(/\\\[[a-z]+\\\]/ig, ".+");
 | 
						|
					options.filename = new RegExp("^[\/]{0,1}" + str + "$");
 | 
						|
				}
 | 
						|
			}
 | 
						|
			// defining custom MIME type
 | 
						|
			if(options.mimeTypes) mime.define(options.mimeTypes);
 | 
						|
 | 
						|
			context.options = options;
 | 
						|
		},
 | 
						|
		defaultReporter: function(reporterOptions) {
 | 
						|
			var time = "";
 | 
						|
			var state = reporterOptions.state;
 | 
						|
			var stats = reporterOptions.stats;
 | 
						|
			var options = reporterOptions.options;
 | 
						|
 | 
						|
			if(!!options.reportTime) {
 | 
						|
				time = "[" + timestamp("HH:mm:ss") + "] ";
 | 
						|
			}
 | 
						|
			if(state) {
 | 
						|
				var displayStats = (!options.quiet && options.stats !== false);
 | 
						|
				if(displayStats && !(stats.hasErrors() || stats.hasWarnings()) &&
 | 
						|
					options.noInfo)
 | 
						|
					displayStats = false;
 | 
						|
				if(displayStats) {
 | 
						|
					if(stats.hasErrors()) {
 | 
						|
						options.error(stats.toString(options.stats));
 | 
						|
					} else if(stats.hasWarnings()) {
 | 
						|
						options.warn(stats.toString(options.stats));
 | 
						|
					} else {
 | 
						|
						options.log(stats.toString(options.stats));
 | 
						|
					}
 | 
						|
				}
 | 
						|
				if(!options.noInfo && !options.quiet) {
 | 
						|
					var msg = "Compiled successfully.";
 | 
						|
					if(stats.hasErrors()) {
 | 
						|
						msg = "Failed to compile.";
 | 
						|
					  } else if(stats.hasWarnings()) {
 | 
						|
						msg = "Compiled with warnings.";
 | 
						|
					}
 | 
						|
					options.log(time + "webpack: " + msg);
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				options.log(time + "webpack: Compiling...");
 | 
						|
			}
 | 
						|
		},
 | 
						|
		handleRangeHeaders: function handleRangeHeaders(content, req, res) {
 | 
						|
			//assumes express API. For other servers, need to add logic to access alternative header APIs
 | 
						|
			res.setHeader("Accept-Ranges", "bytes");
 | 
						|
			if(req.headers.range) {
 | 
						|
				var ranges = parseRange(content.length, req.headers.range);
 | 
						|
 | 
						|
				// unsatisfiable
 | 
						|
				if(-1 == ranges) {
 | 
						|
					res.setHeader("Content-Range", "bytes */" + content.length);
 | 
						|
					res.statusCode = 416;
 | 
						|
				}
 | 
						|
 | 
						|
				// valid (syntactically invalid/multiple ranges are treated as a regular response)
 | 
						|
				if(-2 != ranges && ranges.length === 1) {
 | 
						|
					// Content-Range
 | 
						|
					res.statusCode = 206;
 | 
						|
					var length = content.length;
 | 
						|
					res.setHeader(
 | 
						|
						"Content-Range",
 | 
						|
						"bytes " + ranges[0].start + "-" + ranges[0].end + "/" + length
 | 
						|
					);
 | 
						|
 | 
						|
					content = content.slice(ranges[0].start, ranges[0].end + 1);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return content;
 | 
						|
		},
 | 
						|
		setFs: function(compiler) {
 | 
						|
			if(typeof compiler.outputPath === "string" && !pathIsAbsolute.posix(compiler.outputPath) && !pathIsAbsolute.win32(compiler.outputPath)) {
 | 
						|
				throw new Error("`output.path` needs to be an absolute path or `/`.");
 | 
						|
			}
 | 
						|
 | 
						|
			// store our files in memory
 | 
						|
			var fs;
 | 
						|
			var isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;
 | 
						|
			if(isMemoryFs) {
 | 
						|
				fs = compiler.outputFileSystem;
 | 
						|
			} else {
 | 
						|
				fs = compiler.outputFileSystem = new MemoryFileSystem();
 | 
						|
			}
 | 
						|
			context.fs = fs;
 | 
						|
		},
 | 
						|
		compilerDone: function(stats) {
 | 
						|
			// We are now on valid state
 | 
						|
			context.state = true;
 | 
						|
			context.webpackStats = stats;
 | 
						|
 | 
						|
			// Do the stuff in nextTick, because bundle may be invalidated
 | 
						|
			// if a change happened while compiling
 | 
						|
			process.nextTick(function() {
 | 
						|
				// check if still in valid state
 | 
						|
				if(!context.state) return;
 | 
						|
				// print webpack output
 | 
						|
				context.options.reporter({
 | 
						|
					state: true,
 | 
						|
					stats: stats,
 | 
						|
					options: context.options
 | 
						|
				});
 | 
						|
 | 
						|
				// execute callback that are delayed
 | 
						|
				var cbs = context.callbacks;
 | 
						|
				context.callbacks = [];
 | 
						|
				cbs.forEach(function continueBecauseBundleAvailable(cb) {
 | 
						|
					cb(stats);
 | 
						|
				});
 | 
						|
			});
 | 
						|
 | 
						|
			// In lazy mode, we may issue another rebuild
 | 
						|
			if(context.forceRebuild) {
 | 
						|
				context.forceRebuild = false;
 | 
						|
				share.rebuild();
 | 
						|
			}
 | 
						|
		},
 | 
						|
		compilerInvalid: function() {
 | 
						|
			if(context.state && (!context.options.noInfo && !context.options.quiet))
 | 
						|
				context.options.reporter({
 | 
						|
					state: false,
 | 
						|
					options: context.options
 | 
						|
				});
 | 
						|
 | 
						|
			// We are now in invalid state
 | 
						|
			context.state = false;
 | 
						|
			//resolve async
 | 
						|
			if(arguments.length === 2 && typeof arguments[1] === "function") {
 | 
						|
				var callback = arguments[1];
 | 
						|
				callback();
 | 
						|
			}
 | 
						|
		},
 | 
						|
		ready: function ready(fn, req) {
 | 
						|
			var options = context.options;
 | 
						|
			if(context.state) return fn(context.webpackStats);
 | 
						|
			if(!options.noInfo && !options.quiet)
 | 
						|
				options.log("webpack: wait until bundle finished: " + (req.url || fn.name));
 | 
						|
			context.callbacks.push(fn);
 | 
						|
		},
 | 
						|
		startWatch: function() {
 | 
						|
			var options = context.options;
 | 
						|
			var compiler = context.compiler;
 | 
						|
			// start watching
 | 
						|
			if(!options.lazy) {
 | 
						|
				var watching = compiler.watch(options.watchOptions, share.handleCompilerCallback);
 | 
						|
				context.watching = watching;
 | 
						|
			} else {
 | 
						|
				context.state = true;
 | 
						|
			}
 | 
						|
		},
 | 
						|
		rebuild: function rebuild() {
 | 
						|
			if(context.state) {
 | 
						|
				context.state = false;
 | 
						|
				context.compiler.run(share.handleCompilerCallback);
 | 
						|
			} else {
 | 
						|
				context.forceRebuild = true;
 | 
						|
			}
 | 
						|
		},
 | 
						|
		handleCompilerCallback: function(err) {
 | 
						|
			if(err) {
 | 
						|
				context.options.error(err.stack || err);
 | 
						|
				if(err.details) context.options.error(err.details);
 | 
						|
			}
 | 
						|
		},
 | 
						|
		handleRequest: function(filename, processRequest, req) {
 | 
						|
			// in lazy mode, rebuild on bundle request
 | 
						|
			if(context.options.lazy && (!context.options.filename || context.options.filename.test(filename)))
 | 
						|
				share.rebuild();
 | 
						|
			if(HASH_REGEXP.test(filename)) {
 | 
						|
				try {
 | 
						|
					if(context.fs.statSync(filename).isFile()) {
 | 
						|
						processRequest();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				} catch(e) {
 | 
						|
				}
 | 
						|
			}
 | 
						|
			share.ready(processRequest, req);
 | 
						|
		},
 | 
						|
		waitUntilValid: function(callback) {
 | 
						|
			callback = callback || function() {};
 | 
						|
			share.ready(callback, {});
 | 
						|
		},
 | 
						|
		invalidate: function(callback) {
 | 
						|
			callback = callback || function() {};
 | 
						|
			if(context.watching) {
 | 
						|
				share.ready(callback, {});
 | 
						|
				context.watching.invalidate();
 | 
						|
			} else {
 | 
						|
				callback();
 | 
						|
			}
 | 
						|
		},
 | 
						|
		close: function(callback) {
 | 
						|
			callback = callback || function() {};
 | 
						|
			if(context.watching) context.watching.close(callback);
 | 
						|
			else callback();
 | 
						|
		}
 | 
						|
	};
 | 
						|
	share.setOptions(context.options);
 | 
						|
	share.setFs(context.compiler);
 | 
						|
 | 
						|
	context.compiler.plugin("done", share.compilerDone);
 | 
						|
	context.compiler.plugin("invalid", share.compilerInvalid);
 | 
						|
	context.compiler.plugin("watch-run", share.compilerInvalid);
 | 
						|
	context.compiler.plugin("run", share.compilerInvalid);
 | 
						|
 | 
						|
	share.startWatch();
 | 
						|
	return share;
 | 
						|
};
 |