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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

targeting CJS and ESM modules #107

Closed
bcoe opened this issue Aug 1, 2020 · 6 comments
Closed

targeting CJS and ESM modules #107

bcoe opened this issue Aug 1, 2020 · 6 comments
Labels

Comments

@bcoe
Copy link

bcoe commented Aug 1, 2020

Question

Hello @wessberg, first of thank you for the wonderful utility, this helped unblock my project to target ESM/CJS with yargs-parser 馃挴

Here's what I'm tying to figure out. I've created a module that uses tsc to target ESM, and uses rollup-plugin-ts to target CJS.

In my index I have:

export default yargsParser

This works well for my compilation to ESM, which maintains the same export, but I end up with the following syntax when using rollup-plugin-ts:

export { yargsParser as default };

I would rather than the export be:

export = yargsParser;

As I believe this is the best way to keep yargs-parser's existing API surface.

Is there a configuration setting that would facilitate this?

@wessberg
Copy link
Owner

wessberg commented Aug 5, 2020

Hey there. To my understanding, if you want to generate ExportAssignments following the special export = ... form in TypeScript, the source code needs to follow the following structure:

// source
export = function myFunction(...) {
    ...
}

If you write export default function myFunction(...) or export {myFunction as default}, you're saying to TypeScript that you're working with ESM-based default exports, whereas export = function myFunction generates assignments directly to the exports object, CommonJS-style. You have to pick one or the other. It is two fundamentally different approaches.

However, export = ... won't actually work with rollup-plugin-ts since it is configured to always generate ESM such that Rollup can understand the module structure and construct a proper dependency graph. You can then decide via Rollup's output options which module format to target. The problem is, however, that export = ... syntax will throw when TypeScript isn't targeting CommonJS.

I don't think there's any way around this without allowing targeting CommonJS internally which would lead to the plugin passing back CommonJS modules to Rollup, but this is to be avoided at all costs.

I'm aware of this problem and thinking about potential workarounds. But unfortunately this isn't possible as of yet.

@bcoe
Copy link
Author

bcoe commented Aug 8, 2020

@wessberg sounds like, as silly as it is, a string replacement as a last step isn't the worst possible decision for me?

@wessberg
Copy link
Owner

wessberg commented Aug 8, 2020

Feel free to do so, if that solves the problem for you 鈽猴笍. The best way might be as an afterDeclarations Custom Transformer in which you can manipulate the AST

@axtgr
Copy link

axtgr commented Aug 16, 2020

@bcoe you can try using the package I've recently made for this use case: https://github.com/axtgr/ts-transform-default-export

Adding it in your rollup.config.js like this should do the trick:

import ts from "@wessberg/rollup-plugin-ts";
import transformDefaultExport from "ts-transform-default-export";

export default {
  ...
  plugins: [
    ts({
      transformers: ({ program }) => ({
        afterDeclarations: transformDefaultExport(program),
      }),
    }),
  ],
};

It's apparently even possible to use this combination to make Rollup produce both CJS and ESM bundles and a single declaration file that is compatible with both of them, possibly solving the problem mentioned by @wessberg. The declaration will have export default foo; export = foo, which isn't super valid, but it seems to provide IntelliSense just fine for both CJS and ESM.

@wessberg
Copy link
Owner

@axtgr looks like a great solution, and a great use case for Custom Transformers! 馃檪

@bcoe
Copy link
Author

bcoe commented Aug 18, 2020

@axtgr thank you 馃槃 I prefer this to my hacky replace logic.

@bcoe bcoe closed this as completed Aug 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants