egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
9.29k stars 223 forks source link

esModuleInterop not working #1078

Open clay-risser opened 10 months ago

clay-risser commented 10 months ago

I am importing a module with an esModule export like below.

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = SomeNpmModule;

I import the module in my typscript code.

import SomeNpmModule from 'some-npm-module'

This gets transpiled to the following when I run tsup

const SomeNpmModule = require('some-npm-module');

Now when I use SomeNpmModule, it is no longer SomeNpmModule, but { default: SomeNpmModule }.

How can I prevent this from happening.

Ideally tsup should generate the following code when using a default import, but it doesn't.

const SomeNpmModule = require('some-npm-module').default;

tsup.config.ts

import { defineConfig } from 'tsup';

export default defineConfig({
  bundle: true,
  clean: true,
  dts: true,
  entry: ['src/**/*.ts?(x)'],
  entryPoints: ['src/index.ts'],
  format: ['cjs', 'esm'],
  minify: false,
  outDir: 'lib',
  publicDir: './public',
  skipNodeModulesBundle: true,
  splitting: true,
  target: 'es5',
});

tsconfig.json

{
  "compilerOptions": {
    "allowJs": false,
    "allowSyntheticDefaultImports": true,
    "baseUrl": ".",
    "checkJs": false,
    "composite": true,
    "downlevelIteration": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "importHelpers": true,
    "incremental": true,
    "jsx": "react",
    "lib": ["ES2022", "DOM", "ESNext"],
    "module": "CommonJS",
    "moduleResolution": "Node",
    "noEmitOnError": false,
    "noImplicitAny": false,
    "noImplicitReturns": false,
    "noUncheckedIndexedAccess": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "preserveConstEnums": true,
    "preserveSymlinks": true,
    "removeComments": true,
    "resolveJsonModule": true,
    "rootDir": ".",
    "skipLibCheck": true,
    "sourceMap": false,
    "strictNullChecks": true,
    "target": "ES2022",
    "types": ["node"],
    "useUnknownInCatchVariables": false
  },
  "exclude": ["_"],
  "typeAcquisition": {
    "enable": true
  }
}

Upvote & Fund

Fund with Polar

foxaltus commented 2 months ago

Yeah, I have also noticed that tsup struggles with CJS modules that have a default export (exports.default=...).

Namely I've had issues with axios (https://github.com/axios/axios/issues/6591) and @react-hook/resize-observer. When my bundle ends up loading their CJS version, the .default export is not used, causing errors such as index.mjs:315 Uncaught (in promise) TypeError: axios__WEBPACK_IMPORTED_MODULE_0__.create is not a function (should be axios__WEBPACK_IMPORTED_MODULE_0__.default.create).

I am not sure whether this can be controlled with tsup settings, but the only workaround I found was to bundle the problematic packages using this:

import { defineConfig } from 'tsup';

export default defineConfig({
  // ...
  noExternal: ['axios','@react-hook/resize-observer'],
});

Note that axios has other issues, and you also need to patch their exports in package.json to avoid referencing node modules... (https://github.com/axios/axios/issues/5495), but that's another story...