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

Improve synthetic entry handling #3738

Merged
merged 5 commits into from
Aug 19, 2020
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: 2 additions & 0 deletions src/Bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { timeEnd, timeStart } from './utils/timers';

export default class Bundle {
private facadeChunkByModule = new Map<Module, Chunk>();
private includedNamespaces = new Set<Module>();

constructor(
private readonly outputOptions: NormalizedOutputOptions,
Expand Down Expand Up @@ -202,6 +203,7 @@ export default class Bundle {
this.graph.modulesById,
chunkByModule,
this.facadeChunkByModule,
this.includedNamespaces,
alias
);
chunks.push(chunk);
Expand Down
41 changes: 28 additions & 13 deletions src/Chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export default class Chunk {
modulesById: Map<string, Module | ExternalModule>,
chunkByModule: Map<Module, Chunk>,
facadeChunkByModule: Map<Module, Chunk>,
includedNamespaces: Set<Module>,
facadedModule: Module,
facadeName: FacadeName
): Chunk {
Expand All @@ -147,6 +148,7 @@ export default class Chunk {
modulesById,
chunkByModule,
facadeChunkByModule,
includedNamespaces,
null
);
chunk.assignFacadeName(facadeName, facadedModule);
Expand Down Expand Up @@ -176,6 +178,7 @@ export default class Chunk {
exportMode: 'none' | 'named' | 'default' = 'named';
facadeModule: Module | null = null;
id: string | null = null;
namespaceVariableName = '';
suggestedVariableName: string;
variableName = '';

Expand Down Expand Up @@ -218,12 +221,16 @@ export default class Chunk {
private readonly modulesById: Map<string, Module | ExternalModule>,
private readonly chunkByModule: Map<Module, Chunk>,
private readonly facadeChunkByModule: Map<Module, Chunk>,
private readonly includedNamespaces: Set<Module>,
private readonly manualChunkAlias: string | null
) {
this.execIndex = orderedModules.length > 0 ? orderedModules[0].execIndex : Infinity;
const chunkModules = new Set(orderedModules);

for (const module of orderedModules) {
if (module.namespace.included) {
includedNamespaces.add(module);
}
if (this.isEmpty && module.isIncluded()) {
this.isEmpty = false;
}
Expand All @@ -234,8 +241,8 @@ export default class Chunk {
if (!chunkModules.has(importer)) {
this.dynamicEntryModules.push(module);
// Modules with synthetic exports need an artificial namespace for dynamic imports
if (module.syntheticNamedExports) {
module.namespace.include();
if (module.syntheticNamedExports && !outputOptions.preserveModules) {
includedNamespaces.add(module);
this.exports.add(module.namespace);
}
}
Expand Down Expand Up @@ -359,6 +366,7 @@ export default class Chunk {
this.modulesById,
this.chunkByModule,
this.facadeChunkByModule,
this.includedNamespaces,
module,
facadeName
)
Expand All @@ -379,7 +387,7 @@ export default class Chunk {
) {
this.strictFacade = true;
} else if (!this.facadeChunkByModule.get(module)?.strictFacade) {
module.namespace.include();
this.includedNamespaces.add(module);
this.exports.add(module.namespace);
}
}
Expand Down Expand Up @@ -581,7 +589,7 @@ export default class Chunk {

for (const module of this.orderedModules) {
let renderedLength = 0;
if (module.isIncluded()) {
if (module.isIncluded() || this.includedNamespaces.has(module)) {
const source = module.render(renderOptions).trim();
renderedLength = source.length();
if (renderedLength) {
Expand All @@ -591,7 +599,7 @@ export default class Chunk {
this.usedModules.push(module);
}
const namespace = module.namespace;
if (namespace.included && !this.outputOptions.preserveModules) {
if (this.includedNamespaces.has(module) && !this.outputOptions.preserveModules) {
const rendered = namespace.renderBlock(renderOptions);
if (namespace.renderFirst()) hoistedSource += n + rendered;
else magicString.addSource(new MagicString(rendered));
Expand Down Expand Up @@ -987,7 +995,7 @@ export default class Chunk {
): DependenciesToBeDeconflicted {
const dependencies = new Set<Chunk | ExternalModule>();
const deconflictedDefault = new Set<ExternalModule>();
const deconflictedNamespace = new Set<ExternalModule>();
const deconflictedNamespace = new Set<Chunk | ExternalModule>();
for (const variable of [...this.exportNamesByVariable.keys(), ...this.imports]) {
if (addNonNamespacesAndInteropHelpers || variable.isNamespace) {
const module = variable.module!;
Expand All @@ -1008,6 +1016,13 @@ export default class Chunk {
const chunk = this.chunkByModule.get(module)!;
if (chunk !== this) {
dependencies.add(chunk);
if (
addNonNamespacesAndInteropHelpers &&
chunk.exportMode === 'default' &&
variable.isNamespace
) {
deconflictedNamespace.add(chunk);
}
}
}
}
Expand Down Expand Up @@ -1252,7 +1267,8 @@ export default class Chunk {
this.chunkByModule,
syntheticExports,
this.exportNamesByVariable,
this.accessedGlobalsByScope
this.accessedGlobalsByScope,
this.includedNamespaces
);
}

Expand All @@ -1261,9 +1277,8 @@ export default class Chunk {
// when we are not preserving modules, we need to make all namespace variables available for
// rendering the namespace object
if (!this.outputOptions.preserveModules) {
const namespace = module.namespace;
if (namespace.included) {
const memberVariables = namespace.getMemberVariables();
if (this.includedNamespaces.has(module)) {
const memberVariables = module.namespace.getMemberVariables();
for (const name of Object.keys(memberVariables)) {
moduleImports.add(memberVariables[name]);
}
Expand All @@ -1288,7 +1303,7 @@ export default class Chunk {
}
}
if (
module.namespace.included ||
this.includedNamespaces.has(module) ||
(module.isEntryPoint && module.preserveSignature !== false) ||
module.includedDynamicImporters.some(importer => this.chunkByModule.get(importer) !== this)
) {
Expand All @@ -1299,9 +1314,9 @@ export default class Chunk {
node.included &&
resolution instanceof Module &&
this.chunkByModule.get(resolution) === this &&
!resolution.namespace.included
!this.includedNamespaces.has(resolution)
) {
resolution.namespace.include();
this.includedNamespaces.add(resolution);
this.ensureReexportsAreAvailableForModule(resolution);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export default class Graph {
private includeStatements() {
for (const module of [...this.entryModules, ...this.implicitEntryModules]) {
if (module.preserveSignature !== false) {
module.includeAllExports();
module.includeAllExports(false);
} else {
markModuleAndImpureDependenciesAsExecuted(module);
}
Expand Down
26 changes: 15 additions & 11 deletions src/Module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export interface AstContext {
getModuleName: () => string;
getReexports: () => string[];
importDescriptions: { [name: string]: ImportDescription };
includeAndGetAdditionalMergedNamespaces: () => Variable[];
includeAllExports: () => void;
includeDynamicImport: (node: ImportExpression) => void;
includeVariable: (variable: Variable) => void;
magicString: MagicString;
Expand Down Expand Up @@ -529,18 +529,20 @@ export default class Module {
if (this.ast.shouldBeIncluded(context)) this.ast.include(context, false);
}

includeAllExports() {
includeAllExports(includeNamespaceMembers: boolean) {
if (!this.isExecuted) {
this.graph.needsTreeshakingPass = true;
markModuleAndImpureDependenciesAsExecuted(this);
}

for (const exportName of this.getExports()) {
const variable = this.getVariableForExportName(exportName);
variable.deoptimizePath(UNKNOWN_PATH);
if (!variable.included) {
variable.include();
this.graph.needsTreeshakingPass = true;
if (includeNamespaceMembers || exportName !== this.syntheticNamedExports) {
const variable = this.getVariableForExportName(exportName);
variable.deoptimizePath(UNKNOWN_PATH);
if (!variable.included) {
variable.include();
this.graph.needsTreeshakingPass = true;
}
}
}

Expand All @@ -555,6 +557,10 @@ export default class Module {
variable.module.reexported = true;
}
}

if (includeNamespaceMembers) {
this.namespace.prepareNamespace(this.includeAndGetAdditionalMergedNamespaces());
}
}

includeAllInBundle() {
Expand Down Expand Up @@ -679,9 +685,7 @@ export default class Module {
getModuleName: this.basename.bind(this),
getReexports: this.getReexports.bind(this),
importDescriptions: this.importDescriptions,
includeAndGetAdditionalMergedNamespaces: this.includeAndGetAdditionalMergedNamespaces.bind(
this
),
includeAllExports: () => this.includeAllExports(true),
includeDynamicImport: this.includeDynamicImport.bind(this),
includeVariable: this.includeVariable.bind(this),
magicString: this.magicString,
Expand Down Expand Up @@ -926,7 +930,7 @@ export default class Module {
}).resolution;
if (resolution instanceof Module) {
resolution.includedDynamicImporters.push(this);
resolution.includeAllExports();
resolution.includeAllExports(true);
}
}

Expand Down
27 changes: 11 additions & 16 deletions src/ast/variables/NamespaceVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,21 @@ export default class NamespaceVariable extends Variable {
memberVariables[name] = this.context.traceExport(name);
}
}
this.memberVariables = memberVariables;
return (this.memberVariables = memberVariables);
}

include() {
if (!this.included) {
this.included = true;
for (const identifier of this.references) {
if (identifier.context.getModuleExecIndex() <= this.context.getModuleExecIndex()) {
this.referencedEarly = true;
break;
}
}
this.mergedNamespaces = this.context.includeAndGetAdditionalMergedNamespaces();
const memberVariables = this.getMemberVariables();
// We directly include the variables instead of context.include to not automatically
// generate imports for members from other modules
for (const memberName of Object.keys(memberVariables)) memberVariables[memberName].include();
if (typeof this.syntheticNamedExports === 'string') {
this.context.traceExport(this.syntheticNamedExports).include();
this.included = true;
this.context.includeAllExports();
}

prepareNamespace(mergedNamespaces: Variable[]) {
this.mergedNamespaces = mergedNamespaces;
const moduleExecIndex = this.context.getModuleExecIndex();
for (const identifier of this.references) {
if (identifier.context.getModuleExecIndex() <= moduleExecIndex) {
this.referencedEarly = true;
break;
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/finalisers/shared/getExportBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ function getReexportedImportName(
return depNamedExportsMode ? `${moduleVariableName}['default']` : moduleVariableName;
}
if (imported === '*') {
return !isChunk && namespaceInteropHelpersByInteropType[String(interop(moduleId))]
return (
isChunk
? !depNamedExportsMode
: namespaceInteropHelpersByInteropType[String(interop(moduleId))]
)
? namespaceVariableName
: moduleVariableName;
}
Expand Down
41 changes: 31 additions & 10 deletions src/finalisers/shared/getInteropBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ModuleDeclarationDependency, ReexportSpecifier } from '../../Chunk';
import { GetInterop } from '../../rollup/types';
import {
defaultInteropHelpersByInteropType,
getDefaultOnlyHelper,
getHelpersBlock,
namespaceInteropHelpersByInteropType
} from '../../utils/interopHelpers';
Expand All @@ -19,46 +20,66 @@ export default function getInteropBlock(
t: string
): string {
const neededInteropHelpers = new Set<string>();
const interopStatements = [];
const interopStatements: string[] = [];
const addInteropStatement = (
helperVariableName: string,
helper: string,
dependencyVariableName: string
): void => {
neededInteropHelpers.add(helper);
interopStatements.push(
`${varOrConst} ${helperVariableName}${_}=${_}/*#__PURE__*/${helper}(${dependencyVariableName});`
);
};
for (const {
defaultVariableName,
imports,
id,
isChunk,
name,
namedExportsMode,
namespaceVariableName,
reexports
} of dependencies) {
if (!isChunk) {
if (isChunk) {
for (const { imported, reexported } of [
...(imports || []),
...(reexports || [])
] as ReexportSpecifier[]) {
if (imported === '*' && reexported !== '*') {
if (!namedExportsMode) {
addInteropStatement(namespaceVariableName!, getDefaultOnlyHelper(), name);
}
break;
}
}
} else {
const moduleInterop = String(interop(id));
let hasDefault = false;
let hasNamespace = false;
for (const { imported, reexported } of [
...(imports || []),
...(reexports || [])
] as ReexportSpecifier[]) {
let helper: string | null = null;
let variableName;
let helper: string | undefined | null;
let variableName: string | undefined;
if (imported === 'default') {
if (!hasDefault) {
hasDefault = true;
if (defaultVariableName !== namespaceVariableName) {
variableName = defaultVariableName;
variableName = defaultVariableName!;
helper = defaultInteropHelpersByInteropType[moduleInterop];
}
}
} else if (imported === '*' && reexported !== '*') {
if (!hasNamespace) {
hasNamespace = true;
helper = namespaceInteropHelpersByInteropType[moduleInterop];
variableName = namespaceVariableName;
variableName = namespaceVariableName!;
}
}
if (helper) {
neededInteropHelpers.add(helper);
interopStatements.push(
`${varOrConst} ${variableName}${_}=${_}/*#__PURE__*/${helper}(${name});`
);
addInteropStatement(variableName!, helper, name);
}
}
}
Expand Down