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

Default export behavior when module "default" key is undefined #13017

Closed
soyuka opened this issue Dec 19, 2016 · 3 comments
Closed

Default export behavior when module "default" key is undefined #13017

soyuka opened this issue Dec 19, 2016 · 3 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@soyuka
Copy link

soyuka commented Dec 19, 2016

TypeScript Version: 2.1.4 / tried with current nightly yesterday

Linked issues :

rollup/rollup#1156
infernojs/inferno#596

Code

Inferno exports something like:

typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./inferno')) :
typeof define === 'function' && define.amd ? define(['exports', 'inferno'], factory) :(factory((global.Inferno = global.Inferno || {}),global.inferno));

In typescript, it is export default class Component{}.

When imported, you'll expect this to work:

import createElement from 'inferno-create-element'
import Component from 'inferno-component'

console.log(createElement)
console.log(Component)

But those will both be undefined because the typescript compiler exports something like:

console.log(inferno_create_element_1.default);
console.log(inferno_component_1.default);

I also tried to import as:

import * as createElement from 'inferno-create-element'
import * as Component from 'inferno-component'

Which does bring back the correct values, except their signature is now wrong and you can not use them as intended (for example class extend Component).

Reproduction
Here is a reproduction repository:

https://github.com/soyuka/repro-default-export

Clone and run bash init.sh.

Note that:

  • Inferno creator says typescript fixed this issue (I tried latest + next without success)
  • Rollup (which is used by inferno for umd bundle) says it might be a typescript issue
  • There is no difference with or without webpack, therefore it's definitely not a webpack issue

To me it's probably that typescript always expect a default key, which is why I made a proposal to add the following to rollup:

//add this and everything works:
if (typeof module !== 'undefined') {
    module.exports.default = module.exports
}

Would you be able to give me some details about the typescript expected behavior? Is this a rollup issue or a typescript one?

Thanks!

@soyuka soyuka changed the title Default export behavior when no module "default" key is undefined Default export behavior when module "default" key is undefined Dec 19, 2016
@RyanCavanaugh
Copy link
Member

The ES6 module semantics are very clear on these points:

  • import x from 'y' gets the default export from 'y'
  • import * as q from 'z' cannot possibly produce a q which can be legally invoked with new

It'd be incorrect for us to emit anything other than .default for the first situation and it's incorrect for us to allow you to try to new q or q() in the second situation.

If the top-level export of the inferno-create-element module is really a class or function, then it is not a compliant ES6 module and should not be imported with ES6 syntax. See http://stackoverflow.com/questions/39415661/why-cant-i-import-a-class-or-function-with-import-as-x-from-y . In this case, use import x = require('y'); syntax because this is a CommonJS-style module.

It's possible but unlikely that the allowSyntheticDefaultImports flag might help you. Worth mentioning just in case.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Dec 21, 2016
@soyuka
Copy link
Author

soyuka commented Dec 22, 2016

Thank you very much for this comprehensive answer, I'll check this out and report back. In the time being, I'm closing this.

@Andarist
Copy link
Contributor

Andarist commented Feb 6, 2018

Leaving this here if somebody is gonna stumble on this thread again when having troubles with setting up his/her build pipeline relaying on rollup.

From my point of view if you want to provide a structure that is consumable for your TS typings, you should simply use exports: 'named' in your projects (in rollup.config.js when bundling), instead of relaying on automatic behaviour.

Going further - if you do not enforcing CJS consumers to use require('your-lib').default instead of require('your-lib') you should just use additionally this babel plugin - https://github.com/59naga/babel-plugin-add-module-exports (only when transpiling to CJS, do not use it when transpiling to ESM format)

@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants