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

Prefer locally defined exports and reexports over external namespaces #4064

Merged
merged 3 commits into from May 4, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 1 addition & 1 deletion src/ExternalModule.ts
Expand Up @@ -112,7 +112,7 @@ export default class ExternalModule {

const importersSet = new Set<string>();
for (const name of unused) {
const {importers, dynamicImporters} = this.declarations[name].module;
const { importers, dynamicImporters } = this.declarations[name].module;

if (Array.isArray(importers)) importers.forEach(v => importersSet.add(v));
if (Array.isArray(dynamicImporters)) dynamicImporters.forEach(v => importersSet.add(v));
Expand Down
80 changes: 49 additions & 31 deletions src/Module.ts
Expand Up @@ -45,6 +45,7 @@ import {
RollupWarning,
TransformModuleJSON
} from './rollup/types';
import { EMPTY_OBJECT } from './utils/blank';
import {
augmentCodeLocation,
errCircularReexport,
Expand Down Expand Up @@ -129,8 +130,11 @@ function findSourceMappingURLComments(ast: acorn.Node, code: string): [number, n

let sourcemappingUrlMatch;
const interStatmentCode = code.slice(start, end);
while (sourcemappingUrlMatch = SOURCEMAPPING_URL_COMMENT_RE.exec(interStatmentCode)) {
ret.push([start + sourcemappingUrlMatch.index, start + SOURCEMAPPING_URL_COMMENT_RE.lastIndex]);
while ((sourcemappingUrlMatch = SOURCEMAPPING_URL_COMMENT_RE.exec(interStatmentCode))) {
ret.push([
start + sourcemappingUrlMatch.index,
start + SOURCEMAPPING_URL_COMMENT_RE.lastIndex
]);
}
};

Expand All @@ -149,7 +153,8 @@ function getVariableForExportNameRecursive(
name: string,
importerForSideEffects: Module | undefined,
isExportAllSearch: boolean,
searchedNamesAndModules = new Map<string, Set<Module | ExternalModule>>()
searchedNamesAndModules = new Map<string, Set<Module | ExternalModule>>(),
skipExternalNamespaceReexports: boolean | undefined
): Variable | null {
const searchedModules = searchedNamesAndModules.get(name);
if (searchedModules) {
Expand All @@ -160,12 +165,12 @@ function getVariableForExportNameRecursive(
} else {
searchedNamesAndModules.set(name, new Set([target]));
}
return target.getVariableForExportName(
name,
return target.getVariableForExportName(name, {
importerForSideEffects,
isExportAllSearch,
searchedNamesAndModules
);
searchedNamesAndModules,
skipExternalNamespaceReexports
});
}

function getAndExtendSideEffectModules(variable: Variable, module: Module): Set<Module> {
Expand Down Expand Up @@ -482,9 +487,17 @@ export default class Module {

getVariableForExportName(
name: string,
importerForSideEffects?: Module,
isExportAllSearch?: boolean,
searchedNamesAndModules?: Map<string, Set<Module | ExternalModule>>
{
importerForSideEffects,
isExportAllSearch,
searchedNamesAndModules,
skipExternalNamespaceReexports
}: {
importerForSideEffects?: Module;
isExportAllSearch?: boolean;
searchedNamesAndModules?: Map<string, Set<Module | ExternalModule>>;
skipExternalNamespaceReexports?: boolean;
} = EMPTY_OBJECT
): Variable | null {
if (name[0] === '*') {
if (name.length === 1) {
Expand All @@ -505,7 +518,8 @@ export default class Module {
reexportDeclaration.localName,
importerForSideEffects,
false,
searchedNamesAndModules
searchedNamesAndModules,
false
);

if (!variable) {
Expand Down Expand Up @@ -540,21 +554,27 @@ export default class Module {

if (name !== 'default') {
let foundSyntheticDeclaration: SyntheticNamedExportVariable | null = null;
for (const module of this.exportAllModules) {
const declaration = getVariableForExportNameRecursive(
module,
name,
importerForSideEffects,
true,
searchedNamesAndModules
);

if (declaration) {
if (!(declaration instanceof SyntheticNamedExportVariable)) {
return declaration;
}
if (!foundSyntheticDeclaration) {
foundSyntheticDeclaration = declaration;
const skipExternalNamespaceValues = new Set([true, skipExternalNamespaceReexports]);
for (const skipExternalNamespaces of skipExternalNamespaceValues) {
for (const module of this.exportAllModules) {
if (module instanceof Module || !skipExternalNamespaces) {
const declaration = getVariableForExportNameRecursive(
module,
name,
importerForSideEffects,
true,
searchedNamesAndModules,
skipExternalNamespaces
);

if (declaration) {
if (!(declaration instanceof SyntheticNamedExportVariable)) {
return declaration;
}
if (!foundSyntheticDeclaration) {
foundSyntheticDeclaration = declaration;
}
}
}
}
}
Expand Down Expand Up @@ -798,10 +818,9 @@ export default class Module {
return otherModule.namespace;
}

const declaration = otherModule.getVariableForExportName(
importDeclaration.name,
importerForSideEffects || this
);
const declaration = otherModule.getVariableForExportName(importDeclaration.name, {
importerForSideEffects: importerForSideEffects || this
});

if (!declaration) {
return this.error(
Expand Down Expand Up @@ -837,7 +856,6 @@ export default class Module {
}
}


updateOptions({
meta,
moduleSideEffects,
Expand Down
4 changes: 4 additions & 0 deletions test/form/samples/namespace-reexport-name/_config.js
@@ -0,0 +1,4 @@
module.exports = {
description: 'uses correct names when reexporting from namespace reexports (#4049)',
options: { external: 'external', output: { name: 'bundle' } }
};
29 changes: 29 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/amd.js
@@ -0,0 +1,29 @@
define(['exports', 'external'], function (exports, external) { 'use strict';

const renamedIndirectOverride = external.indirectOverride;

Object.defineProperty(exports, 'noOverride', {
enumerable: true,
get: function () {
return external.noOverride;
}
});
Object.defineProperty(exports, 'renamedDirectOverride', {
enumerable: true,
get: function () {
return external.directOverride;
}
});
exports.renamedIndirectOverride = renamedIndirectOverride;
Object.keys(external).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () {
return external[k];
}
});
});

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

});
29 changes: 29 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/cjs.js
@@ -0,0 +1,29 @@
'use strict';

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

var external = require('external');

const renamedIndirectOverride = external.indirectOverride;

Object.defineProperty(exports, 'noOverride', {
enumerable: true,
get: function () {
return external.noOverride;
}
});
Object.defineProperty(exports, 'renamedDirectOverride', {
enumerable: true,
get: function () {
return external.directOverride;
}
});
exports.renamedIndirectOverride = renamedIndirectOverride;
Object.keys(external).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () {
return external[k];
}
});
});
7 changes: 7 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/es.js
@@ -0,0 +1,7 @@
import { indirectOverride } from 'external';
export * from 'external';
export { noOverride, directOverride as renamedDirectOverride } from 'external';

const renamedIndirectOverride = indirectOverride;

export { renamedIndirectOverride };
32 changes: 32 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/iife.js
@@ -0,0 +1,32 @@
var bundle = (function (exports, external) {
'use strict';

const renamedIndirectOverride = external.indirectOverride;

Object.defineProperty(exports, 'noOverride', {
enumerable: true,
get: function () {
return external.noOverride;
}
});
Object.defineProperty(exports, 'renamedDirectOverride', {
enumerable: true,
get: function () {
return external.directOverride;
}
});
exports.renamedIndirectOverride = renamedIndirectOverride;
Object.keys(external).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () {
return external[k];
}
});
});

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

return exports;

}({}, external));
22 changes: 22 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/system.js
@@ -0,0 +1,22 @@
System.register('bundle', ['external'], function (exports) {
'use strict';
var _starExcludes = { renamedIndirectOverride: 1, default: 1, noOverride: 1, renamedDirectOverride: 1 };
var indirectOverride;
return {
setters: [function (module) {
indirectOverride = module.indirectOverride;
var _setter = {};
for (var _$p in module) {
if (!_starExcludes[_$p]) _setter[_$p] = module[_$p];
}
_setter.noOverride = module.noOverride;
_setter.renamedDirectOverride = module.directOverride;
exports(_setter);
}],
execute: function () {

const renamedIndirectOverride = exports('renamedIndirectOverride', indirectOverride);

}
};
});
33 changes: 33 additions & 0 deletions test/form/samples/namespace-reexport-name/_expected/umd.js
@@ -0,0 +1,33 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('external')) :
typeof define === 'function' && define.amd ? define(['exports', 'external'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bundle = {}, global.external));
}(this, (function (exports, external) { 'use strict';

const renamedIndirectOverride = external.indirectOverride;

Object.defineProperty(exports, 'noOverride', {
enumerable: true,
get: function () {
return external.noOverride;
}
});
Object.defineProperty(exports, 'renamedDirectOverride', {
enumerable: true,
get: function () {
return external.directOverride;
}
});
exports.renamedIndirectOverride = renamedIndirectOverride;
Object.keys(external).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () {
return external[k];
}
});
});

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

})));
@@ -0,0 +1,2 @@
export * from 'external';
export { noOverride } from 'external';
2 changes: 2 additions & 0 deletions test/form/samples/namespace-reexport-name/main.js
@@ -0,0 +1,2 @@
export * from './external-reexport';
export * from './overrides';
5 changes: 5 additions & 0 deletions test/form/samples/namespace-reexport-name/overrides.js
@@ -0,0 +1,5 @@
import { indirectOverride, ignoredOverride } from './external-reexport';
export { directOverride as renamedDirectOverride } from './external-reexport';

export const renamedIndirectOverride = indirectOverride;
export const noOverride = ignoredOverride;
11 changes: 0 additions & 11 deletions test/function/samples/emit-file/non-invalid-asset-name/_config.js

This file was deleted.

This file was deleted.