tsdx: Default export not output as expected -- missing __esModule

Current Behavior

TSDX doesn’t seem to have the expected output when building a package with a default export. The type definitions are output as expected, but the resulting .js file actually exports as { default: /* value */ }. I’ve created a minimal, reproducible example at rtbenfield/tsdx-default-export bootstrapped from tsdx create. This is my first time using TSDX and it is possible I am just doing something incorrectly.

In the repo mentioned above, I changed the sum function to be a default export, then added output.test.ts which imports directly from dist instead of src. output.test.ts logs the value of import sum from "../dist" and is showing sum to be { default: ... } instead of the actual function.

Expected behavior

The .js output files in dist can be consumed as default exports (ex. import sum from "my-module") if the source file utilized default exports.

Suggested solution(s)

Unsure, but willing to investigate if this is confirmed to be an issue. I know Webpack, but not Rollup, so it could be a good excuse for me to get some experience with it.

Additional context

Nothing relevant that I know of.

Your environment

Software Version(s)
TSDX 0.7.2
TypeScript 3.5.2
Browser N/A
npm/Yarn 6.9.0 / 1.16.0
Operating System Windows 10 Pro 1903

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 10
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Or just don’t use this devil syntax. Named exports do the work better.

Ran into this issue today. It’s not that I (and some others) want to use Default Export but because some other tools require Default Export to work, namely Mocha Custom Reporter.

I was just burned by this as well. I know that’s not helpful feedback, but I wanted to ping this issue again so it gets attention. This is sort of an Achilles heel to this tool at the moment.

I realized earlier today that there is a workaround for this in tsdx.config.js (added in the Aug 27th v0.9 release):

module.exports = {
  rollup(config, options) {
    config.output.esModule = true
    return config
  }
}

My fix got merged today and should be out whenever the next release is cut, but in the meantime or for slightly older versions of tsdx, could use that workaround.

@nartc the workaround that @kunukn listed isn’t entirely compatible.

It’ll make const myThing = require('myThing') work for CJS users, but now the ESM build won’t work. You can add module.exports = myThing in addition to export default myThing and then it seems to work for ESM (but I have no idea how consistent that is as it’s mixing CJS syntax with ESM syntax).

BUT if you use module.exports = myThing, then CJS users can only use this one export. You can’t add keyed exports for CJS users that way – CJS doesn’t have named exports, it just exports one thing. exports.default is how transpilers and bundlers have resolved that, but that means you have to do const { default: myThing } = require('myThing') in CJS. CJS and ESM are fundamentally incompatible; this is one of the reasons why Node has had trouble adopting it for years (not to mention static vs dynamic, sync/async, etc, etc – can read a brief, somewhat out-of-date summary on that topic here). Note that most users will probably be CJS users as most tooling does in fact transpile things down, particularly because Node only supports ESM in newer versions, and at that, only behind the --experimental-modules flag.

The __esModule property is what tells a transpiler that:

import myThing from 'myThing'

should transpile to

const { default: myThing } = require('myThing')

and not

const myThing = require('myThing')

As I’ve said in my above comments, the lack of __esModule is the root cause of this problem. And my fix in #327 resolves that.