Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Proposal: ECMAScript version policy for GopherJS #1121

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

Closed
nevkontakte opened this issue Jun 7, 2022 · 6 comments
Closed

Proposal: ECMAScript version policy for GopherJS #1121

nevkontakte opened this issue Jun 7, 2022 · 6 comments
Assignees

Comments

@nevkontakte
Copy link
Member

nevkontakte commented Jun 7, 2022

Background

For a long time GopherJS had a policy of maintaining generated code compatibility with the ECMAScript 5 standard. ES 5 was a good choice due to its broad browser support and ability to use GopherJS-generated scripts almost anywhere without additional post-processing.

However, in the time passed the web landscape has changed enough for us to reconsider this policy. In particular, 94.35% of clients fully support ES 2015 with 2.28% offering partial support according to caniuse. GopherJS already uses ES 2015 typed arrays (supported by 97.98% of clients), so ES 2015 adoption would impact 3.64% of web users (pessimistically assuming that partial support is insufficient). In practice we expect the impact to be further mitigated by the following factors:

  • Tools like babel can be used to transpile ES 2015+ down to ES 5 syntax.
  • There are third-party polyfill libraries like core.js that can be used to emulate ES 2015+ APIs on the older systems.
  • According to caniuse, most non-compliant clients are either Internet Explorer 10/11 or old mobile Android browsers released before 2015. In all likelihood they represent low-end systems using GopherJS on which was already problematic due to performance and large output size.
  • According to the GopherJS user survey, only 2.9% of responders support 5-8 years old browsers, and nobody supports browsers older than 8 years.

As the JavaScript ecosystem evolves, benefits of adopting newer ECMAScript standards become more and more significant for GopherJS. Here is an incomplete list of improvements that become possible with ECMAScript 2015:

Proposed policy

We declare ECMAScript 2015 a baseline targeted version. Any syntax or an API that is a part of the baseline targeted version can be used in the GopherJS generated code, unless explicitly stated in this policy. It is up to the users to transpile or polyfill it for older runtimes.

The baseline targeted version can be updated to newer ECMAScript standards if the following guidelines are met:

  • Chrome (on Android and desktop), Firefox, Safari (on Mac and iOS) and Edge have had complete support of the standard for at least two years. Compatibility with other browsers will be taken into account, but won't be necessarily blocking.
  • The oldest supported Node.js LTS version has complete support for the standard.
  • At least 95% of web users have complete or partial support of the standard as reported by caniuse.com.
  • Upgrading to the newer standard offers tangible benefits to GopherJS and its users in performance, features, or maintenance cost.

We recognize that in many ways the value judgement in this question is subjective, but the final decision is made by consensus among the currently active GopherJS maintainers. If the decision to upgrade the baseline targeted verision is made, it should only take effect when the next minor version is released (i.e. 1.x).

For the ECMAScript features from standard versions newer than the baseline, the following rules apply:

  • Using new syntax features is not allowed.
  • Using new APIs may be allowed if the following conditions are met:
    • It doesn't harm the GopherJS performance or stability in the runtimes missing the feature. Significant bundle size increases are considered a negative effect in this context.
    • GopherJS runtime handles missing APIs gracefully and transparently. GopherJS users don't have to manually polyfill or change build configuration.
    • There is a consensus among the active GopherJS maintainers that this change would be beneficial to GopherJS and its users overall.

Common sense applies: The rules above are meant to provide general guidelines, but we acknowledge that making exceptions may be necessary from time to time. Our ultimate goal is to make GopherJS as useful to our users as possible and avoid inflicting unnecessary toil on them or the maintainers.

Prior discussions:

@nevkontakte nevkontakte self-assigned this Jun 7, 2022
This was referenced Jun 7, 2022
@flimzy
Copy link
Member

flimzy commented Jun 8, 2022

I like this proposal in principle. A few comments, in no particular order:

  • Before formalizing, I thikn we should be explicit about supported browsers. ", etc" is not very actionable 😁 We may want to add a compatibility list/chart/grid somewhere.
  • Do we have concrete examples yet where we're certain ES 2015+ will help GopherJS, or are the examples provided still hypothetical?

@nevkontakte
Copy link
Member Author

  • Before formalizing, I thikn we should be explicit about supported browsers. ", etc" is not very actionable 😁 We may want to add a compatibility list/chart/grid somewhere.

This is exactly the question I was trying to dodge πŸ˜… But since you saw right through it, here are my thoughts:

  • I called out browsers that I'm reasonably confident will have a decent market share for the foreseeable future. We won't be able to ignore them anyway.
  • I wanted to leave the list open because new browsers may become significant in future (e.g. Opera, Brave, or perhaps some Chinese browsers I am currently ignorant about).
  • On the other hand, most of those browsers are likely to be either WebKit or Blink-based, so as long as Chrome supports a feature, they will too, with some lag.
  • I am unsure if we can formulate an objective criteria that wouldn't require us to test GopherJS against 20 different browsers. Doing that would be lovely, but I don't think that either you or me have time to do so, and I'm not aware of any volunteers who could help us on that front. As such, I don't want to make promises I won't be able to keep.

If you can think of a better solution, that would be great :)

  • Do we have concrete examples yet where we're certain ES 2015+ will help GopherJS, or are the examples provided still hypothetical?

I gave a few examples in the background section that seem very plausible to me and have been requested by our users. I can't say definitively that they will 100% work out, since they haven't been prototyped yet. Doing so would be a lot of work, so I haven't bothered without having this discussion.

However, I can give at least two examples of low-hanging fruits:

Reducing generated code size with destructuring assignments and object property shorthands.

Consider the following Go code:

func blocking() {
	x := 1
	y := 2
	runtime.Gosched()
	x++
	y++
}

Currently the generated code for this function looks like this:

	blocking = function() {
		var x, y, $s, $r;
		/* */ $s = 0; var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; x = $f.x; y = $f.y; $s = $f.$s; $r = $f.$r; } s: while (true) { switch ($s) { case 0:
		x = 1;
		y = 2;
		$r = runtime.Gosched(); /* */ $s = 1; case 1: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
		x = x + (1) >> 0;
		y = y + (1) >> 0;
		$s = -1; return;
		/* */ } return; } if ($f === undefined) { $f = { $blk: blocking }; } $f.x = x; $f.y = y; $f.$s = $s; $f.$r = $r; return $f;
	};

Notice the second and the last lines where we restore and save the local context when the function gets blocked. With ES 2015 syntax they could be rewritten in a more compact form:

blocking = function() {
  var x, y, $s, $r;
  /* */ $s = 0; var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; [x, y, $s, $r] = $f; } s: while (true) { switch ($s) { case 0:
  x = 1;
  y = 2;
  $r = runtime.Gosched(); /* */ $s = 1; case 1: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
  x = x + (1) >> 0;
  y = y + (1) >> 0;
  $s = -1; return;
  /* */ } return; } if ($f === undefined) { $f = { $blk: blocking }; } $f = {x, y, $s, $r}; return $f;
};

In this example, the ES 2015 syntax saves us 46 bytes of the generated code size for a function with just two local variables, and this will grow for more complex functions. For a real-life program this may add up to a decent few kilobytes of smaller output. I think lexical this could enable even more compact code, but haven't figured out all corner cases yet.

#136 has been the single biggest pain point called out in our user survey, so I assign a lot of weight to any improvement in that regard.

Proper implementation of the internal/intern package with WeakMap

Instead of hacking net/netip package in 7b2b95a we would be able to implement internal/intern package using a WeakMap and not worry about any future places that package may get used in.

A somewhat longer shot in the same vein would be using a WeakMap to assign actual integer values to pointers, which would enable a much better unsafe support. That ideal, however, requires a lot more design, which I haven't done yet, so I won't go into much more detail now.

@flimzy
Copy link
Member

flimzy commented Jun 8, 2022

This is exactly the question I was trying to dodge

Haha sorry. Well, I would be happy with a fairly narrow list of officially supported browsers. Chrome, Firefox, Safari, Edge, iOS, Android may be enough. (with the addition of version numbers/dates)

I would word our compatibility goals broadly enough, though, that it doesn't look like we aim only to support those, and that we expect many other browsers to work.

I am unsure if we can formulate an objective criteria that wouldn't require us to test GopherJS against 20 different browsers.

I agree, I don't want to get into the business of running tests (manual or automated) on 20 browsers. We haven't needed that yet, so I think we should avoid it.

To that end, I'd suggest we word the supported browser policy something like "We give priority to bug reports against supported browsers."

@nevkontakte
Copy link
Member Author

Updated to:

Chrome (on Android and desktop), Firefox, Safari (on Mac and iOS) and Edge have had complete support of the standard for at least two years. Compatibility with other browsers will be taken into account, but won't be necessarily blocking.

WDYT?

@nevkontakte
Copy link
Member Author

Ping @flimzy.

So far it seems like no strong objections have been made. If none arise by the end of the next week, I will declare this proposal accepted.

@nevkontakte
Copy link
Member Author

Since no objections have been raised I am declaring the proposal accepted and that GopherJS 1.18 will be using some of the ES 2015 features to reduce the output size (I'm thinking about descructuring assignments primarily).

P.S. I was sort of expecting more debate, but perhaps very few people care about ES5 compatibility indeed :)

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

2 participants