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

Additional features related to Node ESM support #734

Open
alangpierce opened this issue Aug 3, 2022 · 3 comments
Open

Additional features related to Node ESM support #734

alangpierce opened this issue Aug 3, 2022 · 3 comments

Comments

@alangpierce
Copy link
Owner

alangpierce commented Aug 3, 2022

It's no secret that ES module support in Node has been a long and challenging transition, and I'd like Sucrase to do what it can to move the process along and minimize pain points as much as possible. The Sucrase project hasn't done much explicit work so far to support ESM, and I'm hoping to change that in some upcoming work.

This issue tracks a few separate work items and lines of investigation that are all generally in the direction of better ESM support, roughly in priority order.

ESM loader for Sucrase

Currently sucrase-node and sucrase/register are CJS-only, so I think the first priority is making it easy to use Sucrase for development in a Node ESM project. For TypeScript, that means following the conventions established in TS 4.7 (particularly explicit .js extensions in imports). Currently it looks like this is a bit trickier to implement than a require hook, so I think the easiest path is to integrate with ts-node, which is happening in #726 and #729 . My impression is that it would still be nice to have a built-in sucrase/esm-loader that's a bit simpler and more opinionated, analogous to sucrase/register.

Prioritize Sucrase improvements that make Node ESM easier to use

Normally I try hard to keep Sucrase as low-config as possible, but I think ESM/CJS interop is probably a place to make an exception. Two recent examples were #727 and #728 , which hopefully will make it easy to work around issues when using an ESM-only package or migrating to ESM.

Some other ideas that come to mind:

If other people seeing this issue have ideas here, feel free to comment!

Use ESM for all internal scripts in Sucrase

Currently Sucrase internally uses sucrase-node for all internal scripts and transpiles everything to CommonJS. Switching all of those to use true ESM would be a good non-breaking first step before changing the package itself to fully support ESM.

Restructure package to work with Node ESM

Currently, using Sucrase from Node will always use the CJS version, which is certainly usable from ESM, but it would be nice if packages were using the ESM build directly. The package structure has an esm folder, but all imports are extensionless, so it can be used by many bundlers but not natively within Node. My plan is to restructure the package into cjs and esm folders with .js extensions for all imports, using conditional exports to point ESM and CJS usages to the right place. I believe this will be a breaking change (because of the package.json exports field, among other things), so it'll be as part of the 4.0 release.

Consider releasing an ESM-only package under an alternate name

The ESM -> CJS transform is a big source of complexity for Sucrase, and it would be great if the community eventually converged on ESM to the point where ESM -> CJS transpilation no longer feels like a necessary feature. I don't think it's reasonable to drop support for that transform as a breaking change within sucrase any time soon, but one idea could be something like a separate sucrase-esm package that's smaller and a little faster.

kodiakhq bot pushed a commit to roots/bud that referenced this issue Mar 29, 2023
## Why?

supports tailwind 3.3.0 compatibility and advances project goals

## Effects?

- users can configure bud using typescript (`bud.config.ts`) out of the box
- no need to use `ts-node` or the alternative `bud` cli command for typescript config support.
- bud.js won't choke on `tailwind.config.ts` files
- support extends to eslint: `eslint.config.ts` should work as well


## Notes

- we're gonna parse configs in a similar way to tailwind
- tailwind does it with [jiti](https://github.com/unjs/jiti)
- it's tempting to do the same, and [sucrase](https://www.npmjs.com/package/sucrase) seems fast. but for now, we're using [module-from-string](https://github.com/exuanbo/module-from-string) namely due to first-class esm support: alangpierce/sucrase#734.

  

refers:

- none
@aleclarson
Copy link
Contributor

aleclarson commented Aug 18, 2023

This would be really useful for the AVA test runner, which only works with ESM loaders these days (e.g. see @ava/babel here which supports AVA 3, two versions back).

@DanielRios549
Copy link

Is there any update? We're almost in 2024 and Sucrase is still not working with type module in package.json...

@alangpierce alangpierce changed the title Node ESM support Additional features related to Node ESM support Dec 23, 2023
@alangpierce
Copy link
Owner Author

alangpierce commented Dec 24, 2023

Hey @DanielRios549, I believe Node ESM is already working in Sucrase, though let me know if you're running into specific issues. Sorry, I think the original issue title ("Node ESM Support") and "open" status were misleading. This issue tracks some additional plans in the same general direction as ESM support, but Sucrase should already work with just about any ESM project and use case.

I'll edit the original description with more details, but as a quick overview:

  • To compile-on-the-fly or use a repl, use ts-node with the Sucrase plugin. ESM loaders, interpreting tsconfig, and integrating deeply with Node all have some complexity that are the primary goal of the ts-node project, and Sucrase handles the transpiler side when you use the Sucrase ts-node plugin. As mentioned above, I've been meaning to write a loader specifically for Sucrase that's a little lighter-weight, but in the meantime, ts-node is the best way to go and will probably always be more feature-complete.
  • For any direct transform() use cases or integrations (webpack, etc), all necessary options that I'm aware of should be available. To target ESM, omit the imports transform in the config. To match TypeScript's module: nodenext most directly, it's best to specify injectCreateRequireForImportRequire as well. If you're working in a project with CJS code that needs to use dynamic import on an ESM project, you'll need to specify the preserveDynamicImport Sucrase option.
  • When using the sucrase CLI, basic cases should be supported, though I'll admit there are some gaps. The CLI can accept any of the options in the last bullet point, so that should cover everything from a standpoint of the transpile behavior. However, I see that it only attempts to transpile .ts/.tsx/.js/.jsx, not any of the newer .mts/.cts/etc. From my usage of Node ESM so far, I haven't had much use for .mjs and .cjs (and instead used the package.json type field), though I understand it can be useful for more advanced use cases. I also think it's often best to set up Sucrase compile-on-the-fly as the development experience and use regular tsc for production builds/releases, since tsc can also generate .d.ts files. That said, Sucrase does compile itself using the Sucrase CLI, and it is a use case I want to support.

If this doesn't cover your use case, I'd love to understand more details. I suppose for JSX/Flow-only use cases, ts-node isn't a reasonable option, for example. Feel free to file any additional issues or just comment here with any details about what's not working or what you need that's missing.

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

No branches or pull requests

3 participants