Coder Social home page Coder Social logo

xk6-enhanced's Introduction

xk6-ts

TypeScript support for k6

xk6-ts makes TypeScript a first-class citizen in k6.

k6 run script.ts
script.ts
import { User, newUser } from "./user";

export default () => {
  const user: User = newUser("John");
  console.log(user);
};
user.ts
interface User {
  name: string;
  id: number;
}

class UserAccount implements User {
  name: string;
  id: number;

  constructor(name: string) {
    this.name = name;
    this.id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
  }
}

function newUser(name: string): User {
  return new UserAccount(name);
}

export { User, newUser };

That's it. A test written in TypeScript can be run directly with k6. No need for Node.js, babel, webpack, bundler, build step, etc.

Do you think modern JavaScript features make TypeScript pointless? xk6-ts can also be used to support modern JavaScript features in k6.

k6 run script.js
script.js
import { newUser } from "./user";

export default () => {
  const user = newUser("John");
  console.log(user);
};

xk6-ts can be disabled by setting the XK6_TS environment variable to false.

To ensure that runtime error messages report the correct source code position, sourcemap generation is enabled by default. Otherwise, due to transpilation and bundling, the source code position is meaningless. Sourcemap generation can be disabled by setting the value of the XK6_TS_SOURCEMAP environment variable to false.

Features

  • TypeScript language support

    k6 run script.ts
  • remote (https) TypeScript/JavaScript module support

    import { User } from 'https://example.com/user.ts'
    console.log(new User())
  • importing JSON files as JavaScript object

    import object from './example.json'
    console.log(object)
  • importing text files as JavaScript string

    import string from './example.txt'
    console.log(string)
  • mix and match JavaScript and TypeScript

    • import TypeScript module from JavaScript module
    • import JavaScript module from TypeScript module

Download

You can download pre-built k6 binaries from Releases page. Check Packages page for pre-built k6 Docker images.

Build

The xk6 build tool can be used to build a k6 that will include xk6-faker extension:

$ xk6 build --with github.com/szkiba/xk6-ts@latest

For more build options and how to use xk6, check out the xk6 documentation.

How It Works

Under the hood, xk6-ts uses the esbuild library for transpiling and bundling. To be precise, xk6-ts uses the k6pack library, which is based on esbuild.

Before the test run, transpilation and bundling are done on the fly.

Compatibility warning

xk6-ts is currently integrated into k6 by modifying the execution of the k6 run command. This is a temporary solution, the final integration will be done in a different way. This temporary integration assumes that the last argument of the k6 run command line is the name of the script file. That is, contrary to the way the original k6 run command line works, xk6-ts does not accept flags after the script file name. By the way, this assumption is not uncommon, many other commands only accept flags before positional arguments. (the original k6 run command also accepts flags after the positional argument).

Benchmarking

Setting the XK6_TS_BENCHMARK environment variable to true will log the time spent on TypeScript/JavaScript bundling. This time also includes downloading any remote modules.

xk6-enhanced's People

Contributors

mstoykov avatar szkiba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

xk6-enhanced's Issues

Feature Request: xk6-ts + Bundling node modules

Hi,

Not so much an issue, but a feature request and question.

In my K6 project, I'd like to both use typescript and bundle in node dependencies following the guide here.

I was curious if you expect it to be possible to leverage esbuild and k6-pack as you currently do in this extension and support bringing in node dependencies, or if these approaches are incompatible.

Is my best bet to abandon use of this extension and rely on babel/webpack to transpile typescript per the K6 guide I linked above?

Thanks!

K6 process hangs on larger test files due to Go buffer size issue

When using

os.Pipe()

in Go, pipes have a fixed buffer size. If the amount of data written to the pipe exceeds the buffer's capacity and there is no concurrent reader, the write operation will block until space becomes available in the buffer. This behavior can cause your program to hang if the buffer is full and the reading end (the other side of the pipe) is not actively reading the data.

This manifests as the k6 process hanging if you have somewhat large k6 javascript/typescript test files to be processed by xk6-ts loader.go file

To reproduce this simply, you can create a contrived k6 test file which is quite long (the contents of which are unimportant, I use an empty function here), simulating what it might be like in a larger codebase with multiple files and imports:

// helloworld.js

export const options = {
    scenarios: {
        per_vu_scenario: {
            executor: "per-vu-iterations",
            vus: 10,
            iterations: 10,
            startTime: "10s",
        },
    },
};

function noop() {}

export default function () {
    noop();
    noop();
    noop();
    // truncating for brevity, but repeat this function call 1500 times or so to make the file sufficiently long.
    // this must be explicit function calls, not a loop calling the function 1500 times.
}

Build k6 with xk6-ts, and run this example:

xk6 build v0.50.0 --output "./k6" --with github.com/szkiba/xk6-ts@latest
./k6 run helloworld.js

And k6 will hang indefinitely.

To fix this, use concurrent Goroutines for reading and writing. Ensure that reading from and writing to the pipe happen concurrently. This approach prevents the buffer from filling up by continuously emptying it while writing. I propose a fix similar to this as a starting point, but I am not a golang expert, so was hoping @szkiba could assist

func redirectStdin() {
    if os.Getenv("XK6_TS") == "false" {
        return
    }

    isRun, scriptIndex := isRunCommand(os.Args)
    if !isRun {
        return
    }

    filename := os.Args[scriptIndex]
    if filename == "-" {
        return
    }

    opts := &k6pack.Options{
        Filename:  filename,
        SourceMap: os.Getenv("XK6_TS_SOURCEMAP") != "false",
    }

    source, err := os.ReadFile(filepath.Clean(filename))
    if err != nil {
        logrus.WithError(err).Fatal()
        return
    }

	packStarted := time.Now()

    jsScript, err := k6pack.Pack(string(source), opts)
    if err != nil {
        logrus.WithError(err).Fatal()
        return
    }

    if os.Getenv("XK6_TS_BENCHMARK") == "true" {
	duration := time.Since(packStarted)
	logrus.WithField("extension", "xk6-ts").WithField("duration", duration).Info("Bundling completed in ", duration)
    }

    reader, writer, err := os.Pipe()
    if err != nil {
        logrus.WithError(err).Fatal()
        return
    }

    // Set up os.Stdin to be the reader before any writing happens
    originalStdin := os.Stdin
    os.Stdin = reader

    // cleanup after function exit
    defer func() {
        os.Stdin = originalStdin
        // Ensure the writer and reader is closed when done
        writer.Close() 
        reader.Close()
    }()

    // Write to the pipe in a goroutine
    go func() {
        // Close writer after writing to signal EOF
        defer writer.Close() 
        _, writeErr := writer.Write(jsScript)
        if writeErr != nil {
            logrus.WithError(writeErr).Error("Failed to write JS script to pipe")
        }
    }()
}

use k6pack

  • Use k6pack library for transpiling and bundling
  • Automatic transpilation of files with the .ts extension
  • Elimination of direct k6 dependence

Enable sourcemap by default

To ensure that runtime error messages report the correct source code position, sourcemap generation is enabled by default. Otherwise, due to transpilation and bundling, the source code position is meaningless.
Sourcemap generation can be disabled by setting the value of the XK6_TS_SOURCEMAP environment variable to false.

Readme Build Command Has Wrong Repo URL

Hello everyone,
the build command in your readme has the wrong repo and fails because of that:
xk6 build --with github.com/szkiba/xk6-ts@latest
✔️ xk6 build --with github.com/grafana/xk6-ts@latest

Also, your readme mentions incorporating the k6-faker extension which seems incorrect because I didn't get access to a faker module when trying it out.

k6 run command final form

In the description, you write "xk6-ts is currently integrated into k6 by modifying the execution of the k6 run command. This is a temporary solution, the final integration will be done in a different way."
When do you expect to finish the final integration?
Many thanks!

Register as k6 extension

In order to appear in the output of the k6 version command, register as a JavaScript module.
This is a temporary workaround, as k6 does not currently support the creation of loader/transformer extensions.

--out option is not supported

Running a test with the --out option fails with a no such file error

k6 run script.ts --out json=/tmp/output.json
FATA[0000]    error="open json=/tmp/output.json: no such file or directory"

Update after move

  • change go package name to github.com/grafana/xk6-ts
  • change k6pack dependency to github.com/grafana/k6pack
  • CODEOWNERS file with @grafana/k6-extensions group
  • change license to AGPL

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.