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

Allow ES6 in emscripten output #11984

Closed
sbc100 opened this issue Aug 20, 2020 · 40 comments · Fixed by #15763 or #20700
Closed

Allow ES6 in emscripten output #11984

sbc100 opened this issue Aug 20, 2020 · 40 comments · Fixed by #15763 or #20700

Comments

@sbc100
Copy link
Collaborator

sbc100 commented Aug 20, 2020

We have a lot JavaScript code that emscripten generates and currently we limit all of it ES5 in order to maximize the portability of the output code.

However, given that non-ES5 runtime as rare (citation needed?), and that there are tools such as babel for converting ES6 to ES5 it seems like the wrong tradeoff to ask all emscripten JavaScript code to avoid modern features for this reason.

I recently ran across this in #11979 where the use of an ES6 feature would save code size and (I think) performance for the vast majority of our users.

Also see #11858

I propose that we remove this restriction and allow all ES6 features in emscripten output. The remained question is now we support user who need ES5 output. Do we:

A. Do nothing. Assume that our users who want to target older engine are well versed in running babel themselves and put the burden on them.
B. Add a compatibility option -s MIN_ES_VERSION=5? Or just -s ES5? This would most likely mean taking an internal dependency on babel and running it as part of the post-link process.

We could also do a hybrid approach where we poll our users and ask how many would want option B? Or at least we cpi;d delay the implementation of option B until we know we there a non-zero number of such users?

Please excuse me if this is a duplicate issue. I'm fairly sure I've seen similar a one but I couldn't find it in a search for ES6 or ES5.

@sbc100 sbc100 changed the title Support ES6 by default Allow ES6 in emscripten output Aug 20, 2020
@curiousdannii
Copy link
Contributor

curiousdannii commented Aug 21, 2020

ES5 is pretty much only needed for IE now. Probably that means mostly only for enterprise intranet type situations? I'd support using ES6+ features in output and saying that anyone who needs it to be ES5 can transpile it themselves.

Could remove stuff like the Promise polyfill too.

@kripken
Copy link
Member

kripken commented Aug 21, 2020

Here is caniuse: https://caniuse.com/#feat=es6

Looks like e.g. Edge 14 lacks full support, not sure when it was released though, wikipedia page is incomplete. Firefox and Chrome seem fine (2017 / 2016). For Safari we should check iOS too.

@Brion I believe you support older versions - thoughts?

@curiousdannii
Copy link
Contributor

curiousdannii commented Aug 21, 2020

There's also https://kangax.github.io/compat-table/es6/

Edge 14 was released Aug 2016 and has only 0.02% browser share. Doesn't it get automatic OS updates?

iOS seems to have close to full support since version 11.

@kripken
Copy link
Member

kripken commented Aug 21, 2020

Thanks @curiousdannii , and looks like iOS11 is from 2017, which is good.

I think Edge's releases have been decoupled from Windows since 2019, so those get automatic updates, but maybe older windows versions don't, I'm not sure. But 0.02% indicates you are right I think.

In general I think we should delay this until we are ready to emit ES6 by default. That is, we already have some defaults for MIN_$BROWSER, and we should probably update those. When they indicate ES6 in all of them, then I think we can make the switch to the "write ES6, depend on babel for legacy". The reason is that running babel like that will have some overhead to build times, which it would be nice to avoid in default builds (but is fine for special builds with legacy support).

It's possible we can do all this now - depending on what we find with ES6 support, and what we decide on how old is "legacy". We don't have exact rules for that since it's hard to be precise given how complex the ecosystem is. We should probably look at other tools targeting the Web to see what they do, e.g. does the TypeScript compiler emit ES6 by default? It looks like no, it's still ES3, but OTOH we do emit wasm by default, and maybe they have reason to be more cautious.

I do think we should add babel integration, if we do this. It should be pretty simple, like our closure integration using npm.

@sbc100
Copy link
Collaborator Author

sbc100 commented Aug 21, 2020

That makes sense to me.

So the first thing we have to do is push the MIN_$BROWSER up to X where X includes ES6.

@sbc100
Copy link
Collaborator Author

sbc100 commented Aug 21, 2020

