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

Is there a Babel preset for Ringo (Rhino?) #418

Closed
pastelmind opened this issue Apr 20, 2021 · 4 comments
Closed

Is there a Babel preset for Ringo (Rhino?) #418

pastelmind opened this issue Apr 20, 2021 · 4 comments

Comments

@pastelmind
Copy link

I'd like to use modern ES features and transpile them. I can easily do so by using @babel/preset-env with no options to transpile everything down to ES5. However, it means I'm missing out on some ES2015 features that are already supported in Ringo, such as for...of loops, arrow functions, etc.

Is there a Babel preset specifically tailored for Ringo (Rhino)? Or perhaps a Babel alternative that can be configured to target Ringo?

@botic
Copy link
Member

botic commented Apr 20, 2021

Not yet or not known, sorry.

@pastelmind
Copy link
Author

pastelmind commented Apr 29, 2021

I went and started https://github.com/pastelmind/babel-preset-rhino. Turns out it's a bigger hassle than I expected. I need help. Since RingoJS users may be interested in this project, I figured I'd ask here.

I created a Babel preset that piggybacks onto @babel/preset-env. I intentionally omitted the targets option, which turns on all ES2015+ transformations. Then I disabled any plugins that Rhino doesn't need, such as transform-for-of. I'm going through features listed on Mozilla's compatibility tables and using a test suite to verify that I'm only disabling transforms that I don't need.

Nearly all of the syntactic transforms are covered. I made some major assumptions, though, and I'd appreciate it if someone else reviewed them.

Babel 7 required

I don't want to bother with older versions of Babel.

-version 200 assumed

I target Rhino 1.7.13 (the latest version) with -version 200 (all ES6 features). If you aren't enabling ES6, there's little point in optimizing a Babel preset at all.

Promises and async/await

Rhino does not natively support setTimeout(). Since most Polyfills for Promises rely on setTimeout(), they won't work either. I therefore skipped transpiling async/await features entirely.

❓ Question: I don't use RingoJS, but I understand it supports setTimeout() and a library version of Promise. Would you be interested in having async/await transpiled as well?

(Caveat: Babel doesn't know that RingoJS has to import Promise from ringo/promise. If async/await is polyfilled, RingoJS users would have to manually import ringo/promise in every file that uses async/await. Or perhaps write a custom Babel plugin for it.

New RegExp flags

Since Rhino does not support the newer RegExp flags (y, u), I didn't bother transpiling them. See below for more discussion.

Polyfills

I'm struggling with Babel's automatic polyfill import feature (enabled with useBuiltIns: 'usage'). For example, preset-env tries to polyfill Object.keys() even though Rhino supports it. I can easily disable this by excluding individual polyfill packages (es.object.keys). However, there are gotchas:

Some polyfills depend on each other. For example, the es.string.split polyfill is normally not needed, since Rhino already supports String.prototype.split(). However, if you want to use the y and u RegExp flags, es.string.split must be used along with es.regexp.exec to support them. I only discovered this after attempting to transpile String.prototype.split(). This is problematic because such dependencies are non-obvious.

How should I generate a set of polyfills that can be safely excluded, given that polyfills have hidden dependencies?

@pastelmind
Copy link
Author

pastelmind commented Apr 30, 2021

For what it's worth, I also investigated a different transpiler named Bublé. It is much more limited than Babel, but simpler to configure and use. I published buble-config-rhino which provides an optimized config for Rhino.

Notes (and this should go in the README for buble-config-rhino):

  • Unlike Babel, Bublé can only transpile syntax. Builtins unsupported by Rhino (e.g. Object.values()) must be polyfilled manually.
  • Bublé can only transpile ≤ ES2018. It doesn't support optional catch binding (ES2019), optional chaining and nullish coalescing (both ES2020).
  • Furthermore, Bublé cannot transpile several ES2015-2018 features. These include, but are not limited to:
    • ES2015: The y RegExp flag (ES2018), spec-compliant tagged template literals (a dangerous transform is supported), unicode code point escapes in strings
    • ES2018: Various RegExp enhancements
  • You can use another transpiler (see below) in front of Bublé to transpile bleeding edge features. I had success pairing TypeScript and Bublé to transpile TypeScript code to ES2018, then Rhino-optimized ES5+.

Other transpilers I examined:

  • esbuild: Sadly, it does not support transpiling to ES5.
  • swc: This is a Rust port of Babel and appears to be structured likewise. I expect similar complications to Babel (if not worse) if I were to create a preset for Rhino.
  • Sucrase: Transpiles down to ES2018 which makes it unsuited for Rhino. However, it may be a perfect pair for Bublé which can handle ES2015-2018.
  • Older version of Babel: I've considered this, as they may be more configurable than Babel 7. However, it is merely a conjecture at this point. I don't want to dig through old docs. I doubt people would want to use older versions of Babel either.

@botic botic closed this as completed Jun 1, 2021
@p-bakker
Copy link

Also see mozilla/rhino#661 and babel/babel#13448

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

No branches or pull requests

3 participants