Skip to content

Commit

Permalink
Provide consistent chunking via a consistent order of entry modules w…
Browse files Browse the repository at this point in the history
…hen emitting chunks (#3055)
  • Loading branch information
lukastaegert committed Aug 13, 2019
1 parent 9cd5668 commit 6b2b650
Show file tree
Hide file tree
Showing 33 changed files with 321 additions and 5 deletions.
22 changes: 17 additions & 5 deletions src/ModuleLoader.ts
Expand Up @@ -90,13 +90,14 @@ function getHasModuleSideEffects(

export class ModuleLoader {
readonly isExternal: IsExternal;
private readonly entryModules: Module[] = [];
private readonly getManualChunk: GetManualChunk;
private readonly graph: Graph;
private readonly hasModuleSideEffects: (id: string, external: boolean) => boolean;
private readonly indexedEntryModules: { index: number; module: Module }[] = [];
private latestLoadModulesPromise: Promise<any> = Promise.resolve();
private readonly manualChunkModules: Record<string, Module[]> = {};
private readonly modulesById: Map<string, Module | ExternalModule>;
private nextEntryModuleIndex = 0;
private readonly pluginDriver: PluginDriver;

constructor(
Expand Down Expand Up @@ -128,6 +129,8 @@ export class ModuleLoader {
manualChunkModulesByAlias: Record<string, Module[]>;
newEntryModules: Module[];
}> {
const firstEntryModuleIndex = this.nextEntryModuleIndex;
this.nextEntryModuleIndex += unresolvedEntryModules.length;
const loadNewEntryModulesPromise = Promise.all(
unresolvedEntryModules.map(({ fileName, id, name }) =>
this.loadEntryModule(id, true).then(module => {
Expand All @@ -145,17 +148,26 @@ export class ModuleLoader {
})
)
).then(entryModules => {
let moduleIndex = firstEntryModuleIndex;
for (const entryModule of entryModules) {
entryModule.isUserDefinedEntryPoint = entryModule.isUserDefinedEntryPoint || isUserDefined;
const existingEntryModule = this.entryModules.find(module => module.id === entryModule.id);
if (!existingEntryModule) {
this.entryModules.push(entryModule);
const existingIndexModule = this.indexedEntryModules.find(
indexedModule => indexedModule.module.id === entryModule.id
);
if (!existingIndexModule) {
this.indexedEntryModules.push({ module: entryModule, index: moduleIndex });
} else {
existingIndexModule.index = Math.min(existingIndexModule.index, moduleIndex);
}
moduleIndex++;
}
this.indexedEntryModules.sort(({ index: indexA }, { index: indexB }) =>
indexA > indexB ? 1 : -1
);
return entryModules;
});
return this.awaitLoadModulesPromise(loadNewEntryModulesPromise).then(newEntryModules => ({
entryModules: this.entryModules,
entryModules: this.indexedEntryModules.map(({ module }) => module),
manualChunkModulesByAlias: this.manualChunkModules,
newEntryModules
}));
Expand Down
37 changes: 37 additions & 0 deletions test/chunking-form/samples/emit-file/emit-chunk-order1/_config.js
@@ -0,0 +1,37 @@
const assert = require('assert');

module.exports = {
description:
'creates a consistent chunking order (needs to be consistent with the other test of this kind)',
options: {
input: 'main',
plugins: {
resolveId(id) {
if (id === 'emitted') {
return id;
}
},
load(id) {
if (id === 'emitted') {
return `import value from './dep.js';
export const id = 'emitted';
console.log(id, value);
`;
}
},
buildStart() {
this.emitFile({
type: 'chunk',
id: 'emitted'
});
},
generateBundle(options, bundle) {
assert.deepStrictEqual(Object.keys(bundle).map(key => bundle[key].name), [
'main',
'dep',
'emitted'
]);
}
}
}
};
@@ -0,0 +1,7 @@
define(['exports'], function (exports) { 'use strict';

var value = 42;

exports.value = value;

});
@@ -0,0 +1,10 @@
define(['exports', './generated-dep'], function (exports, dep) { 'use strict';

const id = 'emitted';
console.log(id, dep.value);

exports.id = id;

Object.defineProperty(exports, '__esModule', { value: true });

});
@@ -0,0 +1,7 @@
define(['./generated-dep', './generated-emitted'], function (dep, emitted) { 'use strict';

console.log(emitted.id);

console.log('main', dep.value);

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

var value = 42;

exports.value = value;
@@ -0,0 +1,10 @@
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var dep = require('./generated-dep.js');

const id = 'emitted';
console.log(id, dep.value);

exports.id = id;
@@ -0,0 +1,8 @@
'use strict';

var dep = require('./generated-dep.js');
var emitted = require('./generated-emitted.js');

console.log(emitted.id);

console.log('main', dep.value);
@@ -0,0 +1,3 @@
var value = 42;

export { value as v };
@@ -0,0 +1,6 @@
import { v as value } from './generated-dep.js';

const id = 'emitted';
console.log(id, value);

export { id };
@@ -0,0 +1,6 @@
import { v as value } from './generated-dep.js';
import { id } from './generated-emitted.js';

console.log(id);

console.log('main', value);
@@ -0,0 +1,10 @@
System.register([], function (exports) {
'use strict';
return {
execute: function () {

var value = exports('v', 42);

}
};
});
@@ -0,0 +1,15 @@
System.register(['./generated-dep.js'], function (exports) {
'use strict';
var value;
return {
setters: [function (module) {
value = module.v;
}],
execute: function () {

const id = exports('id', 'emitted');
console.log(id, value);

}
};
});
@@ -0,0 +1,18 @@
System.register(['./generated-dep.js', './generated-emitted.js'], function () {
'use strict';
var value, id;
return {
setters: [function (module) {
value = module.v;
}, function (module) {
id = module.id;
}],
execute: function () {

console.log(id);

console.log('main', value);

}
};
});
@@ -0,0 +1 @@
export default 42;
@@ -0,0 +1,3 @@
import { id } from 'emitted';

console.log(id);
@@ -0,0 +1,3 @@
import value from './dep.js';
import './dep2.js';
console.log('main', value);
43 changes: 43 additions & 0 deletions test/chunking-form/samples/emit-file/emit-chunk-order2/_config.js
@@ -0,0 +1,43 @@
const assert = require('assert');

module.exports = {
description:
'creates a consistent chunking order (needs to be consistent with the other test of this kind)',
options: {
input: 'main',
plugins: {
resolveId(id) {
if (id === 'emitted') {
return id;
}
},
load(id) {
if (id === 'emitted') {
return new Promise(resolve =>
setTimeout(
() =>
resolve(`import value from './dep.js';
export const id = 'emitted';
console.log(id, value);
`),
200
)
);
}
},
buildStart() {
this.emitFile({
type: 'chunk',
id: 'emitted'
});
},
generateBundle(options, bundle) {
assert.deepStrictEqual(Object.keys(bundle).map(key => bundle[key].name), [
'main',
'dep',
'emitted'
]);
}
}
}
};
@@ -0,0 +1,7 @@
define(['exports'], function (exports) { 'use strict';

var value = 42;

exports.value = value;

});
@@ -0,0 +1,10 @@
define(['exports', './generated-dep'], function (exports, dep) { 'use strict';

const id = 'emitted';
console.log(id, dep.value);

exports.id = id;

Object.defineProperty(exports, '__esModule', { value: true });

});
@@ -0,0 +1,7 @@
define(['./generated-dep', './generated-emitted'], function (dep, emitted) { 'use strict';

console.log(emitted.id);

console.log('main', dep.value);

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

var value = 42;

exports.value = value;
@@ -0,0 +1,10 @@
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var dep = require('./generated-dep.js');

const id = 'emitted';
console.log(id, dep.value);

exports.id = id;
@@ -0,0 +1,8 @@
'use strict';

var dep = require('./generated-dep.js');
var emitted = require('./generated-emitted.js');

console.log(emitted.id);

console.log('main', dep.value);
@@ -0,0 +1,3 @@
var value = 42;

export { value as v };
@@ -0,0 +1,6 @@
import { v as value } from './generated-dep.js';

const id = 'emitted';
console.log(id, value);

export { id };
@@ -0,0 +1,6 @@
import { v as value } from './generated-dep.js';
import { id } from './generated-emitted.js';

console.log(id);

console.log('main', value);
@@ -0,0 +1,10 @@
System.register([], function (exports) {
'use strict';
return {
execute: function () {

var value = exports('v', 42);

}
};
});
@@ -0,0 +1,15 @@
System.register(['./generated-dep.js'], function (exports) {
'use strict';
var value;
return {
setters: [function (module) {
value = module.v;
}],
execute: function () {

const id = exports('id', 'emitted');
console.log(id, value);

}
};
});
@@ -0,0 +1,18 @@
System.register(['./generated-dep.js', './generated-emitted.js'], function () {
'use strict';
var value, id;
return {
setters: [function (module) {
value = module.v;
}, function (module) {
id = module.id;
}],
execute: function () {

console.log(id);

console.log('main', value);

}
};
});
@@ -0,0 +1 @@
export default 42;
@@ -0,0 +1,3 @@
import { id } from 'emitted';

console.log(id);
@@ -0,0 +1,3 @@
import value from './dep.js';
import './dep2.js';
console.log('main', value);

0 comments on commit 6b2b650

Please sign in to comment.