Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly reflect dependency file names in hash #3083

Merged
merged 5 commits into from Aug 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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