Table of contents
- What is Deno
- Differences between Node and Deno
- How dependencies and package management works in Deno
- How to keep dependencies organised in Deno
- Can you use lock files for dependencies in Deno?
- Can you use normal npm packages in Deno?
- Typescript support
- Installing Deno
- How to update Deno
- Running Deno commands
- The Deno Sandbox & Permissions
- Hello World in Deno
- More complex code examples in Deno
- Reading files in Deno
- Testing in Deno
- Examples of testing in Deno
- Running the tests in Deno
- Web standard API (such as fetch)
- The Deno Standard Library
- Where to go next
What is Deno
Deno is a new Javascript/Typescript runtime. Version 1.0.0 was released in May 2020.
It can be thought of as what NodeJS would be like if it was designed in 2020! It was created by Ryan Dahl who was the original creator of NodeJS.
Back in 2018, he gave a speech covering the things that he regretted the most about NodeJS.
Differences between Node and Deno
- Unlike Node, it does not support
require()
. Instead, all imports are done with ES Modules such asimport * as something from "http://example.com/something.ts"
. (more on this further down the page) package.json
is not a thing for Deno for module resolution.- Node has NPM. Deno does not! Dependencies are included via full URLs which the runtime will download (and cache)
- Deno is by default heavily sandboxed (like your browser is) - by default it can't access the web or the filesystem.
- Unlike Node which uses callbacks everywhere, Deno uses promises for async actions. This is a huge move towards a much cleaner, nicer and more modern way of coding.
How dependencies and package management works in Deno
- There is no use of NPM (or yarn)! No
package.json
! - There is no requirement for there to be a central place to hold all of your dependencies (see next section though). Instead, each file that has an import will directly reference it with a full URL.
- Example of an import:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
How to keep dependencies organised in Deno
You can do relative imports (like you do right now in node: require('./models/user.js')
).
I would recommend that you create one main file with all dependencies in it, then export them from that file (self-contained dependency list). Then in other files, you can import from that file.
For example, in /src/deps.ts
(which you can treat as the source for all of your dependencies, a bit like package.json):
// Your self contained dependency list of urls your entire project needs:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import { somethingElse } from "https://some-other-dependency.com/index.ts";
// ... and so on
// Export them so other files can easily access them:
export default const {
assertEquals,
somethingElse,
};
Then in your files which need to use assertEquals
:
// import from your self contained dependency list file:
import { assertEquals } from "./deps.ts";
// use it as you need!
assertEquals('something','something');
This has several benefits including the fact that you have one central location with all of your external dependencies listed (so updating is easy).
Can you use lock files for dependencies in Deno?
Deno can store and check module subresource integrity for modules using a small JSON file. Use the
--lock=lock.json
to enable and specify lock file checking. To update or create a lock use--lock=lock.json --lock-write
.
See here for more details.
Can you use normal npm packages in Deno?
The short answer is no, you cannot you normal npm packages in Deno. However, there are some easy workarounds.
To work with Deno one of the major hurdles with a lot of existing packages is that it requires ES modules (import x from y
) and all imports must have full extensions (e.g. .js
). Most packages on NPM use require (const lodash = require('lodash')
), and very few include the file extension.
An easy way to import any NPM package in deno is to use Pika CDN. Every npm package can be loaded from Pika CDN as a modern ESM import. If a package wasn't written as ESM, we'll do the work to convert it for you.
An example of loading from pika:
import {Component, render} from 'https://cdn.pika.dev/preact@^10.0.0';
Typescript support
Deno supports Javascript and Typescript, both as first-class languages. Even if your current code is only in Javascript, you can start using Typescript straight away. There is no need to think about setting everything up to compile from TyepScript to JavaScript - Deno handles it all for you.
All imports must include the full extension (.js
or .ts
), as it will not try and guess them when resolving modules.
You can still set up Typescript as normal with a tsconfig.json
file.
To run a file with a custom ts config, run deno run -c tsconfig.json some_file.ts
The default Typescript configuration in Deno is as follows:
{
"compilerOptions": {
"allowJs": false,
"allowUmdGlobalAccess": false,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"assumeChangesOnlyAffectDirectDependencies": false,
"checkJs": false,
"disableSizeLimit": false,
"generateCpuProfile": "profile.cpuprofile",
"jsx": "react",
"jsxFactory": "React.createElement",
"lib": [],
"noFallthroughCasesInSwitch": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitUseStrict": false,
"noStrictGenericChecks": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveConstEnums": false,
"removeComments": false,
"resolveJsonModule": true,
"strict": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
"useDefineForClassFields": false
}
}
Installing Deno
Installing Deno on your computer is easy.
If you are on macOS or Linux then run the following from the command line:
curl -fsSL https://deno.land/x/install/install.sh | sh
You can also use Brew to install Deno on macOS:
brew install deno
How to update Deno
It is possible to update Deno by running deno upgrade
. Use deno --version
to check what version of Deno you are running.
Running Deno commands
Deno comes with a bunch of commands. You can see all of them by running deno --help
in your terminal.
Some of the most useful commands include:
-
deno bundle
- This will combine JS and dependencies of a project into a single file
-
deno cache
- This will download and compile a module (with all of its static dependencies) and save them in the local cache. No code will be executed.
-
deno completions
- Outputs a shell completion script. Use it with something like
deno completions bash > /usr/local/etc/bash_completion.d/deno.bash
(then load it withsource /usr/local/etc/bash_completion.d/deno.bash
)
- Outputs a shell completion script. Use it with something like
-
deno doc
- Use
deno doc
to show documention for a module. - You can use it like
deno doc ./path/to/module.ts
- For JSON output
deno doc --json ./path/to/module.ts
- Use
-
deno eval
- Use
deno eval
to run Javascript. - Example:
deno eval "console.log('hello from webdevetc.com')"
- You can also use it for running TypeScript but it requires an additional argument of
-T
:deno eval -T "const v: string = 'hello'; console.log(v)"
- Use
-
deno fmt
- Format JavaScript/TypeScript automatically.
- To ignore formatting some code, add
// deno-fmt-ignore
above it. - To ignore an entire file, add
// deno-fmt-ignore-file
at the start of the file. - Usage example:
deno fmt
,deno fmt myfile1.ts myfile2.ts
- To check for formatting without writing:
deno fmt --check
- If you have ever used Go lang, then you will be familiar with Go's
fmt
function. This is very similar.
-
deno help
- Show all available commands and some debug info
-
deno info
- Use
deno info
to get information about a module. - Can use it with urls, such as
deno info https://deno.land/std/http/file_server.ts
- Use
-
deno install
- Installs a script locally, as an executable.
deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts
deno install https://deno.land/std/examples/colors.ts
- You can use arguments such as
--allow-net
or--allow-read
to give permissions to break out of the sandbox. deno install --allow-net --allow-read -n serve https://deno.land/std/http/file_server.ts
-
deno repl
- Use
deno repl
to enter the "Read-Eval-Print-Loop" mode. - This lets you type Javascript/TypeScript and it will be executed straight away.
- Great for testing things out.
- You can use the
--v8-flags=<v8-flats>
option for specific v8 engine flags
- Use
-
deno run
- Use
deno run
with a filename or URL as an argument to run it. - By default, it will run in a sandbox. Use things such as
--allow-read
or--allow-net
to give extra permissions. - Use
-A
to give all permissions.
- Use
-
deno test
- Run tests using the built-in test runner.
- It will run all tests declared with
Deno.test()
and output to standard output. - By default matches
{*_,}test.{js,ts,jsx,tsx}
-
deno types
- output type declaration file.
- Use it like
deno types > lib.deno.d.ts
-
deno upgrade
- As mentioned previously, this will upgrade Deno to the latest version
The Deno Sandbox & Permissions
The Deno sandbox is one of it's greatest features. Deno's sandbox is similar to your web browser's Javascript sandbox, which prevents accessing you files on your computer.
By default, the sandbox is enabled, which means Deno is very restricted in what it can do.
The following restrictions can be removed by allowing certain actions:
-A
or--allow-all
- Allow all permissions (use with caution!)--allow-env
- Allow environment access--allow-hrtime
- Allow high-resolution time measurement-
--allow-net
- Allow network access- You can set specific restrictions with --allow-net=
- You can set specific restrictions with --allow-net=
--allow-plugin
- Allow loading plugins-
--allow-read
- Allow file system read access- You can set specific restrictions, such as allowing access only to
/var/log
withdeno --allow-read=/var/log
- You can set specific restrictions, such as allowing access only to
--allow-run
- Allow running subprocesses-
--allow-write
- Allow file system write access- You can optionally specify what directories it can write to (similar to
--allow-read
)
- You can optionally specify what directories it can write to (similar to
(Node had no such restrictions, and could access any files, make any network request etc).
Hello World in Deno
The most basic of a Hello World example would be a file containing just console.log("Hello world!")
.
To see something with a little more going on, here is a very basic web server in Deno which will output 'Hello World':
import { serve } from "https://deno.land/std@0.50.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
req.respond({ body: "Hello World\n" });
}
More complex code examples in Deno
Reading files in Deno
The following example would work when run from the command line. Deno.args
are the arguments provided when running the file.
for (let i = 0; i < Deno.args.length; i++) {
let filename = Deno.args[i];
let file = await Deno.open(filename);
await Deno.copy(file, Deno.stdout);
file.close();
}
Testing in Deno
Deno has a fantastic built-in test runner that you can use to test your JavaScript or TypeScript code.
Examples of testing in Deno
Deno.test("hello world", () => {
const x = 1 + 2;
if (x !== 3) {
throw Error("x should be equal to 3");
}
});
It is more common to use their testing utility package, which includes helpers such as assertEquals()
. An example of that in use (along with the import) follows:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
Deno.test("hello world", () => {
const x = 1 + 2;
assertEquals(x, 3);
});
Running the tests in Deno
To run tests in Deno you can use the deno test
command:
deno test my_test.ts
The filename (my_test.ts
in the above example) is optional. If you do not include it then all tests in the current directory (recursively) that match the glob {*_,}test.{js,ts,jsx,tsx}
will be run.
If you pass a directory as then it will test all files in the directory that match {*_,}test.{js,ts,jsx,tsx}
.
Web standard API (such as fetch)
Although packages, libraries and frameworks are invented on a nearly daily basis in the Javascript world, the APIs provided by web standards are set in stone and will be around for a long time. So Deno has implemented many of them, so your code can be identical on Deno as it is for browsers.
Some of the commons ones that you should be aware of include:
addEventListener
clearInterval
clearTimeout
dispatchEvent
fetch
removeEventListener
setInterval
setTimeout
onload
onunload
self
window
The Deno Standard Library
As well as providing the Deno runtime, there is also a large official standard library. The creators of Deno put a huge amount of effort into keeping the standard library up to a very high standard.
You can see where they are hosted at deno.land/std.
These includes packages such as:
testing
- see the section on testing in this guidefs
(filesystem) - all using promises so you can useawait
with themhash
(for hashing data)datetime
to handle date and time- and many more
Where to go next
The first place you should go is DenoLand - the official home of Deno. You can read their full installation guide and get up and running in a few minutes.
Next, you should read through their easy to follow manual. Then start building things!
Please leave a comment below if you have any suggestions.
Comments →Introduction to Deno