Actually we our policy could be more fine grained. I think we could start with just requiring a few features from ES6 by default:

  1. spread/rest (...) operator
  2. arrow functions
  3. let

I think just those three would give a good win on code side, performance and maintainability.

@kripken
Copy link
Member

kripken commented Aug 21, 2020

It it's necessary we can be more fine grained perhaps - I think we already are by using fetch for downloading wasm, since we realized all browsers with wasm support have fetch support anyhow. But that does get more complicated. Is there a big difference in browser support between ES6 and those 3 parts of it?

@dschuff pointed out that wasm-supporting browsers may also support ES6 anyhow, so this may only be relevant for wasm2js, which could make this simpler.

@jvail
Copy link

jvail commented Aug 24, 2020

Just an observation from someone trying to decide which build flags to use (only slightly off-topic):
It is bit confusing that with EXPORT_ES6=1 em emits code with require(...) and __dirname in node which makes it effectively unusable as node module in node 14.

@curiousdannii
Copy link
Contributor

@jvail You can subscribe to #11792 to get notified when that eventually gets fixed.

@sbc100
Copy link
Collaborator Author

sbc100 commented Sep 8, 2020

Here is caniuse: https://caniuse.com/#feat=es6

Looks like e.g. Edge 14 lacks full support, not sure when it was released though, wikipedia page is incomplete. Firefox and Chrome seem fine (2017 / 2016). For Safari we should check iOS too.

Our min Edge version is 44.. which has full support according to that site. So I can't see any MIN_XXX_VERSIONS in our settings that don't already default to a version that fully supports ES6.

@Brion I believe you support older versions - thoughts?

sbc100 added a commit that referenced this issue Sep 8, 2020
This match the input we accept when running the acorn compiler.

Since we still want to output ES5 by default, also set language
out to ES5 for now.

See #11984
sbc100 added a commit that referenced this issue Sep 8, 2020
This match the input we accept when running the acorn compiler.

Since we still want to output ES5 by default, also set language
out to ES5 for now.

See #11984
sbc100 added a commit that referenced this issue Sep 8, 2020
This matches the input we accept when running the acorn compiler.

See #11984
sbc100 added a commit that referenced this issue Sep 10, 2020
This matches the input we accept when running the acorn compiler.

See #11984
sbc100 added a commit that referenced this issue Sep 10, 2020
This matches the input we accept when running the acorn compiler.

See #11984
sbc100 added a commit that referenced this issue Sep 10, 2020
This matches the input we accept when running the acorn compiler.

See #11984
@stale
Copy link

stale bot commented Sep 21, 2021

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

@sbc100
Copy link
Collaborator Author

sbc100 commented Sep 23, 2021

bump!

@stale stale bot removed the wontfix label Sep 23, 2021
@curiousdannii
Copy link
Contributor

What still needs to be done? EM_ASYNC_JS already outputs async functions and arrow functions.

@sbc100
Copy link
Collaborator Author

sbc100 commented Sep 23, 2021

Are you sure about that? We verify that only ES5 is emitted as part of our test suite:

emscripten/tests/common.py

Lines 575 to 576 in 592dec1

if js_outfile and not self.uses_es6:
self.verify_es5(output)

This runs for pretty much every single test.. except those that specifically use ES6 concepts in their use code? Perhaps you are refering to code the that developer writes? Or does EM_ASYNC_JS itself output an arrow function?

@sbc100
Copy link
Collaborator Author

sbc100 commented Oct 24, 2023

We are currently blocked form using all ES6 features to google/closure-compiler#2007.

One possible way forward, as suggested in google/closure-compiler#1138 is to force SIMPLE_OPTIMIZATIONS, even in debug builds, when transpilation is triggered.

@RReverser @kripken WDYT? I think that seems fairly reasonable. Hopefully most folks aren't doing too much debugging in older browsers.

@RReverser
Copy link
Collaborator

Maybe, but not a huge fan...

Also cross-pasting from the chat:

Btw it might be interesting to look into something like swc for transpilation. It's a Babel alternative built in Rust & available as Wasm-based package.

Should be much faster than using Closure compiler just for transpilation, although at the cost of extra dependency. It also has Babel/Buble inspired loose mode which should output smaller ES5 code for common usages as well, for example:

