Skip to content

Commit ee0b14d

Browse files
committed
Use default import alias for externals
1 parent 535c586 commit ee0b14d

File tree

6 files changed

+86
-35
lines changed

6 files changed

+86
-35
lines changed

lib/impl/NollupCodeGenerator.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,32 @@ function getExportAllFrom (namespace) {
9191
}
9292

9393
/**
94-
* @param {string} source
94+
* @param {NollupInternalModuleImport} externalImport
9595
* @return {string}
9696
*/
97-
function getIIFEName(source) {
98-
return source.replace(/\-([\w])/g, (m) => m[1].toUpperCase()).replace(/[^a-zA-Z0-9$_]/g, '_');
97+
function getIIFEName(externalImport) {
98+
let hasDefaultSpec = externalImport.specifiers.find(s => s.imported === 'default' && s.local !== 'default');
99+
100+
if (hasDefaultSpec && hasDefaultSpec.local) {
101+
return hasDefaultSpec.local;
102+
}
103+
104+
return externalImport.source.replace(/\-([\w])/g, (m) => m[1].toUpperCase()).replace(/[^a-zA-Z0-9$_]/g, '_');
99105
}
100106

101107
/**
102108
* @param {RollupRenderedChunk} chunk
103109
* @param {RollupOutputOptions} outputOptions
110+
* @param {Array<NollupInternalModuleImport>} externalImports
104111
* @return {string}
105112
*/
106-
function createExternalImports (chunk, outputOptions) {
113+
function createExternalImports (chunk, outputOptions, externalImports) {
107114
let output = '';
108115
let { format, globals } = outputOptions;
109116

110-
output += chunk.imports.map(source => {
111-
let name = source.replace(/[\W]/g, '_');
112-
let specifiers = chunk.importedBindings[source];
117+
output += externalImports.map(ei => {
118+
let name = ei.source.replace(/[\W]/g, '_');
119+
let { source, specifiers } = ei;
113120

114121
// Bare external import
115122
if (specifiers.length === 0) {
@@ -119,10 +126,12 @@ function createExternalImports (chunk, outputOptions) {
119126
return `require('${source}');`
120127
}
121128

129+
130+
let iifeName = format === 'iife'? (globals[source] || getIIFEName(ei)) : '';
131+
122132
return specifiers.map(s => {
123-
let iifeName = format === 'iife'? (globals[source] || getIIFEName(source)) : '';
124133

125-
if (s === '*') {
134+
if (s.imported === '*') {
126135
if (format === 'es')
127136
return `import * as __nollup__external__${name}__ from '${source}';`;
128137
if (format === 'cjs' || format === 'amd')
@@ -131,7 +140,7 @@ function createExternalImports (chunk, outputOptions) {
131140
return `var __nollup__external__${name}__ = self.${iifeName};`
132141
}
133142

134-
if (s === 'default') {
143+
if (s.imported === 'default') {
135144
if (format === 'es')
136145
return `import __nollup__external__${name}__default__ from '${source}';`;
137146
if (format === 'cjs' || format === 'amd')
@@ -141,11 +150,11 @@ function createExternalImports (chunk, outputOptions) {
141150
}
142151

143152
if (format === 'es')
144-
return `import { ${s} as __nollup__external__${name}__${s}__ } from '${source}';`;
153+
return `import { ${s.imported} as __nollup__external__${name}__${s.imported}__ } from '${source}';`;
145154
if (format === 'cjs' || format === 'amd')
146-
return `var __nollup__external__${name}__${s}__ = require('${source}').${s};`
155+
return `var __nollup__external__${name}__${s.imported}__ = require('${source}').${s.imported};`
147156
if (format === 'iife')
148-
return `var __nollup__external__${name}__${s}__ = self.${iifeName}.${s};`
157+
return `var __nollup__external__${name}__${s.imported}__ = self.${iifeName}.${s.imported};`
149158
}).join('\n');
150159
}).join('\n');
151160

@@ -549,9 +558,10 @@ class NollupCodeGenerator {
549558
* @param {RollupOutputChunk} chunk
550559
* @param {RollupOutputOptions} outputOptions
551560
* @param {RollupConfigContainer} config
561+
* @param {Array<NollupInternalModuleImport>} externalImports
552562
* @return {string}
553563
*/
554-
onGenerateChunk (modules, chunk, outputOptions, config) {
564+
onGenerateChunk (modules, chunk, outputOptions, config, externalImports) {
555565
let files = Object.keys(chunk.modules).map(filePath => {
556566
let file = modules[filePath];
557567
return file.index + ':' + file.code;
@@ -564,7 +574,7 @@ class NollupCodeGenerator {
564574
if (chunk.isDynamicEntry) {
565575
return `
566576
${format === 'amd'? 'define(function (require, exports) {' : ''}
567-
${createExternalImports(chunk, outputOptions)}
577+
${createExternalImports(chunk, outputOptions, externalImports)}
568578
(function (global) {
569579
global.__nollup_dynamic_require_callback("${chunk.fileName}", ${entryIndex}, {${files}});
570580
})(typeof globalThis !== 'undefined'? globalThis : (
@@ -575,7 +585,7 @@ class NollupCodeGenerator {
575585
} else {
576586
return [
577587
format === 'amd'? 'define(function (require, exports) {' : '',
578-
createExternalImports(chunk, outputOptions),
588+
createExternalImports(chunk, outputOptions, externalImports),
579589
` ${(chunk.exports.length > 0 && (format === 'es' || format === 'amd'))? 'var __nollup_entry_exports = ' : ''}
580590
(function (modules, __nollup__global__) {
581591

lib/impl/NollupCompiler.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,17 @@ async function compileModule (context, filePath, parentFilePath, depth, emitted,
125125
if (!foundSource) {
126126
foundSource = {
127127
source: ei.source,
128-
specifiers: []
128+
specifiers: [],
129+
export: ei.export,
130+
external: true
129131
};
130132

131133
emitted.externalImports.push(foundSource);
132134
}
133135

134136
ei.specifiers.forEach(spec => {
135-
if (foundSource.specifiers.indexOf(spec.imported) === -1) {
136-
foundSource.specifiers.push(spec.imported);
137+
if (foundSource.specifiers.findIndex(s => s.imported === spec.imported) === -1) {
138+
foundSource.specifiers.push(spec);
137139
}
138140
});
139141
});
@@ -236,6 +238,7 @@ module.exports = {
236238
let bundleOutputTypes = /** @type {Object<String, string>} */ ({});
237239
let bundleDynamicImports = /** @type {Object<string, string[]>} */ ({});
238240
let bundleCirculars = [];
241+
let bundleExternalImports = /** @type {Object<string, NollupInternalModuleImport[]>} */ ({});
239242

240243
let invalidated = Object.keys(context.files).filter(filePath => context.files[filePath].invalidate);
241244

@@ -306,7 +309,7 @@ module.exports = {
306309
fileName: '',
307310
imports: emitted.externalImports.map(e => e.source),
308311
importedBindings: emitted.externalImports.reduce((acc, val) => {
309-
acc[val.source] = val.specifiers;
312+
acc[val.source] = val.specifiers.map(s => s.imported);
310313
return acc;
311314
}, {}),
312315
dynamicImports: [],
@@ -322,6 +325,7 @@ module.exports = {
322325
bundleOutputTypes[file] = 'entry';
323326
bundleDynamicImports[file] = emitted.dynamicImports;
324327
bundleCirculars = bundleCirculars.concat(emitted.circulars);
328+
bundleExternalImports[file] = emitted.externalImports;
325329
}
326330

327331
for (let i = 0; i < bundleEmittedChunks.length; i++) {
@@ -357,6 +361,7 @@ module.exports = {
357361

358362
bundleReferenceIdMap[chunk.referenceId] = bundleEntry;
359363
bundleCirculars = bundleCirculars.concat(emitted.circulars);
364+
bundleExternalImports[chunk.id] = emitted.externalImports;
360365
bundle.push(bundleEntry);
361366
}
362367
} catch (e) {
@@ -425,7 +430,12 @@ module.exports = {
425430
});
426431
});
427432

428-
bundleEntry.code = banner + '\n' + intro + '\n' + generator.onGenerateChunk(modules, bundleEntry, context.config.output, context.config) + '\n' + outro + '\n' + footer;
433+
bundleEntry.code =
434+
banner + '\n' +
435+
intro + '\n' +
436+
generator.onGenerateChunk(modules, bundleEntry, context.config.output, context.config, bundleExternalImports[bundleEntry.facadeModuleId]) + '\n' +
437+
outro + '\n' +
438+
footer;
429439

430440
await context.plugins.hooks.renderChunk(bundleEntry.code, bundleEntry, context.config.output);
431441
}

lib/impl/types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
/**
8383
* @typedef NollupInternalModuleImport
8484
* @property {string} source
85-
* @property {boolean} syntheticNamedExports
85+
* @property {boolean?} syntheticNamedExports
8686
* @property {boolean?} export
8787
* @property {NollupInternalModuleImportSpecifier[]} specifiers
8888
*/

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@
3737
"mocha-istanbul-ui": "^0.4.1",
3838
"proxyquire": "^2.0.1",
3939
"requirejs": "^2.3.6",
40-
"rollup": "^2.75.5"
40+
"rollup": "^2.77.0"
4141
}
4242
}

test/cases/Externals.js

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ let EXTERNAL_MODULES = {
6767
'readline': {
6868
clearLine: true
6969
},
70-
'DefaultModule': {
70+
'Default': {
7171
default: {
7272
prop: true
7373
}
@@ -86,6 +86,12 @@ let EXTERNAL_MODULES = {
8686
NamedExport1: 123,
8787
NamedExport2: 456
8888
},
89+
'MyLibrary': {
90+
NamedExport1: 123,
91+
},
92+
'MyLibraryOther': {
93+
NamedExport2: 456
94+
},
8995
'__globalModule': {
9096
NamedExport1: 123,
9197
NamedExport2: 456
@@ -287,7 +293,13 @@ describe('External', () => {
287293
external: ['DefaultModule']
288294
});
289295

290-
let { output } = await bundle.generate({ format });
296+
let { output } = await bundle.generate({
297+
format,
298+
globals: {
299+
'DefaultModule': 'Default'
300+
}
301+
});
302+
291303
let { globals } = await Evaluator.init(format, 'main.js', getModules(output, format), getGlobalScope({ }, format));
292304
expect(globals.result).to.equal(true);
293305
fs.reset();
@@ -417,12 +429,31 @@ describe('External', () => {
417429
let bundle = await nollup({
418430
input: './src/main.js',
419431
external: ['-iIFE-special+_Characters-Test$)('],
420-
output: {
421-
globals: {
422-
'-iIFE-special+_Characters-Test$)(': '__globalModule'
423-
}
432+
});
433+
434+
let { output } = await bundle.generate({
435+
format: 'iife',
436+
globals: {
437+
'-iIFE-special+_Characters-Test$)(': '__globalModule'
424438
}
425439
});
440+
let { globals } = await Evaluator.init('iife', 'main.js', output, getGlobalScope({ }, 'iife'));
441+
expect(globals.result).to.equal(true);
442+
fs.reset();
443+
});
444+
445+
it ('should use the default variable name as the name of the import', async () => {
446+
fs.stub('./src/main.js', () => `
447+
import MyLibrary from "my-library";
448+
import MyLibraryOther from "my-library-other";
449+
if (MyLibrary.NamedExport1 === 123 && MyLibraryOther.NamedExport2 === 456) {
450+
self.result = true;
451+
}
452+
`);
453+
454+
let bundle = await nollup({
455+
input: './src/main.js',
456+
});
426457

427458
let { output } = await bundle.generate({ format: 'iife' });
428459
let { globals } = await Evaluator.init('iife', 'main.js', output, getGlobalScope({ }, 'iife'));

test/cases/options/output-format.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ describe ('Options: output.format', () => {
513513

514514
describe('iife', () => {
515515
it ('should use externals from window', async () => {
516-
fs.stub('./src/main.js', () => 'import $ from "jquery";');
516+
fs.stub('./src/main.js', () => 'import jquery from "jquery";');
517517

518518
let bundle = await nollup({
519519
input: './src/main.js',
@@ -526,7 +526,7 @@ describe ('Options: output.format', () => {
526526

527527
expect(output[0].code.match(/import (.*?) from 'jquery'/)).to.be.null;
528528
expect(output[0].code.indexOf(`var __nollup__external__jquery__default__ = self.jquery && self.jquery.hasOwnProperty('default')? self.jquery.default : self.jquery;`) > -1).to.be.true;
529-
expect(output[0].code.indexOf(`var $ = __nollup__external__jquery__default__;`) > -1).to.be.true;
529+
expect(output[0].code.indexOf(`var jquery = __nollup__external__jquery__default__;`) > -1).to.be.true;
530530
fs.reset();
531531
});
532532

@@ -553,7 +553,7 @@ describe ('Options: output.format', () => {
553553
});
554554

555555
it ('should use externals from import for multiple files and duplicate imports', async () => {
556-
fs.stub('./src/other.js', () => `import { query } from "jquery"; import _ from 'lodash';`)
556+
fs.stub('./src/other.js', () => `import { query } from "jquery"; import lodash from 'lodash';`)
557557
fs.stub('./src/main.js', () => 'import "./other"; import { ajax } from "jquery";');
558558

559559
let bundle = await nollup({
@@ -570,7 +570,7 @@ describe ('Options: output.format', () => {
570570
expect(output[0].code.indexOf(`var __nollup__external__lodash__default__ = self.lodash && self.lodash.hasOwnProperty('default')? self.lodash.default : self.lodash;`) > -1).to.be.true;
571571
expect(output[0].code.indexOf(`var ajax = __nollup__external__jquery__ajax__;`) > -1).to.be.true;
572572
expect(output[0].code.indexOf(`var query = __nollup__external__jquery__query__;`) > -1).to.be.true;
573-
expect(output[0].code.indexOf(`var _ = __nollup__external__lodash__default__;`) > -1).to.be.true;
573+
expect(output[0].code.indexOf(`var lodash = __nollup__external__lodash__default__;`) > -1).to.be.true;
574574
fs.reset();
575575
});
576576

@@ -603,8 +603,8 @@ describe ('Options: output.format', () => {
603603
format: 'iife'
604604
});
605605

606-
expect(output[0].code.indexOf(`var __nollup__external__jquery__default__ = self.jquery && self.jquery.hasOwnProperty('default')? self.jquery.default : self.jquery;`) > -1).to.be.true;
607-
expect(output[0].code.indexOf(`var __nollup__external__jquery__ = self.jquery;`) > -1).to.be.true;
606+
expect(output[0].code.indexOf(`var __nollup__external__jquery__default__ = self.$ && self.$.hasOwnProperty('default')? self.$.default : self.$;`) > -1).to.be.true;
607+
expect(output[0].code.indexOf(`var __nollup__external__jquery__ = self.$;`) > -1).to.be.true;
608608
expect(output[0].code.indexOf('var $ = __nollup__external__jquery__default__;') > -1).to.be.true;
609609
expect(output[0].code.indexOf('var rest = __nollup__external__jquery__;') > -1).to.be.true;
610610
fs.reset();

0 commit comments

Comments
 (0)