nitrogql logonitrogql

nitrogql 1.7 release: Jest transform, async internals

Published at March 31, 2023

Today, we are happy to announce release of nitrogql 1.7!

nitrogql is a toolchain for using GraphQL in TypeScript projects. In 1.7, we added a new package named @nitrogql/jest-transform. This package is a Jest transformer that lets you load .graphql files from your code during testing. Also, we made some improvements to the internals of nitrogql.

Jest transform

nitrogql recommends importing GraphQL files directly in your code. This allows us to maximize type safety and editor support, avoiding all those subtle problems that come with mixing GraphQL and TypeScript in out file.

Previously, this posed a problem when testing the code. We only provided Webpack loader and Rollup plugin, which were good for building the project, but not for testing with Jest.

With the new @nitrogql/jest-transform package, we also support this use case. You can now test code that uses GraphQL without any hassle.

Below is an example of how to use @nitrogql/jest-transform in your Jest configuration:

{
  "transform": {
    "^.+\.graphql$": ["@nitrogql/jest-transform", {
      "configFile":  path.resolve(__dirname, "nitrogql.config.js")
    }],
  }
}

Also, we've noticed that there is a need for additional transformation after the GraphQL files are loaded. This is because nitrogql only transforms GraphQL files to ES modules, and some projects need CommonJS support.

To address this, we added the additionalTransformer option to @nitrogql/jest-transform. You can now apply another transformer that can convert ES modules to CommonJS. In practice, your Jest configuration might look like this:

{
  "transform": {
    "^.+\.graphql$": ["@nitrogql/jest-transform", {
      "configFile":  path.resolve(__dirname, "nitrogql.config.js"),
      "additionalTransformer": ["ts-jest", { isolatedModules: true }],
    }],
  }
}

We hope that this new package will make it easier for you to test your GraphQL code.

Async internals

Since 1.6, we also made some improvements to the internals of nitrogql. Now, async Rust is used for parts of the codebase. This change is mostly internal, but it allows future improvements to the performance of nitrogql.

Since nitrogql is written in Rust and compiled to WebAssembly, it should be generally fast. However, there is a critically slow feature in nitrogql: JavaScript execution. As nitrogql allows using JavaScript for configuration file and scalar definitions, it needs to execute JavaScript code at runtime. This is done by delegating execution to Node.js.

For a couple of reasons, using Node.js for this task has been slow. First, a separate process is spawned for each execution. Second, the Node.js' module loading customization hooks have extreme overhead.

While we cannot eliminate these problems entirely, we can mitigate them by making communication with Node.js asynchronous. This is what we did in 1.7. Doing so allows us to reuse the same Node.js process for multiple executions, reducing the overhead of spawning processes.

Synchronous nature of Node.js and WebAssembly

Currently, execution of a WebAssembly module from Node.js is synchronous. That is, JavaScript code and WebAssembly code share the same thread and they appear in the same call stack. While there are multiple ongoing proposals to bake asynchronous execution into WebAssembly, they are not yet available.

Within this limitation, we had to make the communication between nitrogql and Node.js asynchronous. Particularly, we wanted to use Futures in Rust code to represent asynchronous communication with Node.js.

To achieve this, standard async executors like Tokio and async-std were not suitable. Instead, we developed a custom async executor that is specifically designed to integrate WebAssembly into Node.js' event loop. Async-executor was a great for building this custom executor on top of. More details are available in this article (Japanese).

Conclusion

nitrogql 1.7 is a release that makes it easier to test your GraphQL code with Jest. We hope that you will find this new package useful. Also, we made some improvements to the internals of nitrogql, which will allow us to improve the performance in the future.


nitrogql is developed by uhyo. Contribution is more than welcome!