image

vs

image

IMO the smaller output produced faster is worth it, but I know Emscripten was historically trying to avoid adding new dependencies.

@sbc100
Copy link
Collaborator Author

sbc100 commented Oct 24, 2023

That looks like a great option actually. Sounds like this won't have the bable downside of blowing up the number of dependencies in our node modules.

Having said that I think we could do these in either order.. i.e. we could switch to swc if/when folks complain about the SIMPLE_OPTIMIZATIONS approach?

@RReverser
Copy link
Collaborator

i.e. we could switch to swc if/when folks complain about the SIMPLE_OPTIMIZATIONS approach?

I guess you could yeah, if going with basic optimisations is not a deal breaker.

@RReverser
Copy link
Collaborator

RReverser commented Oct 24, 2023

Sounds like this won't have the bable downside of blowing up the number of dependencies in our node modules.

Yup, looks like @swc/core has only 2 dependencies, both are basically empty (one is TS types and another is completely empty, just used for counting total npm downloads across couple of SWC packages that declare it as a dependency 😅).

@RReverser
Copy link
Collaborator

Hopefully most folks aren't doing too much debugging in older browsers.

Thinking about it more, this seems like a sensible assumption for a quick solution. I'd say go for it.

@kripken
Copy link
Member

kripken commented Oct 24, 2023

One possible way forward, as suggested in google/closure-compiler#1138 is to force SIMPLE_OPTIMIZATIONS, even in debug builds, when transpilation is triggered.

