grafana / k6

A modern load testing tool, using Go and JavaScript - https://k6.io
GNU Affero General Public License v3.0
25.84k stars 1.27k forks source link

a Roadmap to target higher ES standards? ES6+ ES7+ ES8+ or ES2020 ES2021+ ? #2296

Open tx0c opened 2 years ago

tx0c commented 2 years ago

Feature Description

the main feature of k6 still says ES6, but ES6 has existed long time (since 2015), some features are not cool enough at the end of 2021, and we have been using many newer JS features for years, like this optional chaining operator (?.) with babel or natively since 2020;

wish can write tests in this way, checking the response header should have 'content-type' and should string includes 'application/json'

  check(res, {
    'header has content-type application/json': r => r.headers['content-type'] ?. includes('application/json')
  });

instead of writing it the old way:

  check(res, {
    'header has content-type application/json': r => r.headers['content-type'] && r.headers['content-type'].indexOf('application/json') > -1
  });

wonder what JS engine is builtin this k6 tool? can that bump version to target a higher version of JS standard?

many things like URL, URLSearchParams have been builtin Node.js for years;

and have to import it is not cool https://k6.io/docs/examples/urls-with-query-parameters/

Suggested Solution (optional)

many things like URL, URLSearchParams have been builtin Node.js for years;

and have to import it is not cool https://k6.io/docs/examples/urls-with-query-parameters/

Already existing or connected issues / PRs (optional)

No response

Link #2168 #824

na-- commented 2 years ago

We'd like to have all of that! Unfortunately it's not easy to keep up with the speed of the JS ecosystem... :sweat_smile:

I'll try to provide some background of how JS execution actually happens in k6. After all, k6 itself is written in Go, so we can't just immediately get all of the new features from V8 or node.js... Instead, k6 uses goja to parse and execute scripts, a JavaScript runtime written purely in Go. It is not as fast as other more optimized runtimes and it doesn't support all of the latest JS features, but there are a lot of reasons for us to use it despite these shortcomings!

JS runtime performance doesn't matter all that much for our use case, since bottlenecks in k6 are mostly with IO. For example, making actual HTTP requests efficiently is much more important for our load testing use case than JS performance. After all, that is where the majority of script execution time goes and the Go standard library (without a lot of optimization) outperforms node.js. Concurrency and ease of use are also more important. Integrating goja is orders of magnitude simpler and better than trying to use a C or a C++ library in Go... Since it's written in Go, it allows us to have a very tight and seamless integration. It even allows us to support Go extensions that are usable from the JS scripts with xk6! Every VU in k6 is an independent goja runtime and takes only a few hundred KB of RAM and is very well integrated with the rest of the k6 components, something that's pretty much impossible to do with V8.

Unfortunately, goja itself doesn't even support all ECMAScript 6 features yet. It supports all ES 5.1 features and a lot of ES6+ features, but not all of them. Because of that, k6 bundles an old version of Babel and automatically tries to transpile any scripts that goja can't parse with it (unless --compatibility-mode=base is used).

We've investigated updating that bundled version of Babel with a newer one and decided against it, because it unfortunately introduced unacceptable performance regressions... :disappointed: Because even our current old version of Babel has performance issues, and because goja already supports almost everything it does, we've decided to do the opposite and actually get rid of Babel altogether. We are currently working on contributing import/export support natively for goja (https://github.com/dop251/goja/issues/348) and once we have that, ES classes and a few other minor things, we'll have full ES6 support and get rid of Babel completely.

We then plan to contribute support for other newer ES features to goja as well. Unfortunately, we can't do that before we get completely rid of Babel, because it's in the way. For example, goja already supports the spread operator better than our old Babel version (https://github.com/grafana/k6/issues/824#issuecomment-915918351), which throws an error. Similarly, even if we added optional chaining (https://github.com/grafana/k6/issues/2168) to goja today, which shouldn't be that complicated to implement, we still won't be able to actually use it by default, because our old Babel will treat it as a parse error... :sob:

So, yeah, the first step is to get rid of Babel and fully support all of ES6 natively. After that we'll invest time and resources to get support for other ES7+ goodies, most of which should be substantially simpler to implement. And while our team is expanding and we plan to dedicate a lot more attention to these efforts, we (and probably the goja author) will appreciate any help we can get! We have even considered adding optional built-in support for esbuild, an alternative to Babel that's written in Go and is much more performant and easier to integrate... :man_shrugging:

And while we want to have full compatibility with the latest ECMAScript versions, it's still not clear which roads we'll take... Because of the fragmented nature of the JS ecosystem, it's not always clear what we should even support. For example, the URL APIs are not actually ECMASCript APIs, they are Web APIs. We plan to support them (https://github.com/grafana/k6/issues/991), but we probably won't support the majority of non-ECMAScript APIs that exist in node.js or browsers... We might support some, we might have polyfills of others, but we'll evaluate whether every non-ECMASCript API makes sense to include in k6 on a case-by-case basis.

Anyway, until we have all of that, the best suggestion I can give you and everyone else that wants to use the latest and greatest JS features is to use the latest Babel (or something like it) and transpile your scripts outside of k6 before you execute them with it. We are working on improving our sourcemap support (https://github.com/grafana/k6/pull/2082), so the UX of that would soon become even better! Transpiling the scripts yourself is easy to automate and will allow you to write your scripts using features from any JS version, or even TypeScript!

na-- commented 2 years ago

It's worth pointing out that we've fixed sourcemap support in https://github.com/grafana/k6/pull/2082, so starting with k6 v0.36.0 (hopefully to be released later this week), it now should be much nicer to execute externally transpiled scripts with k6. If there are any issues, you should get correct stacktraces from your original unbundled source code.

mstoykov commented 2 years ago

Additionally I would like to get something like (preferably the same) as https://test262.report/ with k6/goja support at some point. The about page has more info on how it gets generated.

I did try something like that 2 years ago unsuccessfully(for many reasons) but hopefully at some future point someone can do it :crossed_fingers:

rohit-gohri commented 1 year ago

The JS community is converging to some common list of supported features on all the different runtimes (Node, Cloudflare Workers, Deno, etc) - https://common-min-api.proposal.wintercg.org/

This might be a good list of things to target long term for users coming to k6 from these other runtimes