Skip to content

Commit

Permalink
Clean up chunk deconflicting code
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Feb 14, 2019
1 parent 3b7e3f0 commit a06fb8f
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 133 deletions.
15 changes: 4 additions & 11 deletions src/Chunk.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand All @@ -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;
}
Expand All @@ -445,8 +439,7 @@ export default class Chunk {
this.dependencies,
this.imports,
usedNames,
forbiddenNames,
esmOrSystem,
options.format,
options.interop !== false,
this.graph.preserveModules
);
Expand Down
2 changes: 1 addition & 1 deletion 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';
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/shared/pureFunctions.ts
@@ -1,4 +1,4 @@
import { NameCollection } from '../../../utils/safeName';
import { NameCollection } from '../../../utils/reservedNames';

const pureFunctions: NameCollection = {};

Expand Down
3 changes: 2 additions & 1 deletion 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';
Expand Down
4 changes: 2 additions & 2 deletions 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';
Expand Down Expand Up @@ -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);
}

Expand Down
135 changes: 90 additions & 45 deletions src/utils/deconflictChunk.ts
Expand Up @@ -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<Variable>,
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<Variable>,
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)
Expand All @@ -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<Variable>,
_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<Variable>,
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())
)
Expand All @@ -91,8 +140,4 @@ export function deconflictChunk(
namespace.setRenderNames(null, getSafeName(namespace.name, usedNames));
}
}

for (const module of modules) {
module.scope.deconflict(forbiddenNames);
}
}
2 changes: 1 addition & 1 deletion src/utils/pluginDriver.ts
Expand Up @@ -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;
Expand Down
73 changes: 73 additions & 0 deletions 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 }
};

0 comments on commit a06fb8f

Please sign in to comment.