Skip to content

Commit

Permalink
A chunk may only ever be facade for a single module to simplify the l…
Browse files Browse the repository at this point in the history
…ogic

Also delete tests that have been skipped for years. Let's rather make a fresh
start should the problem still persists and someone care to address it.
  • Loading branch information
lukastaegert committed Dec 1, 2018
1 parent af1c537 commit 4dacac6
Show file tree
Hide file tree
Showing 33 changed files with 83 additions and 254 deletions.
56 changes: 22 additions & 34 deletions src/Chunk.ts
Expand Up @@ -127,9 +127,8 @@ export default class Chunk {
private exportNames: { [name: string]: Variable } = Object.create(null);

private dependencies: (ExternalModule | Chunk)[] = undefined;
// an entry module chunk is a chunk that exactly exports the exports of
// an input entry point module
entryModules: Set<Module> = new Set();
entryModules: Module[] = [];
facadeModule: Module | null = null;
isEmpty: boolean;
isManualChunk: boolean = false;

Expand Down Expand Up @@ -159,14 +158,16 @@ export default class Chunk {
}
module.chunk = this;
if (module.isEntryPoint || (module.isDynamicEntryPoint && !inlineDynamicImports)) {
this.entryModules.add(module);
this.entryModules.push(module);
}
}

if (this.entryModules.size > 0) {
const entryModules = Array.from(this.entryModules);
if (this.entryModules.length > 0) {
this.variableName = makeLegal(
basename(entryModules.map(module => module.chunkAlias).find(Boolean) || entryModules[0].id)
basename(
this.entryModules.map(module => module.chunkAlias).find(Boolean) ||
this.entryModules[0].id
)
);
} else this.variableName = '__chunk_' + ++graph.curChunkIndex;
}
Expand All @@ -193,7 +194,7 @@ export default class Chunk {

turnIntoFacade(facadedModule: Module) {
this.dependencies = [facadedModule.chunk];
this.entryModules.add(facadedModule);
this.facadeModule = facadedModule;
facadedModule.facadeChunk = this;
for (const exportName of facadedModule.getAllExports()) {
const tracedVariable = facadedModule.traceExport(exportName);
Expand Down Expand Up @@ -244,42 +245,29 @@ export default class Chunk {
}
}

// TODO Lukas dynamic imports -> always named export mode!
// TODO Lukas multiple entry points -> always generate facade for more than one
// TODO Lukas handle circularly connected entries
generateEntryExportsOrMarkAsTainted() {
const exportVariableMaps = Array.from(this.entryModules).map(module => ({
const exportVariableMaps = this.entryModules.map(module => ({
module,
map: this.getExportVariableMapForModule(module)
}));
const variableByExportName: Map<string, Variable> = new Map();
for (const { map } of exportVariableMaps) {
for (const exposedVariable of Array.from(map.keys())) {
this.exports.set(exposedVariable, map.get(exposedVariable).module);
for (const exportName of map.get(exposedVariable).exportNames) {
variableByExportName.set(exportName, exposedVariable);
}
}
}
checkNextEntryModule: for (const { map, module } of exportVariableMaps) {
for (const exposedVariable of Array.from(this.exports.keys())) {
if (
!map.has(exposedVariable) ||
map
.get(exposedVariable)
.exportNames.some(
exportName => variableByExportName.get(exportName) !== exposedVariable
)
) {
this.entryModules.delete(module);
if (!map.has(exposedVariable)) {
continue checkNextEntryModule;
}
}
this.facadeModule = module;
for (const [variable, { exportNames }] of Array.from(map)) {
for (const exportName of exportNames) {
this.exportNames[exportName] = variable;
}
}
return;
}
}

Expand Down Expand Up @@ -333,7 +321,9 @@ export default class Chunk {
this.traceAndInitializeImport(importName, traced.variable.module);
} else {
const externalVariable = traced.variable.module.traceExport(importName);
if (externalVariable.included) this.imports.set(original, traced.variable.module);
if (externalVariable.included) {
this.imports.set(original, traced.variable.module);
}
}
}
}
Expand Down Expand Up @@ -401,7 +391,7 @@ export default class Chunk {
}

generateInternalExports(options: OutputOptions) {
if (this.entryModules.size > 0) return;
if (this.facadeModule !== null) return;
const mangle = options.format === 'system' || options.format === 'es' || options.compact;
let i = 0,
safeExportName: string;
Expand Down Expand Up @@ -818,7 +808,7 @@ export default class Chunk {
};

// if an entry point facade or dynamic entry point, inline the execution list to avoid loading latency
if (this.entryModules.size > 0) {
if (this.facadeModule !== null) {
for (const dep of this.dependencies) {
if (dep instanceof Chunk) this.inlineChunkDependencies(dep, true);
}
Expand Down Expand Up @@ -919,7 +909,7 @@ export default class Chunk {
* A new facade will be added to chunkList if tainting exports of either as an entry point
*/
merge(chunk: Chunk, chunkList: Chunk[], options: OutputOptions, inputBase: string) {
if (this.entryModules.size > 0 || chunk.entryModules.size > 0)
if (this.facadeModule !== null || chunk.facadeModule !== null)
throw new Error('Internal error: Code splitting chunk merges not supported for facades');

for (const module of chunk.orderedModules) {
Expand Down Expand Up @@ -1061,10 +1051,8 @@ export default class Chunk {
}

private computeChunkName(): string {
if (this.entryModules.size > 0) {
for (const entryModule of Array.from(this.entryModules)) {
if (entryModule.chunkAlias) return entryModule.chunkAlias;
}
if (this.facadeModule !== null && this.facadeModule.chunkAlias) {
return this.facadeModule.chunkAlias;
}
for (const module of this.orderedModules) {
if (module.chunkAlias) return module.chunkAlias;
Expand Down Expand Up @@ -1136,7 +1124,7 @@ export default class Chunk {
dependencies: this.renderedDeclarations.dependencies,
exports: this.renderedDeclarations.exports,
graph: this.graph,
isEntryModuleFacade: !!Array.from(this.entryModules).find(module => module.isEntryPoint),
isEntryModuleFacade: this.facadeModule !== null && this.facadeModule.isEntryPoint,
usesTopLevelAwait
},
options
Expand Down
32 changes: 12 additions & 20 deletions src/Graph.ts
Expand Up @@ -369,7 +369,7 @@ export default class Graph {

this.link();

const { orderedModules, cyclePaths, dynamicImports } = analyseModuleExecution(entryModules);
const { orderedModules, cyclePaths } = analyseModuleExecution(entryModules);
for (const cyclePath of cyclePaths) {
this.warn({
code: 'CIRCULAR_DEPENDENCY',
Expand Down Expand Up @@ -419,7 +419,9 @@ export default class Graph {
if (preserveModules) {
for (const module of orderedModules) {
const chunk = new Chunk(this, [module], inlineDynamicImports);
if (module.isEntryPoint || !chunk.isEmpty) chunk.entryModules.add(module);
if (module.isEntryPoint || !chunk.isEmpty) {
chunk.entryModules = [module];
}
chunks.push(chunk);
}
} else {
Expand Down Expand Up @@ -450,35 +452,25 @@ export default class Graph {

// filter out empty dependencies
chunks = chunks.filter(
chunk => !chunk.isEmpty || chunk.entryModules.size > 0 || chunk.isManualChunk
chunk => !chunk.isEmpty || chunk.entryModules.length > 0 || chunk.isManualChunk
);

// then go over and ensure all entry chunks export their variables
for (const chunk of chunks) {
if (preserveModules || chunk.entryModules.size > 0) {
if (preserveModules || chunk.entryModules.length > 0) {
chunk.generateEntryExportsOrMarkAsTainted();
}
}

// create entry point facades for entry module chunks that have tainted exports
const facades = [];
if (!preserveModules) {
for (const entryModule of entryModules) {
if (!entryModule.chunk.entryModules.has(entryModule)) {
const entryPointFacade = new Chunk(this, [], inlineDynamicImports);
entryPointFacade.turnIntoFacade(entryModule);
chunks.push(entryPointFacade);
}
}
if (!inlineDynamicImports) {
for (const entryModule of dynamicImports) {
if (
entryModule.isDynamicEntryPoint &&
!entryModule.chunk.entryModules.has(entryModule) &&
!entryModule.facadeChunk
) {
for (const chunk of chunks) {
for (const entryModule of chunk.entryModules) {
if (chunk.facadeModule !== entryModule) {
const entryPointFacade = new Chunk(this, [], inlineDynamicImports);
entryPointFacade.turnIntoFacade(entryModule);
chunks.push(entryPointFacade);
facades.push(entryPointFacade);
}
}
}
Expand All @@ -487,7 +479,7 @@ export default class Graph {
timeEnd('generate chunks', 2);

this.finished = true;
return chunks;
return chunks.concat(facades);
}
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/chunk-optimization.ts
Expand Up @@ -36,10 +36,10 @@ export function optimizeChunks(
nextChunk = execGroup[1];

const isMergeCandidate = (chunk: Chunk) => {
if (chunk.entryModules.size > 0 || chunk.isManualChunk) {
if (chunk.facadeModule !== null || chunk.isManualChunk) {
return false;
}
if (!nextChunk || nextChunk.entryModules.size > 0) {
if (!nextChunk || nextChunk.facadeModule !== null) {
return false;
}
if (chunk.getRenderedSourceLength() > CHUNK_GROUPING_SIZE) {
Expand Down
13 changes: 6 additions & 7 deletions src/rollup/index.ts
Expand Up @@ -68,7 +68,7 @@ function checkOutputOptions(options: OutputOptions) {
function getAbsoluteEntryModulePaths(chunks: Chunk[]): string[] {
const absoluteEntryModulePaths: string[] = [];
for (const chunk of chunks) {
for (const entryModule of Array.from(chunk.entryModules)) {
for (const entryModule of chunk.entryModules) {
if (isAbsolute(entryModule.id)) {
absoluteEntryModulePaths.push(entryModule.id);
}
Expand Down Expand Up @@ -282,7 +282,7 @@ export default function rollup(
for (const chunk of chunks) {
if (!inputOptions.experimentalPreserveModules)
chunk.generateInternalExports(outputOptions);
if (Array.from(chunk.entryModules).find(module => module.isEntryPoint))
if (chunk.facadeModule && chunk.facadeModule.isEntryPoint)
chunk.exportMode = getExportMode(chunk, outputOptions);
}
for (const chunk of chunks) {
Expand All @@ -298,17 +298,16 @@ export default function rollup(
// assign to outputBundle
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
const facadeModule = chunk.facadeModule;

outputBundle[chunk.id] = {
code: undefined,
entryModuleIds: Array.from(chunk.entryModules).map(module => module.id),
facadeModuleId: facadeModule && facadeModule.id,
exports: chunk.getExportNames(),
fileName: chunk.id,
imports: chunk.getImportIds(),
isDynamicEntry: !!Array.from(chunk.entryModules).find(
module => module.isDynamicEntryPoint
),
isEntry: !!Array.from(chunk.entryModules).find(module => module.isEntryPoint),
isDynamicEntry: facadeModule !== null && facadeModule.isDynamicEntryPoint,
isEntry: facadeModule !== null && facadeModule.isEntryPoint,
map: undefined,
modules: chunk.renderedModules,
get name() {
Expand Down
2 changes: 1 addition & 1 deletion src/rollup/types.d.ts
Expand Up @@ -363,8 +363,8 @@ export interface RenderedModule {
}

export interface RenderedChunk {
entryModuleIds: string[];
exports: string[];
facadeModuleId: string | null;
fileName: string;
imports: string[];
isDynamicEntry: boolean;
Expand Down
9 changes: 4 additions & 5 deletions src/utils/assignChunkIds.ts
Expand Up @@ -14,10 +14,9 @@ export function assignChunkIds(
const usedIds: Record<string, true> = {};
const [entryChunks, otherChunks] = chunks.reduce(
([entryChunks, otherChunks], chunk) => {
(Array.from(chunk.entryModules).find(module => module.isEntryPoint)
? entryChunks
: otherChunks
).push(chunk);
(chunk.facadeModule && chunk.facadeModule.isEntryPoint ? entryChunks : otherChunks).push(
chunk
);
return [entryChunks, otherChunks];
},
[[], []]
Expand All @@ -37,7 +36,7 @@ export function assignChunkIds(
chunk.generateIdPreserveModules(inputBase, usedIds);
} else {
let pattern, patternName;
if (Array.from(chunk.entryModules).find(module => module.isEntryPoint)) {
if (chunk.facadeModule && chunk.facadeModule.isEntryPoint) {
pattern = outputOptions.entryFileNames || '[name].js';
patternName = 'output.entryFileNames';
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/executionOrder.ts
Expand Up @@ -75,7 +75,7 @@ export function analyseModuleExecution(entryModules: Module[]) {
}
}

return { orderedModules, dynamicImports, cyclePaths };
return { orderedModules, cyclePaths };
}

function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) {
Expand Down
3 changes: 2 additions & 1 deletion src/utils/getExportMode.ts
Expand Up @@ -32,7 +32,8 @@ export default function getExportMode(
exportMode = 'default';
} else {
if (
Array.from(chunk.entryModules).find(module => module.isEntryPoint) &&
chunk.facadeModule !== null &&
chunk.facadeModule.isEntryPoint &&
format !== 'es' &&
exportKeys.indexOf('default') !== -1
) {
Expand Down
Expand Up @@ -7,7 +7,7 @@ define(['exports'], function (exports) { 'use strict';

console.log('dynamic1');

exports.DYNAMIC_B = DYNAMIC_A;
exports.DYNAMIC_A = DYNAMIC_B;
exports.DYNAMIC_A = DYNAMIC_A;
exports.DYNAMIC_B = DYNAMIC_B;

});
Expand Up @@ -2,7 +2,7 @@ define(['exports', './generated-dynamic.js'], function (exports, dynamic) { 'use



exports.DYNAMIC_A = dynamic.DYNAMIC_B;
exports.DYNAMIC_B = dynamic.DYNAMIC_A;
exports.DYNAMIC_A = dynamic.DYNAMIC_B;

});
@@ -1,6 +1,6 @@
define(['require'], function (require) { 'use strict';

new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(result => console.log(result));
new Promise(function (resolve, reject) { require(['./generated-dynamic2.js'], resolve, reject) }).then(result => console.log(result));
new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(result => console.log(result));

});
Expand Up @@ -7,5 +7,5 @@ const DYNAMIC_B = 'DYNAMIC_B';

console.log('dynamic1');

exports.DYNAMIC_B = DYNAMIC_A;
exports.DYNAMIC_A = DYNAMIC_B;
exports.DYNAMIC_A = DYNAMIC_A;
exports.DYNAMIC_B = DYNAMIC_B;
Expand Up @@ -4,5 +4,5 @@ var dynamic = require('./generated-dynamic.js');



exports.DYNAMIC_A = dynamic.DYNAMIC_B;
exports.DYNAMIC_B = dynamic.DYNAMIC_A;
exports.DYNAMIC_A = dynamic.DYNAMIC_B;
@@ -1,4 +1,4 @@
'use strict';

Promise.resolve(require('./generated-dynamic.js')).then(result => console.log(result));
Promise.resolve(require('./generated-dynamic2.js')).then(result => console.log(result));
Promise.resolve(require('./generated-dynamic.js')).then(result => console.log(result));
Expand Up @@ -5,4 +5,4 @@ const DYNAMIC_B = 'DYNAMIC_B';

console.log('dynamic1');

export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A };
export { DYNAMIC_A, DYNAMIC_B };
@@ -1 +1 @@
export { DYNAMIC_B as DYNAMIC_A, DYNAMIC_A as DYNAMIC_B } from './generated-dynamic.js';
export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A } from './generated-dynamic.js';
@@ -1,2 +1,2 @@
import('./generated-dynamic.js').then(result => console.log(result));
import('./generated-dynamic2.js').then(result => console.log(result));
import('./generated-dynamic.js').then(result => console.log(result));
Expand Up @@ -5,8 +5,8 @@ System.register([], function (exports, module) {

console.log('dynamic2');

const DYNAMIC_A = exports('DYNAMIC_B', 'DYNAMIC_A');
const DYNAMIC_B = exports('DYNAMIC_A', 'DYNAMIC_B');
const DYNAMIC_A = exports('DYNAMIC_A', 'DYNAMIC_A');
const DYNAMIC_B = exports('DYNAMIC_B', 'DYNAMIC_B');

console.log('dynamic1');

Expand Down

0 comments on commit 4dacac6

Please sign in to comment.