Skip to content

Commit

Permalink
Properly reflect dependency file names in hash (#3083)
Browse files Browse the repository at this point in the history
* Create tests

* Include rendered file name without hash in dependency hashes

* Improve and fix documentation

* Update 999-big-list-of-options.md
  • Loading branch information
lukastaegert committed Aug 28, 2019
1 parent e2fa18d commit 8ee03af
Show file tree
Hide file tree
Showing 37 changed files with 146 additions and 84 deletions.
2 changes: 1 addition & 1 deletion docs/999-big-list-of-options.md
Expand Up @@ -397,7 +397,7 @@ Default: `"[name]-[hash].js"`
The pattern to use for naming shared chunks created when code-splitting. Pattern supports the following placeholders:
* `[format]`: The rendering format defined in the output options, e.g. `esm` or `cjs`.
* `[hash]`: A hash based on the content of the chunk and the content of all its dependencies.
* `[name]`: The name of the chunk. This will be `chunk` unless the chunk was created via the [`manualChunks`](guide/en/#manualchunks) options.
* `[name]`: The name of the chunk. This can be explicitly set via the [`manualChunks`](guide/en/#manualchunks) option or when the chunk is created by a plugin via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string). Otherwise it will be derived from the chunk contents.

Forward slashes `/` can be used to place files in sub-directories. See also [`output.assetFileNames`](guide/en/#outputassetfilenames), [`output.entryFileNames`](guide/en/#outputentryfilenames).

Expand Down
28 changes: 21 additions & 7 deletions src/Chunk.ts
Expand Up @@ -250,19 +250,25 @@ export default class Chunk {
}

generateId(
pattern: string,
patternName: string,
addons: Addons,
options: OutputOptions,
existingNames: Record<string, any>
existingNames: Record<string, any>,
includeHash: boolean
): string {
if (this.fileName !== null) {
return this.fileName;
}
const [pattern, patternName] =
this.facadeModule && this.facadeModule.isUserDefinedEntryPoint
? [options.entryFileNames || '[name].js', 'output.entryFileNames']
: [options.chunkFileNames || '[name]-[hash].js', 'output.chunkFileNames'];
return makeUnique(
renderNamePattern(pattern, patternName, {
format: () => (options.format === 'es' ? 'esm' : (options.format as string)),
hash: () => this.computeContentHashWithDependencies(addons, options),
hash: () =>
includeHash
? this.computeContentHashWithDependencies(addons, options, existingNames)
: '[hash]',
name: () => this.getChunkName()
}),
existingNames
Expand Down Expand Up @@ -831,15 +837,23 @@ export default class Chunk {
return hashAugmentation;
}

private computeContentHashWithDependencies(addons: Addons, options: OutputOptions): string {
private computeContentHashWithDependencies(
addons: Addons,
options: OutputOptions,
existingNames: Record<string, any>
): string {
const hash = sha256();
hash.update(
[addons.intro, addons.outro, addons.banner, addons.footer].map(addon => addon || '').join(':')
);
hash.update(options.format);
this.visitDependencies(dep => {
if (dep instanceof ExternalModule) hash.update(':' + dep.renderPath);
else hash.update(dep.getRenderedHash());
if (dep instanceof ExternalModule) {
hash.update(':' + dep.renderPath);
} else {
hash.update(dep.getRenderedHash());
hash.update(dep.generateId(addons, options, existingNames, false));
}
});

return hash.digest('hex').substr(0, 8);
Expand Down
11 changes: 1 addition & 10 deletions src/utils/assignChunkIds.ts
Expand Up @@ -24,21 +24,12 @@ export function assignChunkIds(
// make sure entry chunk names take precedence with regard to deconflicting
const chunksForNaming: Chunk[] = entryChunks.concat(otherChunks);
for (const chunk of chunksForNaming) {
const facadeModule = chunk.facadeModule;
if (outputOptions.file) {
chunk.id = basename(outputOptions.file);
} else if (inputOptions.preserveModules) {
chunk.id = chunk.generateIdPreserveModules(inputBase, bundle);
} else {
let pattern, patternName;
if (facadeModule && facadeModule.isUserDefinedEntryPoint) {
pattern = outputOptions.entryFileNames || '[name].js';
patternName = 'output.entryFileNames';
} else {
pattern = outputOptions.chunkFileNames || '[name]-[hash].js';
patternName = 'output.chunkFileNames';
}
chunk.id = chunk.generateId(pattern, patternName, addons, outputOptions, bundle);
chunk.id = chunk.generateId(addons, outputOptions, bundle, true);
}
bundle[chunk.id] = FILE_PLACEHOLDER;
}
Expand Down

This file was deleted.

@@ -0,0 +1,5 @@
define(['./chunk-main2-6a714ad3-amd'], function (main2) { 'use strict';

main2.log(main2.dep);

});
@@ -0,0 +1,7 @@
define(['./chunk-main2-6a714ad3-amd'], function (main2) { 'use strict';



return main2.log;

});

This file was deleted.

@@ -0,0 +1,5 @@
'use strict';

var main2 = require('./chunk-main2-397efa8f-cjs.js');

main2.log(main2.dep);

This file was deleted.

This file was deleted.

@@ -0,0 +1,7 @@
'use strict';

var main2 = require('./chunk-main2-397efa8f-cjs.js');



module.exports = main2.log;

This file was deleted.

@@ -0,0 +1,3 @@
import { l as log, d as dep } from './chunk-main2-5251e7d2-esm.js';

log(dep);
@@ -0,0 +1 @@
export { l as default } from './chunk-main2-5251e7d2-esm.js';

This file was deleted.

@@ -1,4 +1,4 @@
System.register(['./chunk-main2-63744fb4-system.js'], function () {
System.register(['./chunk-main2-97f5caac-system.js'], function () {
'use strict';
var log, dep;
return {
Expand Down
@@ -1,4 +1,4 @@
System.register(['./chunk-main2-63744fb4-system.js'], function (exports) {
System.register(['./chunk-main2-97f5caac-system.js'], function (exports) {
'use strict';
return {
setters: [function (module) {
Expand Down
Expand Up @@ -17,13 +17,13 @@ module.exports = {
assert.equal(
code,
'\n' +
`${color}//→ entry1-d8c4343d.js:${standard}\n` +
`${color}//→ entry1-b70571c1.js:${standard}\n` +
"console.log('main1');\n" +
'\n' +
`${color}//→ Entry 2-99f48ca0.js:${standard}\n` +
`${color}//→ Entry 2-cc781491.js:${standard}\n` +
"console.log('main2');\n" +
'\n' +
`${color}//→ main3-a6240449.js:${standard}\n` +
`${color}//→ main3-5e259623.js:${standard}\n` +
"console.log('main3');\n"
);
}
Expand Down
6 changes: 3 additions & 3 deletions test/cli/samples/code-splitting-named-inputs/_config.js
Expand Up @@ -17,13 +17,13 @@ module.exports = {
assert.equal(
code,
'\n' +
`${color}//→ entry1-d8c4343d.js:${standard}\n` +
`${color}//→ entry1-b70571c1.js:${standard}\n` +
"console.log('main1');\n" +
'\n' +
`${color}//→ Entry 2-99f48ca0.js:${standard}\n` +
`${color}//→ Entry 2-cc781491.js:${standard}\n` +
"console.log('main2');\n" +
'\n' +
`${color}//→ main3-a6240449.js:${standard}\n` +
`${color}//→ main3-5e259623.js:${standard}\n` +
"console.log('main3');\n"
);
}
Expand Down
40 changes: 28 additions & 12 deletions test/file-hashes/index.js
@@ -1,7 +1,6 @@
const path = require('path');
const rollup = require('../../dist/rollup');
const { extend, runTestSuiteWithSamples } = require('../utils.js');
const assert = require('assert');

runTestSuiteWithSamples('file hashes', path.resolve(__dirname, 'samples'), (dir, config) => {
(config.skip ? describe.skip : config.solo ? describe.only : describe)(
Expand All @@ -24,24 +23,41 @@ runTestSuiteWithSamples('file hashes', path.resolve(__dirname, 'samples'), (dir,
)
).then(([generated1, generated2]) => {
const fileContentsByHash = new Map();
addAndCheckFileContentsByHash(fileContentsByHash, generated1);
addAndCheckFileContentsByHash(fileContentsByHash, generated2);
addFileContentsByFileName(fileContentsByHash, generated1);
addFileContentsByFileName(fileContentsByHash, generated2);
if (config.show) {
console.log(fileContentsByHash);
}
for (const contents of fileContentsByHash.values()) {
if (contents.size > 1) {
throw new Error(
`Two chunks contained different code even though the hashes were the same: ${Array.from(
contents
)
.map(JSON.stringify)
.join(' != ')}`
);
}
}
});
});
}
);
});

function addAndCheckFileContentsByHash(fileContentsByHash, generated) {
function addFileContentsByFileName(fileContentsByFileName, generated) {
for (const chunk of generated.output) {
const hash = chunk.fileName;
if (fileContentsByHash.has(hash)) {
assert.equal(
fileContentsByHash.get(hash),
chunk.code,
'Two chunks contained different code even though the hashes were the same.'
);
const fileName = chunk.fileName;
if (fileContentsByFileName.has(fileName)) {
fileContentsByFileName.get(fileName).add(chunk.code);
} else {
fileContentsByFileName.set(fileName, new Set([chunk.code]));
}
fileContentsByHash.set(hash, chunk.code);
}
}

// assert.equal(
// fileContentsByHash.get(hash),
// chunk.code,
// 'Two chunks contained different code even though the hashes were the same.'
// );
21 changes: 21 additions & 0 deletions test/file-hashes/samples/chunk-name/_config.js
@@ -0,0 +1,21 @@
module.exports = {
description: 'creates different hashes if the name pattern differs',
options1: {
input: {
main: 'main',
foo: 'main2'
},
output: {
entryFileNames: '[name]-[hash].js'
}
},
options2: {
input: {
main: 'main',
bar: 'main2'
},
output: {
entryFileNames: '[name]-[hash].js'
}
}
};
2 changes: 2 additions & 0 deletions test/file-hashes/samples/chunk-name/main.js
@@ -0,0 +1,2 @@
import './main2';
console.log('main');
1 change: 1 addition & 0 deletions test/file-hashes/samples/chunk-name/main2.js
@@ -0,0 +1 @@
console.log('main2');
15 changes: 15 additions & 0 deletions test/file-hashes/samples/name-pattern/_config.js
@@ -0,0 +1,15 @@
module.exports = {
description: 'creates different hashes if the name pattern differs',
options1: {
input: 'main',
output: {
chunkFileNames: '[hash]-[name]'
}
},
options2: {
input: 'main',
output: {
chunkFileNames: '[name]-[hash]'
}
}
};
1 change: 1 addition & 0 deletions test/file-hashes/samples/name-pattern/dep.js
@@ -0,0 +1 @@
export const value = 42;
1 change: 1 addition & 0 deletions test/file-hashes/samples/name-pattern/main.js
@@ -0,0 +1 @@
import('./dep').then(({ value }) => console.log(value));
24 changes: 12 additions & 12 deletions test/hooks/index.js
Expand Up @@ -268,9 +268,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);

return rollup.rollup({
Expand All @@ -293,9 +293,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);

return rollup.rollup({
Expand All @@ -315,9 +315,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);
});
});
Expand Down Expand Up @@ -1242,9 +1242,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);

return rollup.rollup({
Expand All @@ -1267,9 +1267,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);

return rollup.rollup({
Expand All @@ -1289,9 +1289,9 @@ describe('hooks', () => {
.then(({ output }) => {
assert.equal(
output[0].code,
`var input = new URL('chunk-01406d83.js', import.meta.url).href;\n\nexport default input;\n`
`var input = new URL('chunk-928cb70b.js', import.meta.url).href;\n\nexport default input;\n`
);
assert.equal(output[1].fileName, 'chunk-01406d83.js');
assert.equal(output[1].fileName, 'chunk-928cb70b.js');
assert.equal(output[1].code, `console.log('chunk');\n`);
});
});
Expand Down

0 comments on commit 8ee03af

Please sign in to comment.