To make sure I follow: Does this mean to do simple optimizations instead of no optimizations, or simple optimizations instead of advanced optimizations? (the former makes more sense given "even in debug builds", but the latter makes more sense to me otherwise, so I'm confused)

@sbc100
Copy link
Collaborator Author

sbc100 commented Oct 24, 2023

Yes, it means that user who want to transpile will be forced to also get at least SIMPLE_OPTIMIZATIONS

@sbc100
Copy link
Collaborator Author

sbc100 commented Oct 24, 2023

So SIMPLE_OPTIMIZATIONS instead of none.

@kripken
Copy link
Member

kripken commented Oct 24, 2023

I see, thanks. That is kind of weird, but otoh transpiling does modify the source code substantially anyhow, so I doubt it would make debugging harder. And usually for debugging people can run in a modern browser and avoid transpiling. So this sounds like a reasonable workaround to me as well.

To be sure I follow, though, this would have no effect in a default build, since by default we don't transpile?

@RReverser
Copy link
Collaborator

To be sure I follow, though, this would have no effect in a default build, since by default we don't transpile?

That's correct.

Semi-related question though: I also saw various places in the codebase that could benefit from nullish coalescing operator (A && A.B && A.B.C - >A?.B?.C).

It's supported in Chrome 80+, Firefox 72+, Safari 13.1+ and Node.js 14+.

Our min versions defaults haven't changed in a long time and are currently set to Chrome 75+, Firefox 68+ and the others are higher already.

Given that Chrome & Firefox are evergreen and it's been a while, I hope it's not a deal-breaker to bump those versions as well so that we could benefit from this operator w/o worrying about transpiling?

@kripken
Copy link
Member

kripken commented Oct 24, 2023

Our min versions defaults haven't changed in a long time and are currently set to Chrome 75+, Firefox 68+ and the others are higher already. Given that Chrome & Firefox are evergreen and it's been a while, I hope it's not a deal-breaker to bump those versions as well so that we could benefit from this operator w/o worrying about transpiling?

Yes, that sgtm. Looks like we updated Firefox to 68 in April, and Chrome even earlier, so a few versions higher should be fine. Even Firefox ESR is 115 (recently updated it seems) so that seems ok.

@RReverser
Copy link
Collaborator

RReverser commented Oct 24, 2023

Hm yeah Chrome minimum is very old. I'll bump just a few versions more to include nullish assignment too then (Chrome 85+, Firefox 79+, others already covered).

RReverser added a commit to RReverser/emscripten that referenced this issue Oct 24, 2023
Note that this bumps minimum Chrome & Firefox versions.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
RReverser added a commit to RReverser/emscripten that referenced this issue Oct 25, 2023
Note that this bumps minimum Chrome & Firefox versions.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
RReverser added a commit to RReverser/emscripten that referenced this issue Oct 28, 2023
Note that this bumps minimum Chrome & Firefox versions.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
sbc100 added a commit to sbc100/emscripten that referenced this issue Nov 13, 2023
When transpiling to ES5 use closure with `SIMPLE_OPTIMIZATIONS` rather
then `WHITESPACE_ONLY`.  This means that polyfills cant be included
as needed and removes the limits on what ES6 features we can use.

The downside of this is that is slows down builds for ES5 users but
this seems like a reasonable tradeoff.

Fixes: emscripten-core#11984
sbc100 added a commit to sbc100/emscripten that referenced this issue Nov 13, 2023
When transpiling to ES5 use closure with `SIMPLE_OPTIMIZATIONS` rather
then `WHITESPACE_ONLY`.  This means that polyfills cant be included
as needed and removes the limits on what ES6 features we can use.

The downside of this is that is slows down builds for ES5 users but
this seems like a reasonable tradeoff.

Fixes: emscripten-core#11984
sbc100 added a commit to sbc100/emscripten that referenced this issue Nov 13, 2023
When transpiling to ES5 use closure with `SIMPLE_OPTIMIZATIONS` rather
then `WHITESPACE_ONLY`.  This means that polyfills cant be included
as needed and removes the limits on what ES6 features we can use.

The downside of this is that is slows down builds for ES5 users but
this seems like a reasonable tradeoff.

Fixes: emscripten-core#11984
sbc100 added a commit to sbc100/emscripten that referenced this issue Nov 15, 2023
When transpiling to ES5 use closure with `SIMPLE_OPTIMIZATIONS` rather
then `WHITESPACE_ONLY`.  This means that polyfills cant be included
as needed and removes the limits on what ES6 features we can use.

The downside of this is that is slows down builds for ES5 users but
this seems like a reasonable tradeoff.

Fixes: emscripten-core#11984
sbc100 added a commit that referenced this issue Nov 15, 2023
When transpiling to ES5 use closure with `SIMPLE_OPTIMIZATIONS` rather
then `WHITESPACE_ONLY`.  This means that polyfills cant be included
as needed and removes the limits on what ES6 features we can use.

The downside of this is that is slows down builds for ES5 users but
this seems like a reasonable tradeoff.

Fixes: #11984
RReverser added a commit to RReverser/emscripten that referenced this issue Nov 30, 2023
Note that this bumps minimum Chrome & Firefox versions, as well as JS version from ES2020 to ES2021.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups. Best viewed with "ignore whitespace changes" (https://github.com/emscripten-core/emscripten/pull/20531/files) due to indentation changes and due to first commit being emscripten-core#20530.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
RReverser added a commit to RReverser/emscripten that referenced this issue Nov 30, 2023
Note that this bumps minimum Chrome & Firefox versions, as well as JS version from ES2020 to ES2021.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups. Best viewed with "ignore whitespace changes" (https://github.com/emscripten-core/emscripten/pull/20531/files) due to indentation changes and due to first commit being emscripten-core#20530.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
RReverser added a commit to RReverser/emscripten that referenced this issue Dec 1, 2023
Note that this bumps minimum Chrome & Firefox versions, as well as JS version from ES2020 to ES2021.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups. Best viewed with "ignore whitespace changes" (https://github.com/emscripten-core/emscripten/pull/20531/files) due to indentation changes and due to first commit being emscripten-core#20530.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
RReverser added a commit to RReverser/emscripten that referenced this issue Dec 7, 2023
Note that this bumps minimum Chrome & Firefox versions, as well as JS version from ES2020 to ES2021.

I believe this is not blocked on emscripten-core#11984 as it doesn't require Closure to emit runtime helpers.

This is mostly automated with ast-grep, bunch of custom rules, and a few manual fixups. Best viewed with "ignore whitespace changes" (https://github.com/emscripten-core/emscripten/pull/20531/files) due to indentation changes and due to first commit being emscripten-core#20530.

Care was taken to ensure that false-y conditions still use `||` where it might matter and only null-ish conditions use `??`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants