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

Proposal: export as namespace for UMD module output #26532

Open
saschanaz opened this issue Aug 18, 2018 · 4 comments
Open

Proposal: export as namespace for UMD module output #26532

saschanaz opened this issue Aug 18, 2018 · 4 comments
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@saschanaz
Copy link
Contributor

saschanaz commented Aug 18, 2018

Current problem

TypeScript supports UMD output but does not support exporting as a global namespace.

Syntax

  NamespaceExportDeclaration:
   exportasnamespaceIdentifierPath

Behavior

export var x = 0;
export function y() {}
export default {};
export as namespace My.Custom.Namespace;

// emits:

(function (global, factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
  }
  else if (typeof define === "function" && define.amd) {
    define(["require", "exports"], factory);
  }
  else {
    global.My = global.My || {};
    global.My.Custom = global.My.Custom || {};
    global.My.Custom.Namespace = global.My.Custom.Namespace || {};
    var exports = global.My.Custom.Namespace;
    factory(global.require, exports);
  }
})(this, function (require, exports) {
  "use strict";
  exports.__esModule = true;
  exports.x = 0;
  function y() { }
  exports.y = y;
  exports["default"] = {};
});

Note

  • This proposal basically follows Babel behavior.
  • Importing any module without a module loader will throw in this proposal. A further extension may use global namespaces as Babel does.
  • Babel overwrites on the existing namespace whereas this proposal extends the existing one, as TS namespace does.
  • Rollup has a special behavior where export default X works like CommonJS module.exports = X whereas this proposal does not.

Prior arts: Babel exactGlobals, Webpack multi part library, Rollup output.name option with namespace support

See also

#8436
#10907
#20990

@kitsonk
Copy link
Contributor

kitsonk commented Aug 18, 2018

Personal opinion, is that because this expression level syntax would only apply to UMD modules, that it is "dangerous" to deal with this like that. Because what would you emit for AMD, CommonJS or ES Modules? Having syntax that is only valid in one module format feels very anti-pattern for TypeScript.

I would think that a triple slash directive would be a better way of solving this. There is already the AMD directive:

///<amd-module name="NamedModule"/>

So why not just extend that to UMD and follow the suggestion above:

///<umd-module name="foo.bar.baz"/>

@saschanaz
Copy link
Contributor Author

saschanaz commented Aug 19, 2018

The umd-module directive would also work, but maybe not very natural given that TS is already using export as namespace in d.ts files, again only for UMD modules.

export var x = 3;
export as namespace Foo;
export declare var x: number;
export as namespace Foo; // same syntax!

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Aug 20, 2018
@weswigham
Copy link
Member

Related: #20990

@cmerighi
Copy link

cmerighi commented May 28, 2019

I'd take this to extremes wondering about straight transpilation of modules into namespaces (global objects) given a shape/schema defined in an entry point:

// browser-index.ts
import * as _Core from "./core/index";
import * as _Components from "./components/index";

export namespace UI {
    export import MyCoreThing = _Core.MyCoreThing;
}

export namespace Components {
    export namespace UI {
        export import MyComponentThing = _Components.MyComponentThing;
    }
}

export as namespace Vendor.Awesomeness; // <- dots should be allowed because I'm lazy.

When compiling against that, I'd expect to get everything bundled - with coherent aside typings - into Vendor.Awesomeness.UI / Vendor.Awesomeness.Components.UI globals (augmenting the already-existing ones, if any).
I could then consume:

<script>
var coreThing = new Vendor.Awesomeness.UI.MyCoreThing();
var componentThing = new Vendor.Awesomeness.Components.UI.MyComponentThing();
</script>

That would be very useful for granular libraries distribution (e.g. webcomponent libs):

  • @vendor/awesomeness-core
  • @vendor/awesomeness-ui
  • @vendor/awesomeness-maps
  • @vendor/awesomeness-charts
    ...
  • @vendor/awesomeness-3d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants