Skip to content

Commit

Permalink
Improve circular dependency execution order
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Dec 6, 2020
1 parent 92a2dfa commit e2ee8ae
Show file tree
Hide file tree
Showing 137 changed files with 403 additions and 240 deletions.
7 changes: 2 additions & 5 deletions src/Chunk.ts
Expand Up @@ -36,12 +36,12 @@ import {
errUnexpectedNamespaceReexport
} from './utils/error';
import { escapeId } from './utils/escapeId';
import { sortByExecutionOrder } from './utils/executionOrder';
import { assignExportsToMangledNames, assignExportsToNames } from './utils/exportNames';
import getExportMode from './utils/getExportMode';
import { getId } from './utils/getId';
import getIndentString from './utils/getIndentString';
import { getOrCreate } from './utils/getOrCreate';
import { getStaticDependencies } from './utils/getStaticDependencies';
import { makeLegal } from './utils/identifierHelpers';
import {
defaultInteropHelpersByInteropType,
Expand Down Expand Up @@ -546,8 +546,8 @@ export default class Chunk {
}

link() {
this.dependencies = getStaticDependencies(this, this.orderedModules, this.chunkByModule);
for (const module of this.orderedModules) {
this.addDependenciesToChunk(module.getDependenciesToBeIncluded(), this.dependencies);
this.addDependenciesToChunk(module.dynamicDependencies, this.dynamicDependencies);
this.addDependenciesToChunk(module.implicitlyLoadedBefore, this.implicitlyLoadedBefore);
this.setUpChunkImportsAndExportsForModule(module);
Expand Down Expand Up @@ -585,9 +585,6 @@ export default class Chunk {
if (dep instanceof Chunk) this.inlineChunkDependencies(dep);
}
}
const sortedDependencies = [...this.dependencies];
sortByExecutionOrder(sortedDependencies);
this.dependencies = new Set(sortedDependencies);

this.prepareDynamicImportsAndImportMetas();
this.setIdentifierRenderResolutions(options);
Expand Down
68 changes: 45 additions & 23 deletions src/Module.ts
Expand Up @@ -333,8 +333,9 @@ export default class Module {
getDependenciesToBeIncluded(): Set<Module | ExternalModule> {
if (this.relevantDependencies) return this.relevantDependencies;
const relevantDependencies = new Set<Module | ExternalModule>();
const additionalSideEffectModules = new Set<Module>();
const possibleDependencies = new Set(this.dependencies);
const necessaryDependencies = new Set<Module | ExternalModule>();
const alwaysCheckedDependencies = new Set<Module>();

let dependencyVariables = this.imports;
if (
this.info.isEntry ||
Expand All @@ -354,36 +355,25 @@ export default class Module {
const { modules, original } = variable.getOriginalVariableAndDeclarationModules();
variable = original;
for (const module of modules) {
additionalSideEffectModules.add(module);
possibleDependencies.add(module);
alwaysCheckedDependencies.add(module);
}
}
relevantDependencies.add(variable.module!);
necessaryDependencies.add(variable.module!);
}
if (this.options.treeshake && this.info.hasModuleSideEffects !== 'no-treeshake') {
for (const dependency of possibleDependencies) {
if (
!(
dependency.info.hasModuleSideEffects ||
additionalSideEffectModules.has(dependency as Module)
) ||
relevantDependencies.has(dependency)
) {
continue;
}
if (dependency instanceof ExternalModule || dependency.hasEffects()) {
relevantDependencies.add(dependency);
} else {
for (const transitiveDependency of dependency.dependencies) {
possibleDependencies.add(transitiveDependency);
}
}
}
this.addRelevantSideEffectDependencies(
relevantDependencies,
necessaryDependencies,
alwaysCheckedDependencies
);
} else {
for (const dependency of this.dependencies) {
relevantDependencies.add(dependency);
}
}
for (const dependency of necessaryDependencies) {
relevantDependencies.add(dependency);
}
return (this.relevantDependencies = relevantDependencies);
}

Expand Down Expand Up @@ -960,6 +950,38 @@ export default class Module {
}
}

private addRelevantSideEffectDependencies(
relevantDependencies: Set<Module | ExternalModule>,
necessaryDependencies: Set<Module | ExternalModule>,
alwaysCheckedDependencies: Set<Module | ExternalModule>
) {
const handledDependencies = new Set<Module | ExternalModule>();

function addSideEffectDependencies(possibleDependencies: Set<Module | ExternalModule>) {
for (const dependency of possibleDependencies) {
if (handledDependencies.has(dependency)) {
continue;
}
handledDependencies.add(dependency);
if (necessaryDependencies.has(dependency)) {
relevantDependencies.add(dependency);
continue;
}
if (!(dependency.info.hasModuleSideEffects || alwaysCheckedDependencies.has(dependency))) {
continue;
}
if (dependency instanceof ExternalModule || dependency.hasEffects()) {
relevantDependencies.add(dependency);
continue;
}
addSideEffectDependencies(dependency.dependencies);
}
}

addSideEffectDependencies(this.dependencies);
addSideEffectDependencies(alwaysCheckedDependencies);
}

private includeAndGetAdditionalMergedNamespaces(): Variable[] {
const mergedNamespaces: Variable[] = [];
for (const module of this.exportAllModules) {
Expand Down
52 changes: 52 additions & 0 deletions src/utils/getStaticDependencies.ts
@@ -0,0 +1,52 @@
import Chunk from '../Chunk';
import ExternalModule from '../ExternalModule';
import Module from '../Module';

export function getStaticDependencies(
chunk: Chunk,
orderedModules: Module[],
chunkByModule: Map<Module, Chunk>
): Set<Chunk | ExternalModule> {
const staticDependencyBlocks: (Chunk | ExternalModule)[][] = [];
const handledDependencies = new Set<Module>();
for (let modulePos = orderedModules.length - 1; modulePos >= 0; modulePos--) {
const module = orderedModules[modulePos];
if (!handledDependencies.has(module)) {
const staticDependencies: (Chunk | ExternalModule)[] = [];
addStaticDependencies(module, staticDependencies, handledDependencies, chunk, chunkByModule);
staticDependencyBlocks.unshift(staticDependencies);
}
}
const dependencies = new Set<Chunk | ExternalModule>();
for (const block of staticDependencyBlocks) {
for (const dependency of block) {
dependencies.add(dependency);
}
}
return dependencies;
}

function addStaticDependencies(
module: Module,
staticDependencies: (Chunk | ExternalModule)[],
handledModules: Set<Module>,
chunk: Chunk,
chunkByModule: Map<Module, Chunk>
): void {
const dependencies = module.getDependenciesToBeIncluded();
for (const dependency of dependencies) {
if (dependency instanceof ExternalModule) {
staticDependencies.push(dependency);
continue;
}
const dependencyChunk = chunkByModule.get(dependency)!;
if (dependencyChunk !== chunk) {
staticDependencies.push(dependencyChunk);
continue;
}
if (!handledModules.has(dependency)) {
handledModules.add(dependency);
addStaticDependencies(dependency, staticDependencies, handledModules, chunk, chunkByModule);
}
}
}
@@ -1,4 +1,4 @@
define(['./generated-dep1', './generated-shared2', './generated-dep2'], function (dep1, shared2, dep2) { 'use strict';
define(['./generated-shared2', './generated-dep1', './generated-dep2'], function (shared2, dep1, dep2) { 'use strict';

console.log(shared2.x + shared2.y);

Expand Down
@@ -1,4 +1,4 @@
define(['./generated-dep1', './generated-shared2', './generated-dep2'], function (dep1, shared2, dep2) { 'use strict';
define(['./generated-shared2', './generated-dep1', './generated-dep2'], function (shared2, dep1, dep2) { 'use strict';



Expand Down
@@ -1,7 +1,7 @@
'use strict';

require('./generated-dep1.js');
var shared2 = require('./generated-shared2.js');
require('./generated-dep1.js');
require('./generated-dep2.js');

console.log(shared2.x + shared2.y);
@@ -1,6 +1,6 @@
'use strict';

require('./generated-dep1.js');
require('./generated-shared2.js');
require('./generated-dep1.js');
require('./generated-dep2.js');

@@ -1,5 +1,5 @@
import './generated-dep1.js';
import { x, y } from './generated-shared2.js';
import './generated-dep1.js';
import './generated-dep2.js';

console.log(x + y);
@@ -1,3 +1,3 @@
import './generated-dep1.js';
import './generated-shared2.js';
import './generated-dep1.js';
import './generated-dep2.js';
@@ -1,11 +1,11 @@
System.register(['./generated-dep1.js', './generated-shared2.js', './generated-dep2.js'], function () {
System.register(['./generated-shared2.js', './generated-dep1.js', './generated-dep2.js'], function () {
'use strict';
var x, y;
return {
setters: [function () {}, function (module) {
setters: [function (module) {
x = module.x;
y = module.y;
}, function () {}],
}, function () {}, function () {}],
execute: function () {

console.log(x + y);
Expand Down
@@ -1,4 +1,4 @@
System.register(['./generated-dep1.js', './generated-shared2.js', './generated-dep2.js'], function () {
System.register(['./generated-shared2.js', './generated-dep1.js', './generated-dep2.js'], function () {
'use strict';
return {
setters: [function () {}, function () {}, function () {}],
Expand Down
@@ -1,4 +1,4 @@
define(['./generated-dep111', './generated-dep112', './generated-dep11'], function (dep111, dep112, dep11) { 'use strict';
define(['./generated-dep11', './generated-dep112', './generated-dep111'], function (dep11, dep112, dep111) { 'use strict';

console.log('1');

Expand Down
@@ -1,4 +1,4 @@
define(['./generated-dep111', './generated-dep112', './generated-dep11'], function (dep111, dep112, dep11) { 'use strict';
define(['./generated-dep11', './generated-dep111', './generated-dep112'], function (dep11, dep111, dep112) { 'use strict';



Expand Down
@@ -1,8 +1,8 @@
'use strict';

require('./generated-dep111.js');
var dep112 = require('./generated-dep112.js');
require('./generated-dep11.js');
var dep112 = require('./generated-dep112.js');
require('./generated-dep111.js');

console.log('1');

Expand Down
@@ -1,6 +1,6 @@
'use strict';

require('./generated-dep11.js');
require('./generated-dep111.js');
require('./generated-dep112.js');
require('./generated-dep11.js');

@@ -1,6 +1,6 @@
import './generated-dep111.js';
import { x } from './generated-dep112.js';
import './generated-dep11.js';
import { x } from './generated-dep112.js';
import './generated-dep111.js';

console.log('1');

Expand Down
@@ -1,3 +1,3 @@
import './generated-dep11.js';
import './generated-dep111.js';
import './generated-dep112.js';
import './generated-dep11.js';
@@ -1,4 +1,4 @@
System.register(['./generated-dep111.js', './generated-dep112.js', './generated-dep11.js'], function () {
System.register(['./generated-dep11.js', './generated-dep112.js', './generated-dep111.js'], function () {
'use strict';
var x;
return {
Expand Down
@@ -1,4 +1,4 @@
System.register(['./generated-dep111.js', './generated-dep112.js', './generated-dep11.js'], function () {
System.register(['./generated-dep11.js', './generated-dep111.js', './generated-dep112.js'], function () {
'use strict';
return {
setters: [function () {}, function () {}, function () {}],
Expand Down
2 changes: 1 addition & 1 deletion test/chunking-form/samples/chunk-execution-order/dep11.js
@@ -1,3 +1,3 @@
import './dep111';
import './dep111.js';
export { x } from './dep112.js';
console.log('11');
@@ -1,4 +1,4 @@
define(['exports', 'external', './generated-dep'], function (exports, external, dep) { 'use strict';
define(['exports', './generated-dep', 'external'], function (exports, dep, external) { 'use strict';



Expand Down
@@ -1,4 +1,4 @@
define(['exports', 'external', './generated-dep'], function (exports, external, dep) { 'use strict';
define(['exports', './generated-dep', 'external'], function (exports, dep, external) { 'use strict';



Expand Down
Expand Up @@ -2,8 +2,8 @@

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

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



Expand Down
Expand Up @@ -2,8 +2,8 @@

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

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



Expand Down
@@ -1,2 +1,2 @@
export { asdf as dep } from 'external';
import './generated-dep.js';
export { asdf as dep } from 'external';
@@ -1,2 +1,2 @@
export { asdf as dep } from 'external';
import './generated-dep.js';
export { asdf as dep } from 'external';
@@ -1,9 +1,9 @@
System.register(['external', './generated-dep.js'], function (exports) {
System.register(['./generated-dep.js', 'external'], function (exports) {
'use strict';
return {
setters: [function (module) {
setters: [function () {}, function (module) {
exports('dep', module.asdf);
}, function () {}],
}],
execute: function () {


Expand Down
@@ -1,9 +1,9 @@
System.register(['external', './generated-dep.js'], function (exports) {
System.register(['./generated-dep.js', 'external'], function (exports) {
'use strict';
return {
setters: [function (module) {
setters: [function () {}, function (module) {
exports('dep', module.asdf);
}, function () {}],
}],
execute: function () {


Expand Down
@@ -1,4 +1,4 @@
define(['exports', 'starexternal1', 'external1', 'starexternal2', 'external2', './generated-dep'], function (exports, starexternal1, external1, starexternal2, external2, dep) { 'use strict';
define(['exports', 'starexternal1', 'external1', './generated-dep', 'starexternal2', 'external2'], function (exports, starexternal1, external1, dep, starexternal2, external2) { 'use strict';

var main = '1';

Expand Down

0 comments on commit e2ee8ae

Please sign in to comment.