diff --git a/packages/babel-plugin-transform-es2015-modules-umd/README.md b/packages/babel-plugin-transform-es2015-modules-umd/README.md index 823cd428fb..9af5b210c0 100644 --- a/packages/babel-plugin-transform-es2015-modules-umd/README.md +++ b/packages/babel-plugin-transform-es2015-modules-umd/README.md @@ -36,7 +36,7 @@ as `global.Promise` rather than `global.es6Promise`. This can be accommodated by #### Default semantics -There are a couple things to note about the default semantics. +There are a few things to note about the default semantics. _First_, this transform uses the [basename](https://en.wikipedia.org/wiki/Basename) of each import to generate @@ -88,9 +88,11 @@ This means that if you specify an override as a member expression like: this will _not_ transpile to `factory(global.fizz.buzz)`. Instead, it will transpile to `factory(global.fizzBuzz)` based on the logic in `toIdentifier`. +_Third_, you cannot override the exported global name. + #### More flexible semantics with `exactGlobals: true` -Both of these behaviors can limit the flexibility of the `globals` map. To +All of these behaviors can limit the flexibility of the `globals` map. To remove these limitations, you can set the `exactGlobals` option to `true`. Doing this instructs the plugin to: @@ -99,6 +101,8 @@ the global names 2. skip passing `globals` overrides to the `toIdentifier` function. Instead, they are used exactly as written, so you will get errors if you do not use valid identifiers or valid uncomputed (dot) member expressions. +3. allow the exported global name to be overridden via the `globals` map. Any +override must again be a valid identifier or valid member expression. Thus, if you set `exactGlobals` to `true` and do not pass any overrides, the first example of: @@ -132,6 +136,33 @@ then it'll transpile to: factory(global.fooBAR, global.mylib.fooBar) ``` +Finally, with the plugin options set to: + +```json +{ + "plugins": [ + "external-helpers", + ["transform-es2015-modules-umd", { + "globals": { + "my/custom/module/name": "My.Custom.Module.Name" + }, + "exactGlobals": true + }] + ], + "moduleId": "my/custom/module/name" +} +``` + +it will transpile to: + +```js +factory(mod.exports); +global.My = global.My || {}; +global.My.Custom = global.My.Custom || {}; +global.My.Custom.Module = global.My.Custom.Module || {}; +global.My.Custom.Module.Name = mod.exports; +``` + ### Via CLI ```sh diff --git a/packages/babel-plugin-transform-es2015-modules-umd/src/index.js b/packages/babel-plugin-transform-es2015-modules-umd/src/index.js index cbe8cae0ee..f672e618fc 100644 --- a/packages/babel-plugin-transform-es2015-modules-umd/src/index.js +++ b/packages/babel-plugin-transform-es2015-modules-umd/src/index.js @@ -3,6 +3,17 @@ import { basename, extname } from "path"; import template from "babel-template"; +let buildPrerequisiteAssignment = template(` + GLOBAL_REFERENCE = GLOBAL_REFERENCE || {} +`); + +let buildGlobalExport = template(` + var mod = { exports: {} }; + factory(BROWSER_ARGUMENTS); + PREREQUISITE_ASSIGNMENTS + GLOBAL_TO_ASSIGN = mod.exports; +`); + let buildWrapper = template(` (function (global, factory) { if (typeof define === "function" && define.amd) { @@ -10,9 +21,7 @@ let buildWrapper = template(` } else if (typeof exports !== "undefined") { factory(COMMON_ARGUMENTS); } else { - var mod = { exports: {} }; - factory(BROWSER_ARGUMENTS); - global.GLOBAL_ARG = mod.exports; + GLOBAL_EXPORT } })(this, FUNC); `); @@ -94,14 +103,45 @@ export default function ({ types: t }) { } }); - let globalArg = t.identifier(t.toIdentifier(moduleName ? moduleName.value : this.file.opts.basename)); + let moduleNameOrBasename = moduleName ? moduleName.value : this.file.opts.basename; + let globalToAssign = t.memberExpression( + t.identifier("global"), t.identifier(t.toIdentifier(moduleNameOrBasename)) + ); + let prerequisiteAssignments = null; + + if (state.opts.exactGlobals) { + let globalName = browserGlobals[moduleNameOrBasename]; + + if (globalName) { + if (globalName.indexOf(".") > -1) { + prerequisiteAssignments = []; + + let members = globalName.split("."); + let namespacedProperties = members.slice(1).reduce((accum, curr, index) => { + let prerequisiteAssignment = buildPrerequisiteAssignment({ GLOBAL_REFERENCE: accum[index] }); + prerequisiteAssignments.push(prerequisiteAssignment); + accum.push(t.memberExpression(accum[index], t.identifier(curr))); + return accum; + }, [t.memberExpression(t.identifier("global"), t.identifier(members[0]))]); + + globalToAssign = namespacedProperties[namespacedProperties.length -1]; + } else { + globalToAssign = t.memberExpression(t.identifier("global"), t.identifier(globalName)); + } + } + } + + let globalExport = buildGlobalExport({ + BROWSER_ARGUMENTS: browserArgs, + PREREQUISITE_ASSIGNMENTS: prerequisiteAssignments, + GLOBAL_TO_ASSIGN: globalToAssign + }); last.replaceWith(buildWrapper({ MODULE_NAME: moduleName, - BROWSER_ARGUMENTS: browserArgs, AMD_ARGUMENTS: amdArgs, COMMON_ARGUMENTS: commonArgs, - GLOBAL_ARG: globalArg, + GLOBAL_EXPORT: globalExport, FUNC: func })); } diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/actual.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/actual.js new file mode 100644 index 0000000000..7a4e8a723a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/actual.js @@ -0,0 +1 @@ +export default 42; diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/expected.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/expected.js new file mode 100644 index 0000000000..9000a0b8bd --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/expected.js @@ -0,0 +1,21 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("my custom module name", ["exports"], factory); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.foo = global.foo || {}; + global.foo.bar = mod.exports; + } +})(this, function (exports) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.default = 42; +}); diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/options.json b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/options.json new file mode 100644 index 0000000000..23eb69e3b8 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-namespace/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + "external-helpers", + ["transform-es2015-modules-umd", { + "globals": { + "my custom module name": "foo.bar" + }, + "exactGlobals": true + }] + ], + "moduleId": "my custom module name" +} diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/actual.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/actual.js new file mode 100644 index 0000000000..7a4e8a723a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/actual.js @@ -0,0 +1 @@ +export default 42; diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/expected.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/expected.js new file mode 100644 index 0000000000..52ab4409c0 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/expected.js @@ -0,0 +1,23 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("my custom module name", ["exports"], factory); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.foo = global.foo || {}; + global.foo.bar = global.foo.bar || {}; + global.foo.bar.baz = global.foo.bar.baz || {}; + global.foo.bar.baz.qux = mod.exports; + } +})(this, function (exports) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.default = 42; +}); diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/options.json b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/options.json new file mode 100644 index 0000000000..ad97739f25 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global-in-very-nested-namespace/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + "external-helpers", + ["transform-es2015-modules-umd", { + "globals": { + "my custom module name": "foo.bar.baz.qux" + }, + "exactGlobals": true + }] + ], + "moduleId": "my custom module name" +} diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/actual.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/actual.js new file mode 100644 index 0000000000..7a4e8a723a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/actual.js @@ -0,0 +1 @@ +export default 42; diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/expected.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/expected.js new file mode 100644 index 0000000000..88c2787a3a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/expected.js @@ -0,0 +1,20 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("my custom module name", ["exports"], factory); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.baz = mod.exports; + } +})(this, function (exports) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.default = 42; +}); diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/options.json b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/options.json new file mode 100644 index 0000000000..88df10bb74 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-id-with-overridden-global/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + "external-helpers", + ["transform-es2015-modules-umd", { + "globals": { + "my custom module name": "baz" + }, + "exactGlobals": true + }] + ], + "moduleId": "my custom module name" +} diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/actual.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/actual.js new file mode 100644 index 0000000000..7a4e8a723a --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/actual.js @@ -0,0 +1 @@ +export default 42; diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/expected.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/expected.js new file mode 100644 index 0000000000..777602f707 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/expected.js @@ -0,0 +1,20 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("umd/module-name-with-overridden-global/expected", ["exports"], factory); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.baz = mod.exports; + } +})(this, function (exports) { + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.default = 42; +}); diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/options.json b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/options.json new file mode 100644 index 0000000000..8546968383 --- /dev/null +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/module-name-with-overridden-global/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + "external-helpers", + ["transform-es2015-modules-umd", { + "globals": { + "umd/module-name-with-overridden-global/expected": "baz" + }, + "exactGlobals": true + }] + ], + "moduleIds": true +}