mirror of https://github.com/webpack/webpack.git
add [hash] function
This commit is contained in:
parent
686756ca89
commit
c44e5f8dc4
14
README.md
14
README.md
|
@ -401,6 +401,13 @@ free module variables which are replaced with a module. ex. `{ "$": "jquery" }`
|
||||||
`source` if `options.output` is not set
|
`source` if `options.output` is not set
|
||||||
else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/code-splitting)
|
else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/code-splitting)
|
||||||
|
|
||||||
|
## Bonus featues
|
||||||
|
|
||||||
|
### File hash
|
||||||
|
|
||||||
|
You can use `[hash]` in `scriptSrcPrefix`, `output`, `outputDirectory` and `outputPostfix`.
|
||||||
|
`webpack` will replace it with a hash of your files, when writing.
|
||||||
|
|
||||||
## Comparison
|
## Comparison
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -639,7 +646,7 @@ else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/c
|
||||||
require JSON
|
require JSON
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
yes <em>NEW</em>
|
yes
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
no
|
no
|
||||||
|
@ -669,7 +676,7 @@ else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/c
|
||||||
loaders
|
loaders
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
yes <em>NEW</em>
|
yes
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
no
|
no
|
||||||
|
@ -684,7 +691,7 @@ else `stats` as json see [example](/sokra/modules-webpack/tree/master/examples/c
|
||||||
compile coffee script
|
compile coffee script
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
yes <em>NEW</em>
|
yes
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
no
|
no
|
||||||
|
@ -793,7 +800,6 @@ You are also welcome to correct any spelling mistakes or any language issues, be
|
||||||
## Future plans
|
## Future plans
|
||||||
|
|
||||||
* watch mode
|
* watch mode
|
||||||
* append hash of file to filename, for better caching
|
|
||||||
* more polyfills for node.js buildin modules, but optional
|
* more polyfills for node.js buildin modules, but optional
|
||||||
* require from protocol `require("http://...")`
|
* require from protocol `require("http://...")`
|
||||||
|
|
||||||
|
|
|
@ -125,9 +125,6 @@ if(argv.single) {
|
||||||
if(!options.outputDirectory) options.outputDirectory = path.dirname(output);
|
if(!options.outputDirectory) options.outputDirectory = path.dirname(output);
|
||||||
if(!options.output) options.output = path.basename(output);
|
if(!options.output) options.output = path.basename(output);
|
||||||
if(!options.outputPostfix) options.outputPostfix = "." + path.basename(output);
|
if(!options.outputPostfix) options.outputPostfix = "." + path.basename(output);
|
||||||
var outExists = path.existsSync(options.outputDirectory);
|
|
||||||
if(!outExists)
|
|
||||||
fs.mkdirSync(options.outputDirectory);
|
|
||||||
webpack(input, options, function(err, stats) {
|
webpack(input, options, function(err, stats) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
@ -139,15 +136,16 @@ if(argv.single) {
|
||||||
function c(str) {
|
function c(str) {
|
||||||
return argv.colors ? str : "";
|
return argv.colors ? str : "";
|
||||||
}
|
}
|
||||||
|
console.log("Hash: "+c("\033[1m") + stats.hash + c("\033[22m"));
|
||||||
console.log("Chunks: "+c("\033[1m") + stats.chunkCount + c("\033[22m"));
|
console.log("Chunks: "+c("\033[1m") + stats.chunkCount + c("\033[22m"));
|
||||||
console.log("Modules: "+c("\033[1m") + stats.modulesCount + c("\033[22m"));
|
console.log("Modules: "+c("\033[1m") + stats.modulesCount + c("\033[22m"));
|
||||||
console.log("Modules including duplicates: "+c("\033[1m") + stats.modulesIncludingDuplicates + c("\033[22m"));
|
console.log("Modules including duplicates: "+c("\033[1m") + stats.modulesIncludingDuplicates + c("\033[22m"));
|
||||||
console.log("Modules pre chunk: "+c("\033[1m") + stats.modulesPerChunk + c("\033[22m"));
|
console.log("Modules pre chunk: "+c("\033[1m") + stats.modulesPerChunk + c("\033[22m"));
|
||||||
console.log("Modules first chunk: "+c("\033[1m") + stats.modulesFirstChunk + c("\033[22m"));
|
console.log("Modules first chunk: "+c("\033[1m") + stats.modulesFirstChunk + c("\033[22m"));
|
||||||
if(stats.fileSizes)
|
if(stats.fileSizes)
|
||||||
for(var file in stats.fileSizes) {
|
Object.keys(stats.fileSizes).reverse().forEach(function(file) {
|
||||||
console.log(c("\033[1m") + sprintf("%" + (5 + options.output.length) + "s", file) + c("\033[22m")+": "+c("\033[1m") + sprintf("%8d", stats.fileSizes[file]) + c("\033[22m") + " characters");
|
console.log(c("\033[1m") + sprintf("%" + (5 + options.output.length) + "s", file) + c("\033[22m")+": "+c("\033[1m") + sprintf("%8d", stats.fileSizes[file]) + c("\033[22m") + " characters");
|
||||||
};
|
});
|
||||||
var cwd = process.cwd();
|
var cwd = process.cwd();
|
||||||
var cwdParent = path.dirname(cwd);
|
var cwdParent = path.dirname(cwd);
|
||||||
var buildins = path.join(__dirname, "..");
|
var buildins = path.join(__dirname, "..");
|
||||||
|
@ -174,7 +172,7 @@ if(argv.single) {
|
||||||
console.log(" <id> <size> <filename>");
|
console.log(" <id> <size> <filename>");
|
||||||
if(argv.verbose)
|
if(argv.verbose)
|
||||||
console.log(" <reason> from <filename>");
|
console.log(" <reason> from <filename>");
|
||||||
for(var file in stats.fileModules) {
|
Object.keys(stats.fileModules).reverse().forEach(function(file) {
|
||||||
console.log(c("\033[1m\033[32m") + file + c("\033[39m\033[22m"));
|
console.log(c("\033[1m\033[32m") + file + c("\033[39m\033[22m"));
|
||||||
var modules = stats.fileModules[file];
|
var modules = stats.fileModules[file];
|
||||||
if(argv["by-size"])
|
if(argv["by-size"])
|
||||||
|
@ -207,7 +205,7 @@ if(argv.single) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
if(stats.warnings) {
|
if(stats.warnings) {
|
||||||
stats.warnings.forEach(function(warning) {
|
stats.warnings.forEach(function(warning) {
|
||||||
|
|
|
@ -141,6 +141,7 @@ module.exports = function() {
|
||||||
## Uncompressed
|
## Uncompressed
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 839970d2bf36067bbcc02e254658eee5
|
||||||
Chunks: 2
|
Chunks: 2
|
||||||
Modules: 6
|
Modules: 6
|
||||||
Modules including duplicates: 6
|
Modules including duplicates: 6
|
||||||
|
@ -170,6 +171,7 @@ output.js
|
||||||
## Minimized (uglify-js, no zip)
|
## Minimized (uglify-js, no zip)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 839970d2bf36067bbcc02e254658eee5
|
||||||
Chunks: 2
|
Chunks: 2
|
||||||
Modules: 6
|
Modules: 6
|
||||||
Modules including duplicates: 6
|
Modules including duplicates: 6
|
||||||
|
|
|
@ -108,6 +108,7 @@ webpackJsonp(1,{3:function(a,b,c){},4:function(a,b,c){}})
|
||||||
## Uncompressed
|
## Uncompressed
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: efedb0352f230f80a7d673655c226d6b
|
||||||
Chunks: 2
|
Chunks: 2
|
||||||
Modules: 5
|
Modules: 5
|
||||||
Modules including duplicates: 5
|
Modules including duplicates: 5
|
||||||
|
@ -135,6 +136,7 @@ output.js
|
||||||
## Minimized (uglify-js, no zip)
|
## Minimized (uglify-js, no zip)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: efedb0352f230f80a7d673655c226d6b
|
||||||
Chunks: 2
|
Chunks: 2
|
||||||
Modules: 5
|
Modules: 5
|
||||||
Modules including duplicates: 5
|
Modules including duplicates: 5
|
||||||
|
|
|
@ -110,6 +110,7 @@ console.timeEnd = function() {
|
||||||
## Uncompressed
|
## Uncompressed
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 473faf0d98f59635bba5232deb86646a
|
||||||
Chunks: 1
|
Chunks: 1
|
||||||
Modules: 4
|
Modules: 4
|
||||||
Modules including duplicates: 4
|
Modules including duplicates: 4
|
||||||
|
@ -134,6 +135,7 @@ output.js
|
||||||
## Minimized (uglify-js, no zip)
|
## Minimized (uglify-js, no zip)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 473faf0d98f59635bba5232deb86646a
|
||||||
Chunks: 1
|
Chunks: 1
|
||||||
Modules: 4
|
Modules: 4
|
||||||
Modules including duplicates: 4
|
Modules including duplicates: 4
|
||||||
|
|
|
@ -130,6 +130,7 @@ Prints in node.js (`node example.js`) and in browser:
|
||||||
## Uncompressed
|
## Uncompressed
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 7286e7c84a0b1d6841f47269de641d85
|
||||||
Chunks: 1
|
Chunks: 1
|
||||||
Modules: 5
|
Modules: 5
|
||||||
Modules including duplicates: 5
|
Modules including duplicates: 5
|
||||||
|
|
|
@ -115,6 +115,7 @@ module.exports = function() {
|
||||||
## Uncompressed
|
## Uncompressed
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 34e41b2aba89897d758177096351e8aa
|
||||||
Chunks: 1
|
Chunks: 1
|
||||||
Modules: 6
|
Modules: 6
|
||||||
Modules including duplicates: 6
|
Modules including duplicates: 6
|
||||||
|
@ -142,6 +143,7 @@ output.js
|
||||||
## Minimized (uglify-js, no zip)
|
## Minimized (uglify-js, no zip)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Hash: 34e41b2aba89897d758177096351e8aa
|
||||||
Chunks: 1
|
Chunks: 1
|
||||||
Modules: 6
|
Modules: 6
|
||||||
Modules including duplicates: 6
|
Modules including duplicates: 6
|
||||||
|
|
131
lib/webpack.js
131
lib/webpack.js
|
@ -7,6 +7,8 @@ var path = require("path");
|
||||||
var writeChunk = require("./writeChunk");
|
var writeChunk = require("./writeChunk");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
|
|
||||||
|
var HASH_REGEXP = /\[hash\]/i;
|
||||||
|
|
||||||
var templateAsync = require("fs").readFileSync(path.join(__dirname, "templateAsync.js"));
|
var templateAsync = require("fs").readFileSync(path.join(__dirname, "templateAsync.js"));
|
||||||
var templateSingle = require("fs").readFileSync(path.join(__dirname, "templateSingle.js"));
|
var templateSingle = require("fs").readFileSync(path.join(__dirname, "templateSingle.js"));
|
||||||
/*
|
/*
|
||||||
|
@ -108,29 +110,55 @@ module.exports = function(context, moduleName, options, callback) {
|
||||||
}
|
}
|
||||||
var fileSizeMap = {};
|
var fileSizeMap = {};
|
||||||
var fileModulesMap = {};
|
var fileModulesMap = {};
|
||||||
|
var fileWrites = [];
|
||||||
var chunksCount = 0;
|
var chunksCount = 0;
|
||||||
for(var chunkId in depTree.chunks) {
|
var chunkIds = Object.keys(depTree.chunks);
|
||||||
|
chunkIds.sort(function(a,b) {
|
||||||
|
return parseInt(b, 10) - parseInt(a, 10);
|
||||||
|
});
|
||||||
|
var hash;
|
||||||
|
try {
|
||||||
|
hash = new (require("crypto").Hash)("md5");
|
||||||
|
hash.update(JSON.stringify(options.libary || ""));
|
||||||
|
hash.update(JSON.stringify(options.outputPostfix));
|
||||||
|
hash.update(JSON.stringify(options.outputJsonpFunction));
|
||||||
|
hash.update(JSON.stringify(options.scriptSrcPrefix));
|
||||||
|
hash.update(templateAsync);
|
||||||
|
hash.update(templateSingle);
|
||||||
|
hash.update("1");
|
||||||
|
} catch(e) {
|
||||||
|
callback(e);
|
||||||
|
return;
|
||||||
|
hash = null;
|
||||||
|
}
|
||||||
|
chunkIds.forEach(function(chunkId) {
|
||||||
var chunk = depTree.chunks[chunkId];
|
var chunk = depTree.chunks[chunkId];
|
||||||
if(chunk.empty) continue;
|
if(chunk.empty) return;
|
||||||
if(chunk.equals !== undefined) continue;
|
if(chunk.equals !== undefined) return;
|
||||||
chunksCount++;
|
chunksCount++;
|
||||||
var filename = path.join(options.outputDirectory,
|
var filename = path.join(options.outputDirectory,
|
||||||
chunk.id === 0 ? options.output : chunk.id + options.outputPostfix);
|
chunk.id === 0 ? options.output : chunk.id + options.outputPostfix);
|
||||||
|
var content = writeChunk(depTree, chunk, options);
|
||||||
|
if(hash) hash.update(content);
|
||||||
buffer = [];
|
buffer = [];
|
||||||
if(chunk.id === 0) {
|
if(chunk.id === 0) {
|
||||||
|
if(hash)
|
||||||
|
hash = hash.digest("hex");
|
||||||
|
else
|
||||||
|
hash = "";
|
||||||
if(options.libary) {
|
if(options.libary) {
|
||||||
buffer.push("/******/var ");
|
buffer.push("/******/var ");
|
||||||
buffer.push(options.libary);
|
buffer.push(options.libary);
|
||||||
buffer.push("=\n");
|
buffer.push("=\n");
|
||||||
}
|
}
|
||||||
if(Object.keys(depTree.chunks).length > 1) {
|
if(chunkIds.length > 1) {
|
||||||
buffer.push(templateAsync);
|
buffer.push(templateAsync);
|
||||||
buffer.push("/******/({a:");
|
buffer.push("/******/({a:");
|
||||||
buffer.push(JSON.stringify(options.outputPostfix));
|
buffer.push(JSON.stringify(options.outputPostfix.replace(HASH_REGEXP, hash)));
|
||||||
buffer.push(",b:");
|
buffer.push(",b:");
|
||||||
buffer.push(JSON.stringify(options.outputJsonpFunction));
|
buffer.push(JSON.stringify(options.outputJsonpFunction));
|
||||||
buffer.push(",c:");
|
buffer.push(",c:");
|
||||||
buffer.push(JSON.stringify(options.scriptSrcPrefix));
|
buffer.push(JSON.stringify(options.scriptSrcPrefix.replace(HASH_REGEXP, hash)));
|
||||||
buffer.push(",\n");
|
buffer.push(",\n");
|
||||||
} else {
|
} else {
|
||||||
buffer.push(templateSingle);
|
buffer.push(templateSingle);
|
||||||
|
@ -143,7 +171,7 @@ module.exports = function(context, moduleName, options, callback) {
|
||||||
buffer.push(chunk.id);
|
buffer.push(chunk.id);
|
||||||
buffer.push(", {\n");
|
buffer.push(", {\n");
|
||||||
}
|
}
|
||||||
buffer.push(writeChunk(depTree, chunk, options));
|
buffer.push(content);
|
||||||
buffer.push("/******/})");
|
buffer.push("/******/})");
|
||||||
buffer = buffer.join("");
|
buffer = buffer.join("");
|
||||||
try {
|
try {
|
||||||
|
@ -152,9 +180,7 @@ module.exports = function(context, moduleName, options, callback) {
|
||||||
callback(e);
|
callback(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fs.writeFile(filename, buffer, "utf-8", function(err) {
|
fileWrites.push([filename, buffer]);
|
||||||
if(err) throw err;
|
|
||||||
});
|
|
||||||
fileSizeMap[path.basename(filename)] = buffer.length;
|
fileSizeMap[path.basename(filename)] = buffer.length;
|
||||||
var modulesArray = [];
|
var modulesArray = [];
|
||||||
for(var moduleId in chunk.modules) {
|
for(var moduleId in chunk.modules) {
|
||||||
|
@ -172,30 +198,75 @@ module.exports = function(context, moduleName, options, callback) {
|
||||||
return a.id - b.id;
|
return a.id - b.id;
|
||||||
});
|
});
|
||||||
fileModulesMap[path.basename(filename)] = modulesArray;
|
fileModulesMap[path.basename(filename)] = modulesArray;
|
||||||
|
});
|
||||||
|
// write files
|
||||||
|
var remFiles = fileWrites.length;
|
||||||
|
var outDir = options.outputDirectory.replace(HASH_REGEXP, hash);
|
||||||
|
function createDir(dir, callback) {
|
||||||
|
path.exists(dir, function(exists) {
|
||||||
|
if(exists)
|
||||||
|
callback();
|
||||||
|
else {
|
||||||
|
fs.mkdir(dir, function(err) {
|
||||||
|
if(err) {
|
||||||
|
var parentDir = path.join(dir, "..");
|
||||||
|
if(parentDir == dir)
|
||||||
|
return callback(err);
|
||||||
|
createDir(parentDir, function(err) {
|
||||||
|
if(err) return callback(err);
|
||||||
|
fs.mkdir(dir, function(err) {
|
||||||
|
if(err) return callback(err);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
buffer = {};
|
createDir(outDir, function(err) {
|
||||||
buffer.chunkCount = chunksCount;
|
if(err) return callback(err);
|
||||||
buffer.modulesCount = Object.keys(depTree.modules).length;
|
writeFiles();
|
||||||
var sum = 0;
|
});
|
||||||
for(var chunkId in depTree.chunks) {
|
function writeFiles() {
|
||||||
for(var moduleId in depTree.chunks[chunkId].modules) {
|
fileWrites.forEach(function(writeAction) {
|
||||||
if(depTree.chunks[chunkId].modules[moduleId] === "include")
|
fs.writeFile(writeAction[0].replace(HASH_REGEXP, hash), writeAction[1], "utf-8", function(err) {
|
||||||
|
if(err) throw err;
|
||||||
|
remFiles--;
|
||||||
|
if(remFiles === 0)
|
||||||
|
writingFinished();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function writingFinished() {
|
||||||
|
// Stats
|
||||||
|
buffer = {};
|
||||||
|
buffer.hash = hash;
|
||||||
|
buffer.chunkCount = chunksCount;
|
||||||
|
buffer.modulesCount = Object.keys(depTree.modules).length;
|
||||||
|
var sum = 0;
|
||||||
|
for(var chunkId in depTree.chunks) {
|
||||||
|
for(var moduleId in depTree.chunks[chunkId].modules) {
|
||||||
|
if(depTree.chunks[chunkId].modules[moduleId] === "include")
|
||||||
|
sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.modulesIncludingDuplicates = sum;
|
||||||
|
buffer.modulesPerChunk = Math.round(sum / chunksCount*10)/10;
|
||||||
|
sum = 0;
|
||||||
|
for(var moduleId in depTree.chunks[0].modules) {
|
||||||
|
if(depTree.chunks[0].modules[moduleId] === "include")
|
||||||
sum++;
|
sum++;
|
||||||
}
|
}
|
||||||
|
buffer.modulesFirstChunk = sum;
|
||||||
|
buffer.fileSizes = fileSizeMap;
|
||||||
|
buffer.warnings = depTree.warnings;
|
||||||
|
buffer.errors = depTree.errors;
|
||||||
|
buffer.fileModules = fileModulesMap;
|
||||||
|
callback(null, buffer);
|
||||||
}
|
}
|
||||||
buffer.modulesIncludingDuplicates = sum;
|
|
||||||
buffer.modulesPerChunk = Math.round(sum / chunksCount*10)/10;
|
|
||||||
sum = 0;
|
|
||||||
for(var moduleId in depTree.chunks[0].modules) {
|
|
||||||
if(depTree.chunks[0].modules[moduleId] === "include")
|
|
||||||
sum++;
|
|
||||||
}
|
|
||||||
buffer.modulesFirstChunk = sum;
|
|
||||||
buffer.fileSizes = fileSizeMap;
|
|
||||||
buffer.warnings = depTree.warnings;
|
|
||||||
buffer.errors = depTree.errors;
|
|
||||||
buffer.fileModules = fileModulesMap;
|
|
||||||
callback(null, buffer);
|
|
||||||
} else {
|
} else {
|
||||||
if(options.libary) {
|
if(options.libary) {
|
||||||
buffer.push("/******/var ");
|
buffer.push("/******/var ");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "webpack",
|
"name": "webpack",
|
||||||
"version": "0.3.7",
|
"version": "0.3.8",
|
||||||
"author": "Tobias Koppers @sokra",
|
"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. Support loading of js, json, jade, coffee, css, ... out of the box and more with custom loaders.",
|
"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.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
Loading…
Reference in New Issue