Skip to content

Commit

Permalink
Thoroughly improve import resolution (#2584)
Browse files Browse the repository at this point in the history
* Add modules to variables to make resolution easier

* Improve handling of missing exports, add module references to variables
to simplify tracing

* Simplify namespace handling and prevent name conflicts with other imports
when creating a namespace object

* Directly register imported variables during tree-shaking to only import
variables into modules that actually use them. Get rid of variable
tracing logic on chunks.

* Fix dynamic namespace imports when preserving modules
Also, do not inline the execution list when preserving modules

* Ensure proper execution order by always adding all direct dependencies
and sorting only once all dependencies have been added
  • Loading branch information
lukastaegert committed Dec 11, 2018
1 parent c87132b commit f58d1e6
Show file tree
Hide file tree
Showing 254 changed files with 1,263 additions and 669 deletions.
320 changes: 123 additions & 197 deletions src/Chunk.ts

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions src/ExternalModule.ts
@@ -1,5 +1,4 @@
import ExternalVariable from './ast/variables/ExternalVariable';
import Variable from './ast/variables/Variable';
import Graph from './Graph';
import { OutputOptions } from './rollup/types';
import { makeLegal } from './utils/identifierHelpers';
Expand Down Expand Up @@ -87,7 +86,7 @@ export default class ExternalModule {
});
}

traceExport(name: string, _isExportAllSearch?: boolean): Variable {
getVariableForExportName(name: string, _isExportAllSearch?: boolean): ExternalVariable {
if (name !== 'default' && name !== '*') this.exportsNames = true;
if (name === '*') this.exportsNamespace = true;

Expand Down
28 changes: 13 additions & 15 deletions src/Graph.ts
Expand Up @@ -4,7 +4,6 @@ import injectImportMeta from 'acorn-import-meta/inject';
import { Program } from 'estree';
import GlobalScope from './ast/scopes/GlobalScope';
import { EntityPathTracker } from './ast/utils/EntityPathTracker';
import GlobalVariable from './ast/variables/GlobalVariable';
import Chunk from './Chunk';
import ExternalModule from './ExternalModule';
import Module, { defaultAcornOptions } from './Module';
Expand Down Expand Up @@ -32,6 +31,7 @@ import { createPluginDriver, PluginDriver } from './utils/pluginDriver';
import relativeId, { getAliasName } from './utils/relativeId';
import { timeEnd, timeStart } from './utils/timers';
import transform from './utils/transform';
import { MISSING_EXPORT_SHIM_VARIABLE } from './utils/variableNames';

function makeOnwarn() {
const warned = Object.create(null);
Expand Down Expand Up @@ -61,9 +61,9 @@ export default class Graph {
deoptimizationTracker: EntityPathTracker;
scope: GlobalScope;
shimMissingExports: boolean;
exportShimVariable: GlobalVariable;
treeshakingOptions: TreeshakingOptions;
varOrConst: 'var' | 'const';
preserveModules: boolean;

isExternal: IsExternal;

Expand Down Expand Up @@ -97,6 +97,7 @@ export default class Graph {
for (const key of Object.keys(cache)) cache[key][0]++;
}
}
this.preserveModules = options.experimentalPreserveModules;

this.cacheExpiry = options.experimentalCacheExpiry;

Expand Down Expand Up @@ -155,11 +156,9 @@ export default class Graph {
this.shimMissingExports = options.shimMissingExports;

this.scope = new GlobalScope();
// Strictly speaking, this only applies with non-ES6, non-default-only bundles
for (const name of ['module', 'exports', '_interopDefault']) {
for (const name of ['module', 'exports', '_interopDefault', MISSING_EXPORT_SHIM_VARIABLE]) {
this.scope.findVariable(name); // creates global variable as side-effect
}
this.exportShimVariable = this.scope.findVariable('_missingExportShim');

this.context = String(options.context);

Expand Down Expand Up @@ -335,8 +334,7 @@ export default class Graph {
build(
entryModules: string | string[] | Record<string, string>,
manualChunks: Record<string, string[]> | void,
inlineDynamicImports: boolean,
preserveModules: boolean
inlineDynamicImports: boolean
): Promise<Chunk[]> {
// Phase 1 – discovery. We load the entry module and find which
// modules it imports, and import those, until we have all
Expand Down Expand Up @@ -401,7 +399,7 @@ export default class Graph {
// entry point graph colouring, before generating the import and export facades
timeStart('generate chunks', 2);

if (!preserveModules && !inlineDynamicImports) {
if (!this.preserveModules && !inlineDynamicImports) {
assignChunkColouringHashes(entryModules, manualChunkModules);
}

Expand All @@ -416,7 +414,7 @@ export default class Graph {
// either as a namespace import reexported or top-level export *)
// should be made to be its own entry point module before chunking
let chunks: Chunk[] = [];
if (preserveModules) {
if (this.preserveModules) {
for (const module of orderedModules) {
const chunk = new Chunk(this, [module], inlineDynamicImports);
if (module.isEntryPoint || !chunk.isEmpty) {
Expand Down Expand Up @@ -457,14 +455,14 @@ export default class Graph {

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

// create entry point facades for entry module chunks that have tainted exports
const facades = [];
if (!preserveModules) {
if (!this.preserveModules) {
for (const chunk of chunks) {
for (const entryModule of chunk.entryModules) {
if (chunk.facadeModule !== entryModule) {
Expand Down Expand Up @@ -687,12 +685,12 @@ export default class Graph {
});
}

// add external declarations so we can detect which are never used
for (const name in module.imports) {
const importDeclaration = module.imports[name];
for (const name in module.importDescriptions) {
const importDeclaration = module.importDescriptions[name];
if (importDeclaration.source !== source) return;

externalModule.traceExport(importDeclaration.name);
// this will trigger a warning for unused external imports
externalModule.getVariableForExportName(importDeclaration.name);
}
} else {
module.resolvedIds[source] = <string>resolvedId;
Expand Down

0 comments on commit f58d1e6

Please sign in to comment.