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

Fix UMD wrapper issues and refine wrappers #2600

Merged
merged 4 commits into from Dec 19, 2018
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
32 changes: 17 additions & 15 deletions src/finalisers/iife.ts
Expand Up @@ -31,9 +31,9 @@ export default function iife(

const { extend, name } = options;
const isNamespaced = name && name.indexOf('.') !== -1;
const possibleVariableAssignment = !extend && !isNamespaced;
const useVariableAssignment = !extend && !isNamespaced;

if (name && possibleVariableAssignment && !isLegal(name)) {
if (name && useVariableAssignment && !isLegal(name)) {
error({
code: 'ILLEGAL_IDENTIFIER_AS_NAME',
message: `Given name (${name}) is not legal JS identifier. If you need this you can try --extend option`
Expand All @@ -53,29 +53,31 @@ export default function iife(
});
}

if (extend) {
deps.unshift(`${thisProp(name)}${_}=${_}${thisProp(name)}${_}||${_}{}`);
args.unshift('exports');
} else if (namedExportsMode && hasExports) {
deps.unshift('{}');
args.unshift('exports');
if (namedExportsMode && hasExports) {
if (extend) {
deps.unshift(`${thisProp(name)}${_}=${_}${thisProp(name)}${_}||${_}{}`);
args.unshift('exports');
} else {
deps.unshift('{}');
args.unshift('exports');
}
}

const useStrict = options.strict !== false ? `${t}'use strict';${n}${n}` : ``;

let wrapperIntro = `(function${_}(${args})${_}{${n}${useStrict}`;
let wrapperIntro = `(function${_}(${args.join(`,${_}`)})${_}{${n}${useStrict}`;

if (hasExports && !extend) {
if (hasExports && (!extend || !namedExportsMode)) {
wrapperIntro =
(isNamespaced ? thisProp(name) : `${graph.varOrConst} ${name}`) + `${_}=${_}${wrapperIntro}`;
(useVariableAssignment ? `${graph.varOrConst} ${name}` : thisProp(name)) +
`${_}=${_}${wrapperIntro}`;
}

if (isNamespaced) {
wrapperIntro =
setupNamespace(name, 'this', false, options.globals, options.compact) + wrapperIntro;
if (isNamespaced && hasExports) {
wrapperIntro = setupNamespace(name, 'this', options.globals, options.compact) + wrapperIntro;
}

let wrapperOutro = `${n}${n}}(${deps}));`;
let wrapperOutro = `${n}${n}}(${deps.join(`,${_}`)}));`;

if (!extend && namedExportsMode && hasExports) {
wrapperOutro = `${n}${n}${t}return exports;${wrapperOutro}`;
Expand Down
47 changes: 31 additions & 16 deletions src/finalisers/shared/setupNamespace.ts
Expand Up @@ -4,7 +4,6 @@ import { property } from './sanitize';
export default function setupNamespace(
name: string,
root: string,
forAssignment: boolean,
globals: GlobalsOption,
compact: boolean
) {
Expand All @@ -14,24 +13,40 @@ export default function setupNamespace(
}

const _ = compact ? '' : ' ';
parts.pop();

let acc = root;
return (
parts
.map(
part => ((acc += property(part)), `${acc}${_}=${_}${acc}${_}||${_}{}${compact ? '' : ';'}`)
)
.join(compact ? ',' : '\n') + (compact && parts.length ? ';' : '\n')
);
}

export function assignToDeepVariable(
deepName: string,
root: string,
globals: GlobalsOption,
compact: boolean,
assignment: string
): string {
const _ = compact ? '' : ' ';
const parts = deepName.split('.');
if (globals) {
parts[0] = (typeof globals === 'function' ? globals(parts[0]) : globals[parts[0]]) || parts[0];
}
const last = parts.pop();

let acc = root;
if (forAssignment) {
return parts
.map(part => ((acc += property(part)), `${acc}${_}=${_}${acc}${_}||${_}{}`))
.concat(`${acc}${property(last)}`)
.join(`,${_}`);
} else {
return (
parts
.map(
part => (
(acc += property(part)), `${acc}${_}=${_}${acc}${_}||${_}{}${compact ? '' : ';'}`
)
)
.join(compact ? ',' : '\n') + (compact && parts.length ? ';' : '\n')
);
let deepAssignment = parts
.map(part => ((acc += property(part)), `${acc}${_}=${_}${acc}${_}||${_}{}`))
.concat(`${acc}${property(last)}`)
.join(`,${_}`)
.concat(`${_}=${_}${assignment}`);
if (parts.length > 0) {
deepAssignment = `(${deepAssignment})`;
}
return deepAssignment;
}
92 changes: 54 additions & 38 deletions src/finalisers/umd.ts
Expand Up @@ -6,20 +6,20 @@ import { compactEsModuleExport, esModuleExport } from './shared/esModuleExport';
import getExportBlock from './shared/getExportBlock';
import getInteropBlock from './shared/getInteropBlock';
import { keypath, property } from './shared/sanitize';
import setupNamespace from './shared/setupNamespace';
import { assignToDeepVariable } from './shared/setupNamespace';
import trimEmptyImports from './shared/trimEmptyImports';
import warnOnBuiltins from './shared/warnOnBuiltins';

function globalProp(name: string) {
function globalProp(name: string, globalVar: string) {
if (!name) return 'null';
return `global${keypath(name)}`;
return `${globalVar}${keypath(name)}`;
}

function safeAccess(name: string, compact: boolean) {
function safeAccess(name: string, globalVar: string, _: string) {
const parts = name.split('.');

let acc = 'global';
return parts.map(part => ((acc += property(part)), acc)).join(compact ? '&&' : ` && `);
let acc = globalVar;
return parts.map(part => ((acc += property(part)), acc)).join(`${_}&&${_}`);
}

export default function umd(
Expand All @@ -38,6 +38,8 @@ export default function umd(
) {
const _ = options.compact ? '' : ' ';
const n = options.compact ? '' : '\n';
const factoryVar = options.compact ? 'f' : 'factory';
const globalVar = options.compact ? 'g' : 'global';

if (hasExports && !options.name) {
error({
Expand All @@ -52,16 +54,20 @@ export default function umd(
const cjsDeps = dependencies.map(m => `require('${m.id}')`);

const trimmedImports = trimEmptyImports(dependencies);
const globalDeps = trimmedImports.map(module => globalProp(module.globalName));
const globalDeps = trimmedImports.map(module => globalProp(module.globalName, globalVar));
const factoryArgs = trimmedImports.map(m => m.name);

if (namedExportsMode && (hasExports || options.noConflict === true)) {
amdDeps.unshift(`'exports'`);
cjsDeps.unshift(`exports`);
globalDeps.unshift(
`${setupNamespace(options.name, 'global', true, options.globals, options.compact)}${_}=${_}${
options.extend ? `${globalProp(options.name)}${_}||${_}` : ''
}{}`
assignToDeepVariable(
options.name,
globalVar,
options.globals,
options.compact,
`${options.extend ? `${globalProp(options.name, globalVar)}${_}||${_}` : ''}{}`
)
);

factoryArgs.unshift('exports');
Expand All @@ -74,58 +80,68 @@ export default function umd(
(amdDeps.length ? `[${amdDeps.join(`,${_}`)}],${_}` : ``);

const define = amdOptions.define || 'define';

const cjsExport = !namedExportsMode && hasExports ? `module.exports${_}=${_}` : ``;
const defaultExport =
!namedExportsMode && hasExports
? `${setupNamespace(options.name, 'global', true, options.globals, options.compact)}${_}=${_}`
: '';

const useStrict = options.strict !== false ? `${_}'use strict';${n}` : ``;

let globalExport;
let iifeExport;

if (options.noConflict === true) {
const noConflictExportsVar = options.compact ? 'e' : 'exports';
let factory;

if (!namedExportsMode && hasExports) {
factory = `var exports${_}=${_}factory(${globalDeps});`;
factory = `var ${noConflictExportsVar}${_}=${_}${assignToDeepVariable(
options.name,
globalVar,
options.globals,
options.compact,
`${factoryVar}(${globalDeps.join(`,${_}`)})`
)};`;
} else if (namedExportsMode) {
const module = globalDeps.shift();
factory =
`var exports${_}=${_}${module};${n}` +
`${t}${t}factory(${['exports'].concat(globalDeps)});`;
`var ${noConflictExportsVar}${_}=${_}${module};${n}` +
`${t}${t}${factoryVar}(${[noConflictExportsVar].concat(globalDeps).join(`,${_}`)});`;
}
globalExport =
`(function()${_}{${n}` +
`${t}${t}var current${_}=${_}${safeAccess(options.name, options.compact)};${n}` +
iifeExport =
`(function${_}()${_}{${n}` +
`${t}${t}var current${_}=${_}${safeAccess(options.name, globalVar, _)};${n}` +
`${t}${t}${factory}${n}` +
`${t}${t}${globalProp(options.name)}${_}=${_}exports;${n}` +
`${t}${t}exports.noConflict${_}=${_}function()${_}{${_}` +
`${globalProp(options.name)}${_}=${_}current;${_}return exports${
`${t}${t}${noConflictExportsVar}.noConflict${_}=${_}function${_}()${_}{${_}` +
`${globalProp(options.name, globalVar)}${_}=${_}current;${_}return ${noConflictExportsVar}${
options.compact ? '' : '; '
}};${n}` +
`${t}})()`;
`${t}}())`;
} else {
globalExport = `${defaultExport}factory(${globalDeps})`;
iifeExport = `${factoryVar}(${globalDeps.join(`,${_}`)})`;
if (!namedExportsMode && hasExports) {
iifeExport = assignToDeepVariable(
options.name,
globalVar,
options.globals,
options.compact,
iifeExport
);
}
}

const iifeNeedsGlobal = hasExports || (options.noConflict === true && namedExportsMode);
const globalParam = iifeNeedsGlobal ? `global,${_}` : '';
const globalArg = iifeNeedsGlobal
? `typeof self${_}!==${_}'undefined'${_}?${_}self${_}:${_}this,${_}`
: '';
const iifeNeedsGlobal =
hasExports || (options.noConflict === true && namedExportsMode) || globalDeps.length > 0;
const globalParam = iifeNeedsGlobal ? `${globalVar},${_}` : '';
const globalArg = iifeNeedsGlobal ? `this,${_}` : '';
const iifeStart = iifeNeedsGlobal ? `(${globalVar}${_}=${_}${globalVar}${_}||${_}self,${_}` : '';
const iifeEnd = iifeNeedsGlobal ? ')' : '';
const cjsIntro = iifeNeedsGlobal
? `${t}typeof exports${_}===${_}'object'${_}&&${_}typeof module${_}!==${_}'undefined'${_}?` +
`${_}${cjsExport}factory(${cjsDeps.join(`,${_}`)})${_}:${n}`
`${_}${cjsExport}${factoryVar}(${cjsDeps.join(`,${_}`)})${_}:${n}`
: '';

const wrapperIntro =
`(function${_}(${globalParam}factory)${_}{${n}` +
`(function${_}(${globalParam}${factoryVar})${_}{${n}` +
cjsIntro +
`${t}typeof ${define}${_}===${_}'function'${_}&&${_}${define}.amd${_}?${_}${define}(${amdParams}factory)${_}:${n}` +
`${t}${globalExport};${n}` +
`}(${globalArg}function${_}(${factoryArgs})${_}{${useStrict}${n}`;
`${t}typeof ${define}${_}===${_}'function'${_}&&${_}${define}.amd${_}?${_}${define}(${amdParams}${factoryVar})${_}:${n}` +
`${t}${iifeStart}${iifeExport}${iifeEnd};${n}` +
`}(${globalArg}function${_}(${factoryArgs.join(', ')})${_}{${useStrict}${n}`;

const wrapperOutro = n + n + '}));';

Expand Down
4 changes: 2 additions & 2 deletions test/cli/samples/module-name/_expected.js
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.myBundle = factory();
}(typeof self !== 'undefined' ? self : this, function () { 'use strict';
(global = global || self, global.myBundle = factory());
}(this, function () { 'use strict';

var main = 42;

Expand Down
11 changes: 5 additions & 6 deletions test/cli/samples/no-conflict/_expected.js
@@ -1,13 +1,12 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(function() {
(global = global || self, (function () {
var current = global.conflictyName;
var exports = factory();
global.conflictyName = exports;
exports.noConflict = function() { global.conflictyName = current; return exports; };
})();
}(typeof self !== 'undefined' ? self : this, function () { 'use strict';
var exports = global.conflictyName = factory();
exports.noConflict = function () { global.conflictyName = current; return exports; };
}()));
}(this, function () { 'use strict';

var main = {};

Expand Down
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory(global.bundle = {});
}(typeof self !== 'undefined' ? self : this, function (exports) { 'use strict';
(global = global || self, factory(global.bundle = {}));
}(this, function (exports) { 'use strict';

var buffer = new ArrayBuffer( 8 );

Expand Down
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory(global.myModule = {});
}(typeof self !== 'undefined' ? self : this, function (exports) { 'use strict';
(global = global || self, factory(global.myModule = {}));
}(this, function (exports) { 'use strict';

exports.Foo = class Foo {};
exports.Foo = lol( exports.Foo );
Expand Down
4 changes: 2 additions & 2 deletions test/form/samples/assignment-to-exports/_expected/umd.js
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory(global.bundle = {});
}(typeof self !== 'undefined' ? self : this, function (exports) { 'use strict';
(global = global || self, factory(global.bundle = {}));
}(this, function (exports) { 'use strict';

// Unassigned export
var foo1;
Expand Down
4 changes: 2 additions & 2 deletions test/form/samples/catch-parameter-shadowing/_expected/umd.js
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory(global.bundle = {});
}(typeof self !== 'undefined' ? self : this, function (exports) { 'use strict';
(global = global || self, factory(global.bundle = {}));
}(this, function (exports) { 'use strict';

const e = 2.7182818284;

Expand Down
2 changes: 1 addition & 1 deletion test/form/samples/compact/_expected/umd.js
@@ -1,4 +1,4 @@
(function(global,factory){typeof exports==='object'&&typeof module!=='undefined'?module.exports=factory(require('external')):typeof define==='function'&&define.amd?define(['external'],factory):global.foo=factory(global.x);}(typeof self!=='undefined'?self:this,function(x){'use strict';x=x&&x.hasOwnProperty('default')?x['default']:x;var self = {get default(){return foo$$1}};if(typeof Symbol!=='undefined'&&Symbol.toStringTag)Object.defineProperty(self,Symbol.toStringTag,{value:'Module'});else Object.defineProperty(self,'toString',{value:function(){return'[object Module]';}});/*#__PURE__*/Object.freeze(self);console.log(self);
(function(g,f){typeof exports==='object'&&typeof module!=='undefined'?module.exports=f(require('external')):typeof define==='function'&&define.amd?define(['external'],f):(g=g||self,g.foo=f(g.x));}(this,function(x){'use strict';x=x&&x.hasOwnProperty('default')?x['default']:x;var self = {get default(){return foo$$1}};if(typeof Symbol!=='undefined'&&Symbol.toStringTag)Object.defineProperty(self,Symbol.toStringTag,{value:'Module'});else Object.defineProperty(self,'toString',{value:function(){return'[object Module]';}});/*#__PURE__*/Object.freeze(self);console.log(self);
function foo$$1 () {
console.log( x );
}
Expand Down
4 changes: 2 additions & 2 deletions test/form/samples/computed-properties/_expected/umd.js
@@ -1,8 +1,8 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory(global.computedProperties = {});
}(typeof self !== 'undefined' ? self : this, function (exports) { 'use strict';
(global = global || self, factory(global.computedProperties = {}));
}(this, function (exports) { 'use strict';

var foo = 'foo';
var bar = 'bar';
Expand Down
4 changes: 2 additions & 2 deletions test/form/samples/conflicting-imports/_expected/iife.js
@@ -1,8 +1,8 @@
(function (foo,bar) {
(function (foo, bar) {
'use strict';

console.log( bar.a );

console.log( foo.a );

}(foo,bar));
}(foo, bar));
7 changes: 4 additions & 3 deletions test/form/samples/conflicting-imports/_expected/umd.js
@@ -1,7 +1,8 @@
(function (factory) {
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('foo'), require('bar')) :
typeof define === 'function' && define.amd ? define(['foo', 'bar'], factory) :
factory(global.foo,global.bar);
}(function (foo,bar) { 'use strict';
(global = global || self, factory(global.foo, global.bar));
}(this, function (foo, bar) { 'use strict';

console.log( bar.a );

Expand Down