Skip to content

Commit

Permalink
Fix code splitting with uglify
Browse files Browse the repository at this point in the history
  • Loading branch information
romainberger committed Apr 26, 2016
1 parent aed31a1 commit 8e8026e
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 39 deletions.
8 changes: 4 additions & 4 deletions lib/loader.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use strict';
"use strict";

module.exports = function () {
this.cacheable && this.cacheable();
if (typeof this._compilation.__webpackMultiOutput === 'undefined') {
throw new Error('"webpack-multi-output" loader is used without the corresponding plugin,\nrefer to https://github.com/dailymotion/webpack-multi-output for the usage example');
if (!this._compilation.__webpackMultiOutput) {
throw new Error("\"webpack-multi-output\" loader is used without the corresponding plugin,\nrefer to https://github.com/dailymotion/webpack-multi-output for the usage example");
}

return 'exports.default = "WebpackMultiOutput-' + this.resourcePath + '-WebpackMultiOutput";';
return "exports.default = \"WebpackMultiOutput-" + this.resourcePath + "-WebpackMultiOutput\";";
};
43 changes: 31 additions & 12 deletions lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ function WebpackMultiOutput() {

this.addedAssets = [];
this.assetsMap = {};
this.chunksMap = {};
this.chunkName = '';
this.chunkHash = '';
this.filePathRe = /WebpackMultiOutput-(.*?)-WebpackMultiOutput/;
this.filePathReG = /WebpackMultiOutput-(.*?)-WebpackMultiOutput/g;
}
Expand All @@ -67,6 +69,7 @@ WebpackMultiOutput.prototype.apply = function (compiler) {

compiler.plugin('compilation', function (compilation) {
compilation.__webpackMultiOutput = true;
_this.needsHash = /\[hash\]/.test(compilation.outputOptions.filename);

if (!_this.options.values.length) {
compilation.errors.push(new Error('[webpack-multi-output] Error: option "values" must be an array of length >= 1'));
Expand All @@ -79,8 +82,6 @@ WebpackMultiOutput.prototype.apply = function (compiler) {
return (0, _async.setImmediate)(fileCallback);
}

_this.needsHash = /\[hash\]/.test(compilation.outputOptions.filename);

var source = compilation.assets[file];

if (!_this.filePathReG.test(source.source())) {
Expand All @@ -97,6 +98,7 @@ WebpackMultiOutput.prototype.apply = function (compiler) {
_this.processSource(value, (0, _lodash2.default)(source), function (result) {
_this.log('Add asset ' + filename);
compilation.assets[filename] = result;
_this.chunksMap[chunk.id] = true;
_this.addedAssets.push({ value: value, filename: filename, name: chunk.name });
if (chunk.name) {
if (_this.needsHash) {
Expand All @@ -117,22 +119,24 @@ WebpackMultiOutput.prototype.apply = function (compiler) {
});

compilation.plugin('optimize-assets', function (assets, callback) {
if (!_this.needsHash) {
return callback();
}

var length = _this.chunkHash.length;

_this.addedAssets.forEach(function (_ref) {
var value = _ref.value;
var filename = _ref.filename;
var name = _ref.name;

var source = compilation.assets[filename];
var source = _this.replaceChunkMap(compilation.assets[filename]);

if (!_this.needsHash) {
compilation.assets[filename] = source;
return;
}

var fileHash = (0, _crypto.createHash)('md5').update(source.source()).digest('hex').substr(0, length);
var newFilename = filename.replace(_this.chunkHash, fileHash);

_this.log('Update hash in filename for ' + filename + ' -> ' + newFilename);
_this.log('Update hash in filename for ' + filename + ' -> ' + newFilename, 'ultra');

if (filename !== newFilename) {
compilation.assets[newFilename] = source;
Expand All @@ -143,6 +147,17 @@ WebpackMultiOutput.prototype.apply = function (compiler) {

callback();
});

compilation.mainTemplate.plugin('jsonp-script', function (_) {
var source = _.split('\n');

var chunkIdModifier = 'var webpackMultiOutputGetChunkId = function(chunkId) {\n var map = {__WEBPACK_MULTI_OUTPUT_CHUNK_MAP__:2};\n\n if (map[chunkId]) {\n return \'__WEBPACK_MULTI_OUTPUT_VALUE__.\' + chunkId;\n }\n else {\n return chunkId;\n }\n };\n ';

source[source.length - 1] = source[source.length - 1].replace('chunkId', 'webpackMultiOutputGetChunkId(chunkId)');
source.splice(source.length - 1, 0, chunkIdModifier);

return source.join('\n');
});
});

compiler.plugin('after-emit', function (compilation, callback) {
Expand Down Expand Up @@ -203,10 +218,9 @@ WebpackMultiOutput.prototype.processSource = function (value, source, callback)
replaces.forEach(function (replace) {
_source = _source.replace('"' + replace.source + '"', replace.replace);
});
// make webpack load [value].xx.bundle.js instead of xx.bundle.js
// does not work with uglify
// does not work for bundle not generated by us
// _source = _source.replace('script.src = __webpack_require__.p', `script.src = __webpack_require__.p + "${value}."`)

_source = _source.replace(/__WEBPACK_MULTI_OUTPUT_VALUE__/g, value);

callback(new _webpackSources.ConcatSource(_source));
});
};
Expand Down Expand Up @@ -245,6 +259,11 @@ WebpackMultiOutput.prototype.uglify = function (source) {
return JSON.stringify(JSON.parse(source));
};

WebpackMultiOutput.prototype.replaceChunkMap = function (source) {
this.log('Replacing chunk map ' + JSON.stringify(this.chunksMap), 'ultra');
return new _webpackSources.ConcatSource(source.source().replace(/\{__WEBPACK_MULTI_OUTPUT_CHUNK_MAP__:2\}/, JSON.stringify(this.chunksMap)));
};

WebpackMultiOutput.prototype.addToAssetsMap = function (value, name, filePath) {
this.assetsMap[value] = _defineProperty({}, name, {
js: filePath
Expand Down
2 changes: 1 addition & 1 deletion src/loader.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = function() {
this.cacheable && this.cacheable()
if (typeof this._compilation.__webpackMultiOutput === 'undefined') {
if (!this._compilation.__webpackMultiOutput) {
throw new Error(`"webpack-multi-output" loader is used without the corresponding plugin,
refer to https://github.com/dailymotion/webpack-multi-output for the usage example`)
}
Expand Down
55 changes: 42 additions & 13 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ export default function WebpackMultiOutput(options: Object = {}): void {

this.addedAssets = []
this.assetsMap = {}
this.chunksMap = {}
this.chunkName = ''
this.chunkHash = ''
this.filePathRe = /WebpackMultiOutput-(.*?)-WebpackMultiOutput/
this.filePathReG = /WebpackMultiOutput-(.*?)-WebpackMultiOutput/g
}
WebpackMultiOutput.prototype.apply = function(compiler: Object): void {
compiler.plugin('compilation', (compilation: Object): void => {
compilation.__webpackMultiOutput = true
this.needsHash = /\[hash\]/.test(compilation.outputOptions.filename)

if (!this.options.values.length) {
compilation.errors.push(new Error(`[webpack-multi-output] Error: option "values" must be an array of length >= 1`))
Expand All @@ -46,8 +49,6 @@ WebpackMultiOutput.prototype.apply = function(compiler: Object): void {
return asyncSetImmediate(fileCallback)
}

this.needsHash = /\[hash\]/.test(compilation.outputOptions.filename)

const source: Object = compilation.assets[file]

if (!this.filePathReG.test(source.source())) {
Expand All @@ -64,6 +65,7 @@ WebpackMultiOutput.prototype.apply = function(compiler: Object): void {
this.processSource(value, clone(source), (result) => {
this.log(`Add asset ${filename}`)
compilation.assets[filename] = result
this.chunksMap[chunk.id] = true
this.addedAssets.push({value, filename, name: chunk.name})
if (chunk.name) {
if (this.needsHash) {
Expand All @@ -84,18 +86,20 @@ WebpackMultiOutput.prototype.apply = function(compiler: Object): void {
})

compilation.plugin('optimize-assets', (assets: Object, callback: Function): void => {
if (!this.needsHash) {
return callback()
}

const length = this.chunkHash.length

this.addedAssets.forEach(({value, filename, name}) => {
const source = compilation.assets[filename]
const source = this.replaceChunkMap(compilation.assets[filename])

if (!this.needsHash) {
compilation.assets[filename] = source
return
}

const fileHash = createHash('md5').update(source.source()).digest('hex').substr(0, length)
const newFilename = filename.replace(this.chunkHash, fileHash)

this.log(`Update hash in filename for ${filename} -> ${newFilename}`)
this.log(`Update hash in filename for ${filename} -> ${newFilename}`, 'ultra')

if (filename !== newFilename) {
compilation.assets[newFilename] = source
Expand All @@ -106,6 +110,27 @@ WebpackMultiOutput.prototype.apply = function(compiler: Object): void {

callback()
})

compilation.mainTemplate.plugin('jsonp-script', (_: string): string => {
const source = _.split('\n')

const chunkIdModifier = `var webpackMultiOutputGetChunkId = function(chunkId) {
var map = {__WEBPACK_MULTI_OUTPUT_CHUNK_MAP__:2};
if (map[chunkId]) {
return '__WEBPACK_MULTI_OUTPUT_VALUE__.' + chunkId;
}
else {
return chunkId;
}
};
`

source[source.length - 1] = source[source.length - 1].replace('chunkId', 'webpackMultiOutputGetChunkId(chunkId)')
source.splice(source.length - 1, 0, chunkIdModifier)

return source.join('\n')
})
})

compiler.plugin('after-emit', (compilation: Object, callback: Function): void => {
Expand Down Expand Up @@ -165,10 +190,9 @@ WebpackMultiOutput.prototype.processSource = function(value: string, source: Obj
replaces.forEach(replace => {
_source = _source.replace(`"${replace.source}"`, replace.replace)
})
// make webpack load [value].xx.bundle.js instead of xx.bundle.js
// does not work with uglify
// does not work for bundle not generated by us
// _source = _source.replace('script.src = __webpack_require__.p', `script.src = __webpack_require__.p + "${value}."`)

_source = _source.replace(/__WEBPACK_MULTI_OUTPUT_VALUE__/g, value)

callback(new ConcatSource(_source))
})
}
Expand Down Expand Up @@ -205,11 +229,16 @@ WebpackMultiOutput.prototype.uglify = function(source: string): string {
return JSON.stringify(JSON.parse(source))
}

WebpackMultiOutput.prototype.replaceChunkMap = function(source: Object): string {
this.log(`Replacing chunk map ${JSON.stringify(this.chunksMap)}`, 'ultra')
return new ConcatSource(source.source().replace(/\{__WEBPACK_MULTI_OUTPUT_CHUNK_MAP__:2\}/, JSON.stringify(this.chunksMap)))
}

WebpackMultiOutput.prototype.addToAssetsMap = function(value: string, name: string, filePath: string): void {
this.assetsMap[value] = {
[name]: {
js: filePath,
}
},
}
}

Expand Down
18 changes: 9 additions & 9 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ describe('Webpack Multi Output', () => {
const assetsPath = path.join(__dirname, 'dist-splitting/assets/assets.json')

before(function(done) {
this.timeout(10000)
this.timeout(20000)
const altConfig = {
...config,
entry: [path.join(__dirname, 'src-splitting/app/index.js')],
Expand All @@ -568,14 +568,14 @@ describe('Webpack Multi Output', () => {
// chunkFilename: '[id].[chunkhash].bundle.js',
},
plugins: [
// new webpack.optimize.UglifyJsPlugin({
// output: {
// comments: false
// },
// compressor: {
// warnings: false
// }
// }),
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false
},
compressor: {
warnings: false
}
}),
new WebpackMultiOutputPlugin({
values: ['fr', 'en'],
debug: true,
Expand Down

0 comments on commit 8e8026e

Please sign in to comment.