txiki.js 26.3.0 released, a new dawn!

txiki.js is a small and powerful JavaScript runtime. It targets the latest ECMAScript spec and implements many web platform features.

After a long while (I’m counting since release 24) txiki.js 26.3.0 has been released, and it’s the biggest release since its inception, so let’s unpack the release.

Replace wasm3 with WAMR

wasm3 was a great match for txiki.js: it was “just a bunch of C files”, easy to embed, and it just worked. Alas its creator suffered acute personal losses due to the war in Ukraine and the project development stopped.

Development never picked up, and since issues were not being solved, a contributor suggested migrating to WAMR and created a draft PR. It took a while, but it ultimately took it over and pushed it over the finish line! txiki.js now has a well supported and more featureful WASM support.

I also took the chance to modernize the WASI interface and add a couple of extra features there.

Native Windows build with MSVC

Something I wanted to do for a while was to make a better Windows build. Using MSVC, and fully static. Thanks to the move to WAMR and away from curl, making all of that happen became attainable. vcpkg helped, and the release binary is now a statically linked 5-6MB exe!

HTTP client improvements

txiki.js started out with a simple fetch polyfill, layered on top of XHR. This polyfill had some shortcomings, and I ended up vendoring it so I could make some changes to better adapt it to our internals, and modernize it, since it didn’t support streaming interfaces.

Roughly at that point I realized that rather than using XHR under the hood, it would probably be better to have a somewhat low level HTTP client which both XHR and fetch use internally. This also unlocked a big milestone for fetch in txiki.js: streaming support.

In addition, both fetch and XHR now support automatic decompression!

Web streams all the things!

Alright, let’s get with the big ones. Sockets, stdio and child process streams APIs have historically been somewhat bespoke across different runtimes (Node, Deno and Bun) but ever since the introduction of Web Streams, there seems to be convergence towards using them as the main API surface for reading and writing.

I went ahead and changed all custom APIs in txiki.js to be “Web Streams First”. There is no custom read / write API anymore, it’s Web Streams all the way down!

This suddenly makes everything more composable, and likely future proof.

Direct Sockets

Another big one. When I was browsing through WinterTC specs I noticed an interesting one, the sockets API. As I was browsing through the open issues I noticed there was a mention of Direct Sockets, a proposal Google is championing, that started out before the WinterTC one, but remained dormant for a while, but it picked up recently.

After looking at both I decided to go with Direct Sockets for now, since it’s the more complete one. I extrapolated pipe support and we are off to the races.

I’ll keep watching the space and adapt as it evolves, but the core is very similar.

Replaced curl with libwebsockets

I’ll write an in-depth article only for this one, but essentially I made the call to replace curl with libwebsockets because it gives us access to HTTP and WebSocket clients and servers with a single library.

Since we need some TLS support, I ended up using MbedTLS, since OpenSSL is way too big. This also allows me to start implementing the Subtle Crypto API on top of it going forward.

HTTP and WebSocket server

Oh boy was this a long time in the making. I had wanted this for such a long time, but needed to have all the ducks in a row. With the introduction of libwebsockets we were almost there already, so I went for it.

txiki.js now as a simple API for HTTP / WS servers, inspired by Deno, Bun and Cloudflare Workers. It’s compatible with Hono with a simple adapter too! Here is a sample:


// Run with: tjs serve examples/http-server.js
//

export default {
    fetch(request) {
        const url = new URL(request.url);

        return new Response(`Hello World!\nYou requested: ${url.pathname}\n`);
    },
};

Here is a en echo WebSocket server:

// Run with: tjs serve examples/ws-echo-server.js
//
// Connect with: websocat ws://localhost:8000
//

export default {
    fetch(request, { server }) {
        if (request.headers.get('upgrade') === 'websocket') {
            server.upgrade(request);

            return;
        }

        return new Response('This is a WebSocket server. Connect using a WebSocket client.\n');
    },
    websocket: {
        open(ws) {
            console.log('Client connected');
        },
        message(ws, data) {
            console.log(`Received: ${data}`);
            ws.sendText(`echo: ${data}`);
        },
        close(ws, code, reason) {
            console.log(`Client disconnected: ${code} ${reason}`);
        },
    },
};

Code bundling

Even though creating a standalone has been a possibility for a while with txiki.js, it was annoying that bundling had to be manually done.

With all the streams and fetch work done, it was easy to chain streams to download and decompress esbuild, so that’s what tjs bundle does first, before running it with the right command line arguments to create a bundle txiki.js will handle well. Problem solved!

New website!

To put the cherry on top (and because I was really pumped!) I decided to tackle something I had been putting back for a long time: a website for the project with the documentation and guides.

I’ve done similar things for other projects before, and the biggest problem is usually putting together the first version. Incremental improvements are easier, but getting started can feel impossible.

Well, that’s done now, so head over to txikijs.org to see it in action.

Shout out to my oldest daughter for doing the logo ❤️

Other cool stuff

Happy tinkering! As for me, I hope to make progress on TLS support and some of the subtle crypto API for the next release.

QuickJS-NG 0.10.0 released!

