Skip to content

Commit 95e8926

Browse files
committed
added watch mode and --progress
1 parent fd34d96 commit 95e8926

File tree

6 files changed

+171
-30
lines changed

6 files changed

+171
-30
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ Options:
308308
--verbose Output dependencies in Stats [boolean] [default: false]
309309
--alias Set a alias name for a module. ex. http=http-browserify [string]
310310
--debug Prints debug info to output files [boolean] [default: false]
311+
--watch Recompiles on changes (except loaders) [boolean] [default: false]
312+
--progress Displays a progress while compiling [boolean] [default: false]
311313
```
312314

313315
### Programmatically Usage
@@ -353,6 +355,10 @@ minimize outputs with uglify-js
353355

354356
prints debug info to output files.
355357

358+
`watch`
359+
360+
recompiles on changes (except loaders)
361+
356362
`includeFilenames`
357363

358364
add absolute filenames of input files as comments
@@ -406,6 +412,10 @@ else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/c
406412
You can use `[hash]` in `scriptSrcPrefix`, `output`, `outputDirectory`, `outputPostfix` and in the shell parameters.
407413
`webpack` will replace it with a hash of your files, when writing.
408414

415+
### From shell
416+
417+
Combine the options `--colors --watch --progress` to get a pretty shell compilation.
418+
409419
## Comparison
410420

411421
<table>
@@ -798,7 +808,6 @@ You are also welcome to correct any spelling mistakes or any language issues, be
798808

799809
## Future plans
800810

801-
* watch mode
802811
* more polyfills for node.js buildin modules, but optional
803812
* `require("webpack/require-polyfill.install")` to install for all modules
804813
* require from protocol `require("http://...")`

bin/webpack.js

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ var argv = require("optimist")
5555
.describe("debug", "Prints debug info to output files")
5656
.default("debug", false)
5757

58+
.boolean("watch")
59+
.describe("watch", "Recompiles on changes (except loaders)")
60+
.default("watch", false)
61+
62+
.boolean("progress")
63+
.describe("progress", "Displays a progress while compiling")
64+
.default("progress", false)
65+
5866
.demand(1)
5967
.argv;
6068

@@ -86,6 +94,10 @@ if(argv.debug) {
8694
options.debug = true;
8795
}
8896

97+
if(argv.watch) {
98+
options.watch = true;
99+
}
100+
89101
if(argv.filenames) {
90102
options.includeFilenames = true;
91103
}
@@ -108,7 +120,11 @@ if(argv.alias) {
108120

109121
var webpack = require("../lib/webpack.js");
110122

111-
if(argv.single) {
123+
function c(str) {
124+
return argv.colors ? str : "";
125+
}
126+
127+
if(!output) {
112128
webpack(input, options, function(err, source) {
113129
if(err) {
114130
console.error(err);
@@ -125,17 +141,14 @@ if(argv.single) {
125141
if(!options.outputDirectory) options.outputDirectory = path.dirname(output);
126142
if(!options.output) options.output = path.basename(output);
127143
if(!options.outputPostfix) options.outputPostfix = "." + path.basename(output);
128-
webpack(input, options, function(err, stats) {
144+
var events = webpack(input, options, function(err, stats) {
129145
if(err) {
130146
console.error(err);
131147
return;
132148
}
133149
if(argv.json)
134150
console.log(util.inspect(stats, false, 10, argv.colors));
135151
else {
136-
function c(str) {
137-
return argv.colors ? str : "";
138-
}
139152
console.log("Hash: "+c("\033[1m") + stats.hash + c("\033[22m"));
140153
console.log("Chunks: "+c("\033[1m") + stats.chunkCount + c("\033[22m"));
141154
console.log("Modules: "+c("\033[1m") + stats.modulesCount + c("\033[22m"));
@@ -219,4 +232,35 @@ if(argv.single) {
219232
}
220233
}
221234
});
235+
if(argv.progress) {
236+
var sum = 0;
237+
var finished = 0;
238+
var chars = 0;
239+
function print() {
240+
var msg = "";
241+
if(sum > 0) {
242+
msg += "compiling... (" + c("\033[1m\033[33m");
243+
msg += sprintf("%4s", finished+"") + "/" + sprintf("%4s", sum+"");
244+
msg += " " + sprintf("%4s", Math.floor(finished*100/sum)+"%");
245+
msg += c("\033[39m\033[22m") + ")";
246+
}
247+
for(var i = 0; i < chars; i++)
248+
process.stdout.write("\b");
249+
process.stdout.write(msg);
250+
chars = msg.length;
251+
}
252+
events.on("task", function() {
253+
sum++;
254+
print();
255+
});
256+
events.on("task-end", function() {
257+
finished++;
258+
print();
259+
});
260+
events.on("bundle", function() {
261+
sum = 0;
262+
finished = 0;
263+
print();
264+
});
265+
}
222266
}

lib/buildDeps.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
1919
options = {};
2020
}
2121
if(!options) options = {};
22+
if(!options.events) options.events = { emit: function() {} };
2223

2324
var depTree = {
2425
warnings: [],
@@ -31,6 +32,10 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
3132
chunkModules: {} // used by checkObsolete
3233
}
3334
var mainModuleId;
35+
options.events.emit("task");
36+
options.events.emit("task");
37+
options.events.emit("task");
38+
options.events.emit("task");
3439
addModule(depTree, context, mainModule, options, {type: "main"}, function(err, id) {
3540
if(err) {
3641
callback(err);
@@ -40,13 +45,19 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
4045
buildTree();
4146
});
4247
function buildTree() {
48+
options.events.emit("task-end");
49+
4350
addChunk(depTree, depTree.modulesById[mainModuleId], options);
4451
createRealIds(depTree, options);
52+
options.events.emit("task-end");
53+
4554
for(var chunkId in depTree.chunks) {
4655
removeParentsModules(depTree, depTree.chunks[chunkId]);
4756
removeChunkIfEmpty(depTree, depTree.chunks[chunkId]);
4857
checkObsolete(depTree, depTree.chunks[chunkId]);
4958
}
59+
options.events.emit("task-end");
60+
5061
// cleanup
5162
delete depTree.chunkModules;
5263
depTree.modulesByFile = depTree.modules;
@@ -55,6 +66,7 @@ module.exports = function buildDeps(context, mainModule, options, callback) {
5566
delete depTree.nextModuleId;
5667
delete depTree.nextChunkId;
5768
// return
69+
options.events.emit("task-end");
5870
callback(null, depTree);
5971
}
6072
}
@@ -127,7 +139,13 @@ function execLoaders(request, loaders, filenames, contents, options, callback) {
127139

128140
}
129141

130-
function addModule(depTree, context, modu, options, reason, callback) {
142+
function addModule(depTree, context, modu, options, reason, finalCallback) {
143+
options.events.emit("task");
144+
function callback(err, result) {
145+
options.events.emit("task-end");
146+
finalCallback(err, result);
147+
}
148+
131149
resolve(context || path.dirname(modu), modu, options.resolve, resolved);
132150
function resolved(err, filename) {
133151
if(err) {
@@ -147,6 +165,7 @@ function addModule(depTree, context, modu, options, reason, callback) {
147165
var filenameWithLoaders = filename;
148166
var loaders = filename.split(/!/g);
149167
filename = loaders.pop();
168+
options.events.emit("module", modu, filename);
150169
fs.readFile(filename, "utf-8", function(err, content) {
151170
if(err) {
152171
callback(err);
@@ -265,7 +284,13 @@ function addModule(depTree, context, modu, options, reason, callback) {
265284
}
266285
}
267286

268-
function addContextModule(depTree, context, contextModuleName, options, reason, callback) {
287+
function addContextModule(depTree, context, contextModuleName, options, reason, finalCallback) {
288+
options.events.emit("task");
289+
function callback(err, result) {
290+
options.events.emit("task-end");
291+
finalCallback(err, result);
292+
}
293+
269294
resolve.context(context, contextModuleName, options.resolve, resolved);
270295
function resolved(err, dirname) {
271296
if(err) {
@@ -288,6 +313,7 @@ function addContextModule(depTree, context, contextModuleName, options, reason,
288313
var contextModuleNameWithLoaders = dirname;
289314
var loaders = dirname.split(/!/g);
290315
dirname = loaders.pop();
316+
options.events.emit("context", contextModule, dirname);
291317
var prependLoaders = loaders.length === 0 ? "" : loaders.join("!") + "!";
292318
var extensions = (options.resolve && options.resolve.extensions) || [".web.js", ".js"];
293319
function doDir(dirname, moduleName, done) {

lib/webpack.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,51 @@ module.exports = function(context, moduleName, options, callback) {
6969
callback = options;
7070
options = {};
7171
}
72+
if(!options.events) options.events = new (require("events").EventEmitter)();
73+
if(options.watch) {
74+
console.log("start watching...");
75+
var fs = require("fs");
76+
var watchers = [];
77+
var isRunning = true;
78+
var runAgain = false;
79+
function startAgain() {
80+
watchers.forEach(function(watcher) {
81+
watcher.close();
82+
});
83+
watchers.length = 0;
84+
isRunning = true;
85+
setTimeout(function() {
86+
runAgain = false;
87+
webpack(context, moduleName, options, callback);
88+
}, 200);
89+
}
90+
function change() {
91+
if(isRunning)
92+
runAgain = true;
93+
else
94+
startAgain()
95+
}
96+
options.events.on("module", function(module, filename) {
97+
if(!filename) return;
98+
var w = fs.watch(filename, function() {
99+
change();
100+
});
101+
});
102+
options.events.on("context", function(module, dirname) {
103+
if(!dirname) return;
104+
fs.watch(dirname, function() {
105+
change();
106+
});
107+
});
108+
options.events.on("bundle", function(stats) {
109+
isRunning = false;
110+
if(runAgain)
111+
startAgain();
112+
});
113+
}
114+
return webpack(context, moduleName, options, callback);
115+
}
116+
function webpack(context, moduleName, options, finalCallback) {
72117
options.parse = options.parse || {};
73118
options.parse.overwrites = options.parse.overwrites || {};
74119
options.parse.overwrites.process = options.parse.overwrites.process || ("__webpack_process");
@@ -91,6 +136,11 @@ module.exports = function(context, moduleName, options, callback) {
91136
options.resolve.loaders.push({test: /\.jade$/, loader: "jade"});
92137
options.resolve.loaders.push({test: /\.css$/, loader: "style!css"});
93138
options.resolve.loaders.push({test: /\.less$/, loader: "style!less"});
139+
options.events.emit("task");
140+
function callback(err, result) {
141+
options.events.emit("task-end");
142+
finalCallback(err, result);
143+
}
94144
buildDeps(context, moduleName, options, function(err, depTree) {
95145
if(err) {
96146
callback(err);
@@ -199,6 +249,7 @@ module.exports = function(context, moduleName, options, callback) {
199249
});
200250
fileModulesMap[path.basename(filename)] = modulesArray;
201251
});
252+
options.events.emit("start-writing", hash);
202253
// write files
203254
var remFiles = fileWrites.length;
204255
var outDir = options.outputDirectory.replace(HASH_REGEXP, hash);
@@ -265,6 +316,7 @@ module.exports = function(context, moduleName, options, callback) {
265316
buffer.warnings = depTree.warnings;
266317
buffer.errors = depTree.errors;
267318
buffer.fileModules = fileModulesMap;
319+
options.events.emit("bundle", buffer);
268320
callback(null, buffer);
269321
}
270322
} else {
@@ -286,6 +338,7 @@ module.exports = function(context, moduleName, options, callback) {
286338
}
287339
}
288340
});
341+
return options.events;
289342
}
290343

291344
function uglify(input, filename) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webpack",
3-
"version": "0.3.8",
3+
"version": "0.3.9",
44
"author": "Tobias Koppers @sokra",
55
"description": "Packs CommonJs Modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loading of js, json, jade, coffee, css, ... out of the box and more with custom loaders.",
66
"dependencies": {

test/browsertest/build.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,21 @@ var cp = require('child_process');
77
var argv = process.argv;
88
argv.shift();
99
argv.shift();
10-
var extraArgs = argv.join(" ");
10+
var extraArgs = argv;
11+
12+
function bindOutput(p) {
13+
p.stdout.on("data", function(data) {
14+
process.stdout.write(data);
15+
});
16+
p.stderr.on("data", function(data) {
17+
process.stderr.write(data);
18+
});
19+
}
20+
function join(a, b) {
21+
a = a.slice(0);
22+
Array.prototype.push.apply(a, b);
23+
return a;
24+
}
1125

1226
try {
1327
require("vm-browserify");
@@ -21,26 +35,21 @@ try {
2135
}
2236
function compile() {
2337
console.log("compile scripts...");
24-
25-
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --single --libary libary1 node_modules/libary1 js/libary1.js", function (error, stdout, stderr) {
26-
console.log('libary1 stdout:\n' + stdout);
27-
console.log('libary1 stderr:\n ' + stderr);
28-
if (error !== null) {
29-
console.log('libary1 error: ' + error);
30-
}
31-
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --alias vm=vm-browserify --script-src-prefix js/ lib/index js/web.js", function (error, stdout, stderr) {
32-
console.log('web stdout:\n' + stdout);
33-
console.log('web stderr:\n ' + stderr);
34-
if (error !== null) {
35-
console.log('web error: ' + error);
36-
}
37-
});
38-
});
39-
cp.exec("node ../../bin/webpack.js "+extraArgs+" --colors --script-src-prefix js/ --libary libary2 node_modules/libary2 js/libary2.js", function (error, stdout, stderr) {
40-
console.log('libary2 stdout:\n' + stdout);
41-
console.log('libary2 stderr:\n ' + stderr);
42-
if (error !== null) {
43-
console.log('libary2 error: ' + error);
38+
39+
var extraArgsNoWatch = extraArgs.slice(0);
40+
var watchIndex = extraArgsNoWatch.indexOf("--watch");
41+
if(watchIndex != -1) extraArgsNoWatch.splice(watchIndex, 1);
42+
var libary1 = cp.spawn("node", join(["../../bin/webpack.js", "--colors", "--single", "--libary", "libary1",
43+
"node_modules/libary1", "js/libary1.js"], extraArgsNoWatch));
44+
bindOutput(libary1);
45+
libary1.on("exit", function(code) {
46+
if(code === 0) {
47+
var main = cp.spawn("node", join(["../../bin/webpack.js", "--colors", "--alias", "vm=vm-browserify",
48+
"--script-src-prefix", "js/", "lib/index", "js/web.js"], extraArgs));
49+
bindOutput(main);
4450
}
4551
});
52+
var libary2 = cp.spawn("node", join(["../../bin/webpack.js", "--colors", "--libary", "libary2",
53+
"--script-src-prefix", "js/", "node_modules/libary2", "js/libary2.js"], extraArgs));
54+
bindOutput(libary2);
4655
}

0 commit comments

Comments
 (0)