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

Possible to have export default emit as module.exports #572

Closed
alii opened this issue Feb 19, 2022 · 14 comments · Fixed by #947
Closed

Possible to have export default emit as module.exports #572

alii opened this issue Feb 19, 2022 · 14 comments · Fixed by #947
Labels

Comments

@alii
Copy link

alii commented Feb 19, 2022

I know it's not the preferred way of having a default export, but it would save a lot of time if this would be possible. I'm writing an ESLint plugin and currently cannot import the plugin into a CJS file because the module is exported as module.exports.default rather than simply module.exports.

Have only come across this issue which I wasn't able to find a way to implement it properly: #283 and also #255 but I got the warnings below:
image

Thanks!

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar
@paambaati
Copy link

+1. It isn't obvious what the fix is when trying to write modules with export default ... with CJS output.

@egoist
Copy link
Owner

egoist commented Mar 7, 2022

You can re-export it in another file:

module.exports = require('./dist/index').default

And use this file in the main field in package.json instead

@paambaati
Copy link

FWIW, I solved this by adding this to my tsup config –

import { defineConfig } from 'tsup'

export default defineConfig({
  splitting: false,
  sourcemap: false,
  minify: true,
  clean: true,
+  esbuildOptions: (options) => {
+   options.footer = {
+    // This will ensure we can continue writing this plugin
+      // as a modern ECMA module, while still publishing this as a CommonJS
+      // library with a default export, as that's how ESLint expects plugins to look.
+      // @see https://github.com/evanw/esbuild/issues/1182#issuecomment-1011414271
+      js: 'module.exports = module.exports.default;',
+    }
  },
  entry: ['src/index.ts'],
})

See getoslash/eslint-plugin-tap#36 for reference.

@lvjiaxuan
Copy link

You can re-export it in another file:

module.exports = require('./dist/index').default

And use this file in the main field in package.json instead

We can manually do that in our personal file, but maybe in some runtime env like ESlint couldn't do that.

@lvjiaxuan
Copy link

I know it's not the preferred way of having a default export, but it would save a lot of time if this would be possible. I'm writing an ESLint plugin and currently cannot import the plugin into a CJS file because the module is exported as module.exports.default rather than simply module.exports.

Have only come across this issue which I wasn't able to find a way to implement it properly: #283 and also #255 but I got the warnings below: image

Thanks!

I am wondering why it's not the preferred way of having a default export. Could you explain any arguments for me, thanks~~

@u3u
Copy link

u3u commented May 4, 2023

Everyone, I created a library of fix-tsup-cjs to solve this problem. It can also fix d.ts (export =)
Just modify your build script to tsup && npx fix-tsup-cjs 🎉

Related issues: #255 #283 #338 #572 #710
/cc @pushkine @privatenumber @tbnritzdoge @yaquawa

@github-actions
Copy link

github-actions bot commented Aug 2, 2023

🎉 This issue has been resolved in version 7.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@psirenny
Copy link

Should this issue be closed? I find that I still need the module.exports = module.exports.default workaround. The --cjsInterop flag doesn't set module exports to the default value even in modules with just a default export.

@sxzz
Copy link
Collaborator

sxzz commented Aug 15, 2023

Could you please provide a minimum reproduction repo?

@psirenny
Copy link

Here's a GitHub repo that reproduces the issue: https://github.com/psirenny/tsup-cjs-default-export

The source directory has a module exporting a default string. There's a test.cjs file that imports from the built module. It expects to import a string but instead imports a { default: [Getter] }.

@sxzz
Copy link
Collaborator

sxzz commented Aug 16, 2023

@psirenny Because of issue evanw/esbuild#3281, we have to also enable --splitting flag as a workaround.

@psirenny
Copy link

we have to also enable --splitting flag as a workaround.

Aha, that does indeed do the trick. Thanks for explaining that!

@Mintnoii
Copy link

Mintnoii commented Feb 5, 2024

@sxzz --splitting does work indeed, but I'm not quite sure why enabling code splitting resolves this issue. Additionally, the documentation section on --cjsinterop doesn't explicitly mention the need to use --splitting concurrently. Could you briefly explain its underlying mechanism? Thank you very much!

@sxzz
Copy link
Collaborator

sxzz commented Feb 5, 2024

See evanw/esbuild#3281. In CJS mode, esbuild didn't generate valid export metadata. I think it's a bug of esbuild. So it blocked using cjsinterop in CJS.
But with --splitting flag, tsup will treat CJS as ESM at first then convert ESM back into CJS. So this tricky way can solve the problem.

For docs, maybe someone can submit a PR for mentioned that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants