We'll be benchmarking execution of Microsoft TypeScript .ts
file execution in canary/nightly Deno, Bun, Node.js.
deno
and bun
have been capable of executing .ts
files directly for a while. node
recently added that capability; initially behind a flags --experimental-strip-types
or --experimental-transform-types
,
now without a flag being necessary; see Modules: TypeScript | Node.js v23.6.0 Documentation and
2025-01-07, Version 23.6.0 (Current) #56450.
The file being tested is a standalone Native Messaging test. That is, testing the Native Messaging protocol outside of the browser.
For completeness here is Native Messaging description as appears in Chrome Developers, MDN Web Docs, Microsoft Edge Developer documentation, and Safari web extension documentation
- Chrome Developers
- MDN Web Docs
- Microsoft Edge Developer documentation
- Messaging between the app and JavaScript in a Safari web extension
This is the protocol
Native messaging protocol (Chrome Developers)
Chrome starts each native messaging host in a separate process and communicates with it using standard input (
stdin
) and standard output (stdout
). The same format is used to send messages in both directions; each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB, mainly to protect Chrome from misbehaving native applications. The maximum size of the message sent to the native messaging host is 4 GB.
The test when run standalone, without benchmarking, should print this output, a representation of the communication between the browser and the native application, shell script, or program that implements the host
deno -A nm_standalone_test.js ./nm_typescript.ts native-messaging-extension://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{ messageLength: 1048576 }
[
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null,
... 209615 more items
]
{ messageLength: 6 }
test
{ messageLength: 2 }
{ messageLength: 1 }
1
{ messageLength: 8 }
{ "0": 97 }
The file being tested is below, nm_typescript.ts
. We'll be manually adjusting the shebang line to the given JavaScript/TypeScript
runtime between tests.
The file that we will be using to simulate the communication between the browser and the Native Messaging host is nm_standalone_test.js
,
where we start a subprocess to execute nm_typescript.ts
, implementing the Native Messaging protocol. We have embedded the text
of nm_typescript.ts
in the benchmarking code, which uses Deno.bench()
.
Notice in nm_typescript.ts
JavaScript runtimes do not process stdin
and stdout
the same. ECMA-262 does not specify I/O for
JavaScript. JavaScript engines and runtimes may, or may not, implement reading stdin
and writing to stdout
.
What I have done is use WHATWG Streams for reading stdin
and writing to stdout
, in an effort to use the same or mostly similar
code for each runtime, for the ability to actually test the same code in each runtime, in a runtime agnostic manner.
We'll be testing using the lastest deno
and bun
canary releases, and node
nightly fetched from the respective sources, today.
deno
2.1.6+b962b87 (canary, release, x86_64-unknown-linux-gnu)bun
1.1.45node
v24.0.0-nightly20250119009d53ec3c
Adjusting the shebang for each runtime
#!/usr/bin/env -S /home/user/deno -A
#!/usr/bin/env -S /home/user/bun
#!/usr/bin/env -S /home/user/node --no-warnings
Executed at the command line as
deno bench -A --json bench.js
deno
"min": 361970514.0,
"max": 387731958.0,
"avg": 370500352.0,
bun
"min": 361437526.0,
"max": 393814717.0,
"avg": 385186260.0,
node
"min": 479875419.0,
"max": 517102463.0,
"avg": 502455798.0,
Bun yields the fastest min
, Deno yields the fastest avg
, Node.js yields the slowest min
, avg
, and max
for executing .ts
file.