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

Native TypeScript support #3703

Closed
andrewslotin opened this issue Apr 22, 2024 · 7 comments · Fixed by #3738
Closed

Native TypeScript support #3703

andrewslotin opened this issue Apr 22, 2024 · 7 comments · Fixed by #3738
Assignees
Labels

Comments

@andrewslotin
Copy link
Contributor

Feature Description

TypeScript has become increasingly popular for its strong typing system, which enhances code quality and reliability—key aspects in performance testing scenarios. Currently, k6 does not support TypeScript out-of-the-box, requiring users to rely on external tools to transpile TypeScript code into JavaScript before it can be run by the tool. This additional step not only complicates the setup process but also impacts the overall developer experience, especially for those who primarily work with TypeScript. This setup also discourages TypeScript developers from adopting k6, despite its powerful testing capabilities.

Suggested Solution (optional)

To address the current gap, I suggest integrating k6pack, a solution based on esbuild, into the core functionality of k6. esbuild is a TypeScript transpiler and bundler written in Go, which aligns well with k6’s Go-based architecture. The integration would involve automatically invoking k6pack during the k6 launch process to transpile TypeScript scripts into executable JavaScript.

This integration can be structured as follows:

  • Automatic Detection: k6 should automatically detect TypeScript files (.ts/.tsx) and invoke k6pack.
  • Seamless Transpilation: Behind the scenes, k6pack uses esbuild to transpile TypeScript to JavaScript, handling any necessary bundling and minification. This process should be transparent to the user, requiring no manual steps.
  • Configuration Options: Users can provide custom configuration for the transpilation process via k6's existing configuration files or command-line options, allowing flexibility in how TypeScript is handled (e.g., specifying custom tsconfig.json settings).

Already existing or connected issues / PRs (optional)

No response

@andrewslotin
Copy link
Contributor Author

An experimental integration of k6pack can be found and used in the xk6-ts extension.

@codebien
Copy link
Contributor

Intercepting here some potential future problems that we may encounter during the integration. k6pack should run https://github.com/grafana/k6-ci as we are doing on other extensions. Maybe only part of it does make sense, a good start is the linter.

@pablochacin
Copy link

pablochacin commented Apr 23, 2024

FYI: the grafana bench project is using the k6pack to pre-compile the type script tests before invoking k6. We didn't use the xk6-ts extension because we wanted to be able to use a regular k6 binary and not a custom binary.

@szkiba
Copy link
Contributor

szkiba commented Apr 24, 2024

I implemented my first integration idea. No test code written yet, I'd like to justify with core team is it the right way to integrate or not...

Basically: I introduced a new compatibility mode: "enhanced". Using this compatibility mode activates k6pack (esbuild) bundling of the test script. The bundling happen in test load phase so the archive will be contains the bundled script...

@codebien could you take a look it plz...

#3710

@mstoykov
Copy link
Contributor

mstoykov commented May 8, 2024

This is not an exhaustive list of things, I just decided to post them as this already is very delayed response, for which I am sorry 🙇

General notes on typescript support

esbuild does not support typescript checking it "just" discards types to make it javascript compatible.

This means that either:

  1. users need to run tsc -noEmit to test that your code actually is typesafe
  2. depend on your ide/text editor to do it for you - which I guess will not work across the whole project

IMO this makes the use case a lot smaller. And probably less relevant as:

  1. if you are only using type defitions in a normal js file without defining your own new types - this seems to work pretty okay (on neovim) where ths tsserver lsp already tells you if you use the wrong type somewhere.
  2. Arguably if you are writing your own new types, and you have a big project - you probably want to run tsc to make certain it works across the whole project instead of only in the files you have currently opened.

So it seems likely users will either have to run tsc either way or they just need their IDE to be setup correctly.

Still no zero benefits though.

But I will argue that the wording of "native typescript support" is not correct:

  1. it isn't native - we don't really do anything natively.
  2. typescript support is too broad - I will recommend going with "typescript type-erasure support"

From the list of caveats in the docs there seem to be other things that we might need to look into:

  • given that ESM support is coming soon ™ it will be nice if we do have the ability to transpile to not commonjs files especially as that means that some stuff do not work correctly - like top-level await.
  • tsconfig.json parsing probably should be disabled? Or maybe we want it to be supported?
  • probably other parts of the caveats are relevant

It will be nice to have some idea how fully supporting is esbuild of typescript? Are there some holes that aren't supported?

I am also not certain how much "steam" typescript have, given that there have been some "thought-leaders" arguing against it and the tc39 proposal seemingly going nowhere.

It still does seem to be the de facto winner between it and jsdoc and I don't think anyone remember flow at this point.

More notes on the current implementation

The compatibility mode is nice

I do like this approach especially as it isn't the default. I will probably want it to have "experimental-" prefix for a while though.

It produces as single final file

Instead of actually compiling it per file. As the docs shows esbuild actually does this per file, so this seems like the better approach.

The current problem is that after you use this option you get one final packed file that prevents k6 from knowing where the original file is when it actually executes.

Which does break open:
main.js:

import "./a/a.js"

export default () => { }

a/a.js:

open("./test");

a/test:

whatever
ERRO[0000] GoError: stat /home/mstoykov/work/k6io/k6/scripts/issue-3703/open-bug/test: no such file or directory
        at go.k6.io/k6/js.(*Bundle).setInitGlobals.func3 (native)
        at file:///home/mstoykov/work/k6io/k6/scripts/issue-3703/open-bug/a/a.js:1:13(38)  hint="script exception"
Adding more javascript support through esbuild

I heard people wanting this, but unfortunately while this might work for some cases it has two caveats:

  1. they will still need additional work to make them work with k6 APIs if at all
  2. them not being native means that the above will likely not be nice and arguably more importantly might have different ways it works when it becomes native
  3. the above have happened before with babel

@szkiba szkiba linked a pull request May 13, 2024 that will close this issue
5 tasks
@szkiba
Copy link
Contributor

szkiba commented May 13, 2024

@mstoykov , Thank you for your comments.

I have transformed the use of esbuild as discussed, now it runs per module. In practice, it runs instead of Babel in the "enhanced" compatibility mode.

I also ran the tc39 tests. I adjusted the running of the tc39 tests a bit to be able to use more compatibility modes.

I have prepared a draft PR, I would appreciate it if you could review it.

PR: #3738

@pablochacin
Copy link

@mstoykov

I am also not certain how much "steam" typescript have, given that there have been some "thought-leaders" arguing against it

I don't think we should guide our roadmap based on "thought-leaders" as they have their own agenda of keeping themselves "relevant" by continuously introducing a new "next big thing".

What I think should matter is the adoption in k6 user base or testing community in general. In That regard, my anecdotical evidence is that TS is widely used. It would be interesting to have more information about how much the k6 users demand ts. Having an initial implementation that makes this possible (with the limitations you mention) maybe will allow us to uncover a latent demand.

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

Successfully merging a pull request may close this issue.

5 participants