diff --git a/src/Chunk.ts b/src/Chunk.ts index 4848a570b68..eb0222c890c 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -31,7 +31,6 @@ import { basename, dirname, isAbsolute, normalize, relative, resolve } from './u import renderChunk from './utils/renderChunk'; import { RenderOptions } from './utils/renderHelpers'; import { makeUnique, renderNamePattern } from './utils/renderNamePattern'; -import { ADDITIONAL_NAMES_BY_FORMAT } from './utils/safeName'; import { sanitizeFileName } from './utils/sanitizeFileName'; import { timeEnd, timeStart } from './utils/timers'; import { MISSING_EXPORT_SHIM_VARIABLE } from './utils/variableNames'; @@ -409,8 +408,6 @@ export default class Chunk { } private setIdentifierRenderResolutions(options: OutputOptions) { - const esmOrSystem = options.format === 'es' || options.format === 'system'; - for (const exportName of Object.keys(this.exportNames)) { const exportVariable = this.exportNames[exportName]; if (exportVariable) { @@ -419,7 +416,8 @@ export default class Chunk { } exportVariable.exportName = exportName; if ( - !esmOrSystem && + options.format !== 'es' && + options.format !== 'system' && exportVariable.isReassigned && !exportVariable.isId && (!isExportDefaultVariable(exportVariable) || !exportVariable.hasId) @@ -431,11 +429,7 @@ export default class Chunk { } } - const additionalNames = ADDITIONAL_NAMES_BY_FORMAT[options.format]; - const usedNames = Object.assign(Object.create(null), additionalNames.globals); - const forbiddenNames = Object.assign(Object.create(null), additionalNames.forbidden); - Object.assign(usedNames, forbiddenNames); - + const usedNames = Object.create(null); if (this.needsExportsShim) { usedNames[MISSING_EXPORT_SHIM_VARIABLE] = true; } @@ -445,8 +439,7 @@ export default class Chunk { this.dependencies, this.imports, usedNames, - forbiddenNames, - esmOrSystem, + options.format, options.interop !== false, this.graph.preserveModules ); diff --git a/src/ast/nodes/ObjectExpression.ts b/src/ast/nodes/ObjectExpression.ts index e3d95d0a60d..85732c33613 100644 --- a/src/ast/nodes/ObjectExpression.ts +++ b/src/ast/nodes/ObjectExpression.ts @@ -1,7 +1,7 @@ import MagicString from 'magic-string'; import { BLANK } from '../../utils/blank'; import { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; -import { NameCollection } from '../../utils/safeName'; +import { NameCollection } from '../../utils/reservedNames'; import CallOptions from '../CallOptions'; import { DeoptimizableEntity } from '../DeoptimizableEntity'; import { ExecutionPathOptions } from '../ExecutionPathOptions'; diff --git a/src/ast/nodes/shared/pureFunctions.ts b/src/ast/nodes/shared/pureFunctions.ts index 8ce0eb260d3..5f0f7607de2 100644 --- a/src/ast/nodes/shared/pureFunctions.ts +++ b/src/ast/nodes/shared/pureFunctions.ts @@ -1,4 +1,4 @@ -import { NameCollection } from '../../../utils/safeName'; +import { NameCollection } from '../../../utils/reservedNames'; const pureFunctions: NameCollection = {}; diff --git a/src/ast/scopes/ChildScope.ts b/src/ast/scopes/ChildScope.ts index c3be0e66328..8e124d6587e 100644 --- a/src/ast/scopes/ChildScope.ts +++ b/src/ast/scopes/ChildScope.ts @@ -1,4 +1,5 @@ -import { getSafeName, NameCollection } from '../../utils/safeName'; +import { NameCollection } from '../../utils/reservedNames'; +import { getSafeName } from '../../utils/safeName'; import { ExpressionEntity } from '../nodes/shared/Expression'; import Variable from '../variables/Variable'; import Scope from './Scope'; diff --git a/src/ast/scopes/ModuleScope.ts b/src/ast/scopes/ModuleScope.ts index 3c728606da2..fe506aaf1c1 100644 --- a/src/ast/scopes/ModuleScope.ts +++ b/src/ast/scopes/ModuleScope.ts @@ -1,5 +1,5 @@ import { AstContext } from '../../Module'; -import { NameCollection } from '../../utils/safeName'; +import { NameCollection } from '../../utils/reservedNames'; import ExportDefaultDeclaration from '../nodes/ExportDefaultDeclaration'; import { UNDEFINED_EXPRESSION } from '../values'; import ExportDefaultVariable from '../variables/ExportDefaultVariable'; @@ -38,7 +38,7 @@ export default class ModuleScope extends ChildScope { } deconflict(forbiddenNames: NameCollection) { - // all module level variables are already deconflicted in the chunk + // all module level variables are already deconflicted when deconflicting the chunk for (const scope of this.children) scope.deconflict(forbiddenNames); } diff --git a/src/utils/deconflictChunk.ts b/src/utils/deconflictChunk.ts index 98dc8913d6a..d6c5f43be67 100644 --- a/src/utils/deconflictChunk.ts +++ b/src/utils/deconflictChunk.ts @@ -3,19 +3,54 @@ import Variable from '../ast/variables/Variable'; import Chunk from '../Chunk'; import ExternalModule from '../ExternalModule'; import Module from '../Module'; -import { getSafeName, NameCollection } from './safeName'; +import { NameCollection, RESERVED_NAMES_BY_FORMAT } from './reservedNames'; +import { getSafeName } from './safeName'; + +const DECONFLICT_IMPORTED_VARIABLES_BY_FORMAT: { + [format: string]: ( + usedNames: NameCollection, + imports: Set, + dependencies: (ExternalModule | Chunk)[], + interop: boolean, + preserveModules: boolean + ) => void; +} = { + cjs: deconflictImportsOther, + iife: deconflictImportsOther, + amd: deconflictImportsOther, + umd: deconflictImportsOther, + system: deconflictImportsEsm, + es: deconflictImportsEsm +}; export function deconflictChunk( modules: Module[], dependencies: (ExternalModule | Chunk)[], imports: Set, usedNames: NameCollection, - forbiddenNames: NameCollection, - esmOrSystem: boolean, + format: string, interop: boolean, preserveModules: boolean ) { - // register globals + const { forbiddenNames, formatGlobals } = RESERVED_NAMES_BY_FORMAT[format]; + Object.assign(usedNames, forbiddenNames); + Object.assign(usedNames, formatGlobals); + addUsedGlobalNames(usedNames, modules); + DECONFLICT_IMPORTED_VARIABLES_BY_FORMAT[format]( + usedNames, + imports, + dependencies, + interop, + preserveModules + ); + deconflictTopLevelVariables(usedNames, modules); + + for (const module of modules) { + module.scope.deconflict(forbiddenNames); + } +} + +function addUsedGlobalNames(usedNames: NameCollection, modules: Module[]) { const accessedGlobals: { [name: string]: Variable } = Object.assign( {}, ...modules.map(module => module.scope.accessedOutsideVariables) @@ -27,58 +62,72 @@ export function deconflictChunk( usedNames[name] = true; } } +} - // deconflict chunk imports - if (esmOrSystem) { - for (const variable of Array.from(imports)) { - const module = variable.module; - const name = variable.name; - let proposedName: string; - if (module instanceof ExternalModule && (name === '*' || name === 'default')) { - if (name === 'default' && interop && module.exportsNamespace) { - proposedName = module.variableName + '__default'; - } else { - proposedName = module.variableName; - } +function deconflictImportsEsm( + usedNames: NameCollection, + imports: Set, + _dependencies: (ExternalModule | Chunk)[], + interop: boolean +) { + for (const variable of Array.from(imports)) { + const module = variable.module; + const name = variable.name; + let proposedName: string; + if (module instanceof ExternalModule && (name === '*' || name === 'default')) { + if (name === 'default' && interop && module.exportsNamespace) { + proposedName = module.variableName + '__default'; } else { - proposedName = name; + proposedName = module.variableName; } - variable.setRenderNames(null, getSafeName(proposedName, usedNames)); - } - } else { - for (const dependency of dependencies) { - dependency.variableName = getSafeName(dependency.variableName, usedNames); + } else { + proposedName = name; } - for (const variable of Array.from(imports)) { - const module = variable.module; - if (module instanceof ExternalModule) { - const name = variable.name; - if (name === 'default' && interop && (module.exportsNamespace || module.exportsNames)) { - variable.setRenderNames(null, module.variableName + '__default'); - } else if (name === '*' || name === 'default') { - variable.setRenderNames(null, module.variableName); - } else { - variable.setRenderNames(module.variableName, null); - } + variable.setRenderNames(null, getSafeName(proposedName, usedNames)); + } +} + +function deconflictImportsOther( + usedNames: NameCollection, + imports: Set, + dependencies: (ExternalModule | Chunk)[], + interop: boolean, + preserveModules: boolean +) { + for (const chunkOrExternalModule of dependencies) { + chunkOrExternalModule.variableName = getSafeName(chunkOrExternalModule.variableName, usedNames); + } + for (const variable of Array.from(imports)) { + const module = variable.module; + if (module instanceof ExternalModule) { + const name = variable.name; + if (name === 'default' && interop && (module.exportsNamespace || module.exportsNames)) { + variable.setRenderNames(null, module.variableName + '__default'); + } else if (name === '*' || name === 'default') { + variable.setRenderNames(null, module.variableName); + } else { + variable.setRenderNames(module.variableName, null); + } + } else { + const chunk = module.chunk; + if (chunk.exportMode === 'default' || (preserveModules && variable.isNamespace)) { + variable.setRenderNames(null, chunk.variableName); } else { - const chunk = module.chunk; - if (chunk.exportMode === 'default' || (preserveModules && variable.isNamespace)) { - variable.setRenderNames(null, chunk.variableName); - } else { - variable.setRenderNames(chunk.variableName, module.chunk.getVariableExportName(variable)); - } + variable.setRenderNames(chunk.variableName, module.chunk.getVariableExportName(variable)); } } } +} - // deconflict module level variables +function deconflictTopLevelVariables(usedNames: NameCollection, modules: Module[]) { for (const module of modules) { const moduleVariables = module.scope.variables; for (const name of Object.keys(moduleVariables)) { const variable = moduleVariables[name]; if ( variable.included && - !( + !// this will only happen for exports in some formats + ( variable.renderBaseName || (variable instanceof ExportDefaultVariable && variable.referencesOriginal()) ) @@ -91,8 +140,4 @@ export function deconflictChunk( namespace.setRenderNames(null, getSafeName(namespace.name, usedNames)); } } - - for (const module of modules) { - module.scope.deconflict(forbiddenNames); - } } diff --git a/src/utils/pluginDriver.ts b/src/utils/pluginDriver.ts index ccbe55319f0..d99534c98a8 100644 --- a/src/utils/pluginDriver.ts +++ b/src/utils/pluginDriver.ts @@ -15,7 +15,7 @@ import { import { createAssetPluginHooks, EmitAsset } from './assetHooks'; import { getRollupDefaultPlugin } from './defaultPlugin'; import { error } from './error'; -import { NameCollection } from './safeName'; +import { NameCollection } from './reservedNames'; export interface PluginDriver { emitAsset: EmitAsset; diff --git a/src/utils/reservedNames.ts b/src/utils/reservedNames.ts new file mode 100644 index 00000000000..c2f4fcb840a --- /dev/null +++ b/src/utils/reservedNames.ts @@ -0,0 +1,73 @@ +import { INTEROP_DEFAULT_VARIABLE } from './variableNames'; + +export interface NameCollection { + [name: string]: true; +} + +const RESERVED_NAMES: NameCollection = Object.assign(Object.create(null), { + await: true, + break: true, + case: true, + catch: true, + class: true, + const: true, + continue: true, + debugger: true, + default: true, + delete: true, + do: true, + else: true, + enum: true, + eval: true, + export: true, + extends: true, + finally: true, + for: true, + function: true, + if: true, + implements: true, + import: true, + in: true, + instanceof: true, + interface: true, + let: true, + new: true, + null: true, + package: true, + private: true, + protected: true, + public: true, + return: true, + static: true, + super: true, + switch: true, + throw: true, + try: true, + typeof: true, + undefined: true, + var: true, + void: true, + while: true, + with: true, + yield: true +}); + +const NONE: NameCollection = {}; +const EXPORTS: NameCollection = { exports: true }; + +export const RESERVED_NAMES_BY_FORMAT: { + [format: string]: { formatGlobals: NameCollection; forbiddenNames: NameCollection }; +} = { + cjs: { + formatGlobals: { exports: true, module: true, [INTEROP_DEFAULT_VARIABLE]: true }, + forbiddenNames: RESERVED_NAMES + }, + iife: { formatGlobals: EXPORTS, forbiddenNames: RESERVED_NAMES }, + amd: { formatGlobals: EXPORTS, forbiddenNames: RESERVED_NAMES }, + umd: { formatGlobals: EXPORTS, forbiddenNames: RESERVED_NAMES }, + system: { + formatGlobals: NONE, + forbiddenNames: Object.assign(Object.create(null), RESERVED_NAMES, EXPORTS) + }, + es: { formatGlobals: NONE, forbiddenNames: RESERVED_NAMES } +}; diff --git a/src/utils/safeName.ts b/src/utils/safeName.ts index 765cf6c6dc4..aad1d49a468 100644 --- a/src/utils/safeName.ts +++ b/src/utils/safeName.ts @@ -1,74 +1,5 @@ import { toBase64 } from './base64'; -import { INTEROP_DEFAULT_VARIABLE } from './variableNames'; - -export interface NameCollection { - [name: string]: true; -} - -const RESERVED_NAMES: NameCollection = Object.assign(Object.create(null), { - await: true, - break: true, - case: true, - catch: true, - class: true, - const: true, - continue: true, - debugger: true, - default: true, - delete: true, - do: true, - else: true, - enum: true, - eval: true, - export: true, - extends: true, - finally: true, - for: true, - function: true, - if: true, - implements: true, - import: true, - in: true, - instanceof: true, - interface: true, - let: true, - new: true, - null: true, - package: true, - private: true, - protected: true, - public: true, - return: true, - static: true, - super: true, - switch: true, - throw: true, - try: true, - typeof: true, - undefined: true, - var: true, - void: true, - while: true, - with: true, - yield: true -}); - -const NONE = Object.create(null); -const EXPORTS: NameCollection = { exports: true }; - -export const ADDITIONAL_NAMES_BY_FORMAT: { - [format: string]: { globals: NameCollection; forbidden: NameCollection }; -} = { - cjs: { - globals: { exports: true, module: true, [INTEROP_DEFAULT_VARIABLE]: true }, - forbidden: RESERVED_NAMES - }, - iife: { globals: EXPORTS, forbidden: RESERVED_NAMES }, - amd: { globals: EXPORTS, forbidden: RESERVED_NAMES }, - umd: { globals: EXPORTS, forbidden: RESERVED_NAMES }, - system: { globals: NONE, forbidden: Object.assign(Object.create(null), RESERVED_NAMES, EXPORTS) }, - es: { globals: NONE, forbidden: RESERVED_NAMES } -}; +import { NameCollection } from './reservedNames'; export function getSafeName(baseName: string, usedNames: NameCollection): string { let safeName = baseName; diff --git a/src/utils/traverseStaticDependencies.ts b/src/utils/traverseStaticDependencies.ts index 20229707058..a2cb4b12ac3 100644 --- a/src/utils/traverseStaticDependencies.ts +++ b/src/utils/traverseStaticDependencies.ts @@ -1,6 +1,6 @@ import ExternalModule from '../ExternalModule'; import Module from '../Module'; -import { NameCollection } from './safeName'; +import { NameCollection } from './reservedNames'; export function visitStaticModuleDependencies( baseModule: Module | ExternalModule,