deno vs ts-node : what's the difference

I'm working on a relative large typescript project, I'm using ts-node to run node testing and examples. As far as I understand, ts-node will compile ts files to js files and execute.

Recently I heard about deno, which is a typescript runtime. I tried a few examples in typescript, which works using ts-node. I ran the example with deno, there were many compile messages printed in the console, then execute the code. And later I found there's cache files in /username/.deno. I don't feel the deno execution is faster than ts-node

It seems both deno and ts-node will compile and run using cache. What's the difference between them?


Solution 1:

TL;DR

Deno is more like Node than like ts-node, i.e. it is a JS runtime based on V8. Unlike Node, Deno contains the TypeScript compiler. Deno is not part of the Node/npm ecosystem.

ts-node on the other hand is a Node.js module that uses the TypeScript compiler to transpile TypeScript code and run it in Node. ts-node is part of the Node/npm ecosystem.

Deno is fast. See below.

Deno and ts-node similarities

  • They both run TypeScript code
  • They both run on Linux, Mac and Windows (but ts-node also on SmartOS and AIX)
  • They both use the Google V8 JavaScript engine (ts-node via node that it uses under the hood)

Deno and ts-node differences

ts-node

  • ts-node is a Node.js module
  • it is written in Node.js
  • it's installed with npm
  • it uses the TypeScript compiler as a peer dependency
  • it installs its own dependencies
  • as a runtime it uses Node which is written in C++ using libuv

Deno

  • deno is a standalone executable
  • it doesn't use Node.js
  • it is distributed as a single binary
  • it contains the TypeScript compiler as a V8 snapshot
  • it has no dependencies
  • it is a runtime written in Rust using Tokio

Maturity

ts-node

ts-node relies on the Node.js runtime so it is fair to include it here:

  • Node.js was released in 2009, the latest LTS version is 14.15.0
  • npm was released in 2010, version included in Node LTS is 6.14.8
  • ts-node was released in 2015, the latest version is 9.0.0

Deno

Deno is itself a runtime so it doesn't use anything else:

  • Deno was released in 2018, the latest version is 1.5.2 check latest version here

Popularity

GitHub:

  • nodejs/node GitHub stars
  • TypeStrong/ts-node GitHub stars
  • denoland/deno GitHub stars

Stack Overflow:

  • Questions tagged 'node.js': 358,962
  • Questions tagged 'typescript': 132,043
  • Questions tagged 'ts-node': 199
  • Questions tagged 'deno': 320

Libraries

ts-node

You can use all Node libraries available on npm

(currently there are 955,263 packages on npm, not all of them for Node but still a lot)

The Node libraries that are available on npm even if they were originally written in TypeScript are usually published in a form transpiled to JavaScript with additional type definitions in *.d.ts files (included in the npm package or installed separately from the @types namespace).

Deno

There are 1256 third-party modules on https://deno.land/x/ and 56 libraries and tools on https://github.com/denolib/awesome-deno#modules (I didn't check if all are the same)

The Deno libraries are just TypeScript files.

Installation difference

ts-node

  • you install Node.js
    • https://nodejs.org/en/download/
    • the v10 (current LTS) on Mac and Linux is around 65MB in 4500 files
  • you install typescript and ts-node with their dependencies with npm
    • npm install typescript ts-node
    • it installs 10 npm modules and puts 44MB in 212 files into node_modules

Deno

  • you download a single binary
    • https://github.com/denoland/deno/releases
    • the uncompressed binary of v0.3.6 on Mac and Linux is around 47MB and 41MB on Windows

Your code differences

ts-node

  • your code works the same as if it were transpiled with tsc and run with node (because it is under the hood)
  • you can use the Node API
  • you can use all built-in Node modules
  • you can use modules from npm
  • you can import files using relative paths (usually without .ts suffix)
  • you can import the dependencies installed with npm (or yarn) in node_modules

Deno

  • your code doesn't work the same as in Node (because it isn't run with Node)
  • you use the Deno API
  • you can use the Deno built-in modules
  • you can use other Deno modules that are available
  • you can import files using relative paths (always with .ts suffix!)
  • you can import URLs directly from the Web (no need for npm install)

Examples

Here is an example of publishing a minimal library written in TypeScript and using it.

Creating and using a TypeScript library with Node and ts-node

This is what I am doing right now with an example project on:

https://github.com/rsp/node-ts-hello

Creating library:

  1. find a name that is free on npm (no longer enough, see below)
  2. create repo on GitHub
  3. create package.json with npm init
  4. install TypeScript compiler with npm install typescript
  5. decide if you're keeping package-lock.json in the repo (there are pros and cons)
  6. create a src dir where you will keep TypeScript files
  7. add hello.ts to src
  8. add tsconfig.json file and make sure to:
  • add "src/**/*" to "include"
  • add dependencies and your own types to "paths"
  • add "outDir": "dist" to put the JS files in a known place
  • add the dist directory to .gitignore so that compiled files are not in git
  • add the same as in .gitignore but without dist in .npmignore
    (or otherwise you will not publish the most important files, see below)
  • add "declaration": true so you have *.d.ts files generated
  1. add "main": "dist/hello.js" in package.json (note the "js" suffix)
  2. add "types": "dist/hello.d.ts" in package.json (note the "ts" suffix)
  3. add "build": "tsc" to package.json (watch out for redundant files, see below)
  4. login with npm login (you shouldn't be logged in all the time - see: Now Pushing Malware: NPM package dev logins slurped by hacked tool popular with coders)
  5. compile the project with npm run build
  6. publish the package with npm publish
  • when you get npm ERR! publish Failed PUT 401 you need to login with npm login
  • when you get npm ERR! publish Failed PUT 403 your package may be "too similar to existing packages" - try renaming it in package.json, rename the repo and update all liks to readme, issues itp. in package.json
  1. logout from npm with npm logout
  2. see your ~/.npmrc and make sure you have nothing like this left:
  • //registry.npmjs.org/:_authToken=...

Using the library in other project using ts-node

  1. create a new directory
  2. create a package.json file with npm init
  • (so that you can install dependencies locally for your new program)
  1. install our library with npm install node-ts-hello
  2. optionally install ts-node with npm install typescript ts-node
  • (unless it's installed globally)
  1. add hi.ts file that imports our library with:
  • import { hello } from 'node-ts-hello';
  • hello('TS');
  1. run it with npx ts-node hi.ts (if ts-node was installed locally) or ts-node hi.ts (if ts-node was installed globally)
  • if you get errors, see below

Potential problems: I simplified the above a little bit, my actual process of creating that library is described here.

Creating and using a TypeScript library with Deno

This is what I am doing right now with an example project on:

https://github.com/rsp/deno-hello

Creating library:

  1. create repo on GitHub
  2. put hello.ts in the repo

Using library:

  1. Create a file hi.ts with the contents:
  • import { hello } from 'https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts';
  • hello('TS');
  1. Run your program with deno run hi.ts

The first run will print:

$ deno run hi.ts 
Compiling file:///Users/rsp/talks/deno/hello-deno-test/hi.ts
Downloading https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts
Compiling https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts
Hello, TS!

The second run:

$ deno run hi.ts 
Hello, TS!

If you change hi.ts it will be recompiled but the dependencies will not get downloaded again:

$ deno run hi.ts 
Compiling file:///Users/rsp/talks/deno/hello-deno-test/hi.ts
Hello, TS!

(Note that touch hi.ts will not be enough, you need to make the actual changes because Deno checks the file checksum, not the timestamp.)

Speed

ts-node

The speed of starting the ts-node version of our hi.ts from the examples above:

$ time npx ts-node hi.ts 
Hello, TS!

real    0m0.904s
user    0m1.300s
sys     0m0.083s

This is after the dependencies are already installed and after running several times to make sure that all of the caching works. Almost one second.

Deno

The speed of starting the Deno version of our hi.ts from the examples above:

$ time deno run hi.ts 
Hello, TS!

real    0m0.028s
user    0m0.010s
sys     0m0.015s

This is also after the dependencies are already installed and after running several times to make sure that all of the caching works.

More than 32x speed improvement.

Summary

Deno should be compared more with Node than with ts-node because Deno is an entirely new runtime while ts-node is a module for Node so your program run with ts-node really use the Node runtime.

It is a very young project but has already got a lot of traction. It doesn't have as much documentation or libraries as Node but it means that it may be the best time to get involved because when it gets more popular, and I think it will for many reasons that are beyond the scope of this answer, people who already have experience with it will be needed on the market, like it was with Node.

The program startup speed is already very impressive and I expect more improvements there.

The development speed of using single files with no need for configuration like package.json or node_modules together with a possibility to import dependencies directly from URLs (like on the frontend) will make it possible to work in a different way both for the end user code and for the libraries. We'll see how it all works in practice but it already looks promising.

Solution 2:

ts-node is based on Node, while Deno is a completely different and new server-side runtime, with design changes on API, module systems, security model, etc. (which reflects better of the post ES6 developments). Also, the TypeScript compiler lives directly inside of the single Deno executable (through V8 snapshots) and thus should have a shorter startup time.

Solution 3:

I think @rsp has already posted detailed info related to Deno.

I want to put some key points here so that others can easily put their eyes on key difference:

  • Language- Deno is based on RUST language - Rust is a multi-paradigm programming language focused on performance and safety, especially safe concurrency. Rust is syntactically similar to C++, but provides memory safety without using garbage collection

  • Runtime- Deno also relies on the V8 engine.

  • Security — A common criticism of Node.js is that once a node app is running, it can easily access the file system or the network etc. While Deno asks user permission to allow use of resuorces like net, file system etc.

  • NPM?- Deno does not rely on NPM at all, instead of this we import our libraries via the URL.

Example:

> import { serve } from "https://deno.land/std/http/server.ts";

All the library we want to use is downloaded first then cached it.

  • Window Object- Good news is that now we can use the Window Object in Deno which is not available in Node.js. Window Object has much rich APIs which can help a lot in Deno for development.
  • Import- Deno use ES6 import in inject the module in files.
  • Typescript- Deno fully supports typescript.