QuickJS is a small and embeddable JavaScript engine. It aims to support the latest ECMAScript specification. QuickJS NG is a fork of the original QuickJS project by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development.

Another few months of development, version 0.10.0 is out. Here are some notable changes

  • Implemented Array.fromAsync
  • Support os.Worker on Windows
  • Added parserless build mode
  • Added os.exePath()
  • Added promise hooks
  • Fixed reporting handled promises as unhandled in tracker

See the full changelog here.

txiki.js 24.12.0 released

txiki.js is a small and powerful JavaScript runtime. It targets the latest ECMAScript spec and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS-ng as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

Earlier this week I released version 24.12.0 featuring standalone executables, namespace reorganization, more web platform features, initial binary releases, more filesystem APIs, REPL updates and more! Check here for the full changelog, and read-on for some highlights.

Read more

txiki.js 24.6.0 released!

Long time, no post. Time to break the dry spell!

txiki.js is a small and powerful JavaScript runtime. It targets ECMAScript 2023 and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS-ng as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

This is the first release after 6 months, and a lot has happened since the last one. 103 commits to be exact. Let’s break it down.

Read more

txiki.js 23.10.0 released!

txiki.js is a small and powerful JavaScript runtime. It targets ECMAScript 2020 and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

After a few months of hiatus I’m happy to announce a new txiki.js release: 23.10.0, and it’s a good one!

This new release is packed with new features:

  • Faster startup time
  • New fs features
  • SQLite builtin module
  • Storage web APIs support
  • curl integration fixes
  • Added import.meta.path
  • Better CLI errors
  • Improved types documentation

Check the full changelog here!

This release is particularly exciting because I’ve been looking forward to integrating SQLite support for a while. I started implementing the Storage API support thinking I’d use a file for persistence, but at one point I thought I’d use a SQLite databse instead, so I went for it!

There is likely stuff to be improved specially in this new builtin, the SQLite module, but I’m happy it’s in now!

The last release was over 6 months ago, so please do check the full changelog, I almost didn’t remember all the things that were added in the months past…

Thinking ahead, it might be time to start bringing in Mbed TLS support. Maybe just hasing at first, then TLS sockets, then WebCrypto. Step by step…

txiki.js 23.1.0 released, and it’s a big one!

txiki.js is a small and powerful JavaScript runtime. It’s built on the shoulders of giants: it uses QuickJSas its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP client.

After a few months of more work I’m happy to announce a new txiki.js release, version 23.1.0, quite possibly the biggest release I’ve made, and one that paves the way for the future. Let’s dive right in!

Standard library refactor

I’ve actually gone back and forth on this one. The standard library modules started being importable as @tjs/ modules, but I later switched to having it all bundled together in @tjs/stdlib. While easier to work with, that was a mistake. It’s slower to load and the churn due to the bundles being in the repo is just annoying.

It’s also important to look around and see what others are doing. Both Node and Bun seem to have settled in using namespace:module naming for builtins, so that’s what I went with. All standard library modules are now imported like so: tjs:module.

These modules are now documented too, so you can see the full API at a glance.

CLI refactor

The CLI also got some much needed love on this one. Generally speaking the CLI allowed one to either launch a file or eval an expression, plus some modifiers for each. After giving it some though, the idea of using subcommands sounded the most appealing, so now you can do tjs run foo.js and tjs eval ”console.log(42)”

But there is more. There is a also a builtin test runner now so tjs test is a thing too!

Last, running WASI binaries directly was too easy not to do, so you can also tjs run foo.wasm now and it works as expected.

Top level await

Just when I was about ready to cut the release I noticed zamfofex had sent a patch adding top level await support to QuickJS to the mailing list. That was too good to pass so I quickly incorporated it, and it worked beautifully!

This makes writing simple scripts (and tests!) so much more pleasant! So off I went and migrated the test suite to use TLA, the examples too, and added some initial support to the REPL while I was at it!

There is even more!

While these are the highlights, there are a lot more fixes that went into the release. Please checkout the full release notes here.

txiki.js 22.11 released with FFI, WebSocket and more!

txiki.js is a small and powerful JavaScript runtime. It’s built on the shoulders of giants: it uses QuickJS as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP client.

Today I’m happy to release txiki.js 22.11, which contains a bunch of improvements that have happened during the last few months. Let’s look at some of those!

Read more

Skookum JS 0.4.0 and the plan forward

Hey there! Another Skookum JS release is out and about! It’s 0.4.0 this time, slowly making progress.

This time around the release focus was on getting the module system mode Common JS compliant and similar to Node’s. This also brought __filename and __dirname, which simplified a few tests.

There are also some improvements like simple tab completion for the CLI and some new modules, check the full changelog for details.

When I started sjs I had this idea about a JS interpreter with a more “traditional” look, rather than the inherent async model Node provides. Just for the sake of exploring. Well, live and learn, I had no idea Common JS defined more stuff than modules! Somewhat randomly I also ran into Ringo JS, which looks pretty much like what I wanted to do, but built on the JVM. So I’ve decided to follow some of the Common JS specs (open issue here), and let’s see how deep the rabbit hole goes.

commonjs