# Deno

Deno can run JavaScript and TypeScript with no additional tools or configuration required, unlike `Node` which will require some additional libraries and configurations to work with it.

Additionally Deno by default can work as `HTTP Server`, `Routes`, `Database access`, and more.

{% embed url="<https://docs.deno.com/>" %}

## Installing Deno

Installing on Linux is simple:

```bash
curl -fsSL https://deno.land/install.sh | sh
```

Check verion with:

```bash
deno --version
```

## [Deno CLI](https://docs.deno.com/runtime/reference/cli/)

To interact with the Deno runtime environment from your terminal or command prompt.

### Execution

| Command                                                            | Description                                                    |
| ------------------------------------------------------------------ | -------------------------------------------------------------- |
| [`deno run`](https://docs.deno.com/runtime/reference/cli/run/)     | To run scripts.                                                |
| [`deno serve`](https://docs.deno.com/runtime/reference/cli/serve/) | To run a web server.                                           |
| [`deno task`](https://docs.deno.com/runtime/reference/cli/task/)   | To run tasks configured in `deno.json`. (Ex.: deno task build) |

#### [Command Line Arguments](https://docs.deno.com/runtime/getting_started/command_line_interface/#passing-script-arguments)

It is possible to provide runtime arguments to your scripts.

```bash
deno run main.ts arg1 arg2 arg3
```

Inside `main.ts` you grab the arguments with:

```typescript
console.log(Deno.args);
```

{% hint style="danger" %}
Note that anything passed after the script name will be passed as a script argument and not consumed as a Deno runtime flag.
{% endhint %}

#### [Watch mode](https://docs.deno.com/runtime/getting_started/command_line_interface/#watch-mode)

Supply the `--watch` to `run`, `test`, `fmt` to enable the built-in file watcher.

The watcher enables automatic reloading of your application whenever changes are detected on the source files.

*(Similar to* `nodemon` *for Node)*

#### Other common flags

Can be checked in the [docs](https://docs.deno.com/runtime/getting_started/command_line_interface/#common-flags).

### Dependency Management

| Command                                                                    | Description                           |
| -------------------------------------------------------------------------- | ------------------------------------- |
| [`deno add`](https://docs.deno.com/runtime/reference/cli/add)              | Add dependencies.                     |
| [`deno install`](https://docs.deno.com/runtime/reference/cli/install/)     | Install a dependency or a script.     |
| [`deno uninstall`](https://docs.deno.com/runtime/reference/cli/uninstall/) | Uninstall a dependency or a script.   |
| [`deno remove`](https://docs.deno.com/runtime/reference/cli/remove)        | Remove dependencies.                  |
| [`deno outdated`](https://docs.deno.com/runtime/reference/cli/outdated)    | View or update outdated dependencies. |

### Tooling

| Command                                                                  | Description                                     |
| ------------------------------------------------------------------------ | ----------------------------------------------- |
| [`deno upgrade`](https://docs.deno.com/runtime/reference/cli/upgrade/)   | Upgrade `deno` to last version.                 |
| [`deno init`](https://docs.deno.com/runtime/reference/cli/init/)         | Create a new project.                           |
| [`deno test`](https://docs.deno.com/runtime/reference/cli/test/)         | Run your tests.                                 |
| [`deno coverage`](https://docs.deno.com/runtime/reference/cli/coverage/) | Generate test coverage reports.                 |
| [`deno doc`](https://docs.deno.com/runtime/reference/cli/doc/)           | Generate documentation for a module.            |
| [`deno bench`](https://docs.deno.com/runtime/reference/cli/bench/)       | Benchmarking tool.                              |
| [`deno compile`](https://docs.deno.com/runtime/reference/cli/compile/)   | Compile a program into a standalone executable. |
| [`deno fmt`](https://docs.deno.com/runtime/reference/cli/fmt/)           | Format your code.                               |
| [`deno lint`](https://docs.deno.com/runtime/reference/cli/lint/)         | Lint your code.                                 |

## Deno Project

Deno configuration file is `deno.json` which is similar to the `package.json` from Node.

It will automatically recognize this file in project root folder, but an arbitrary path to the configuration file can be passed through the `--config` flag when executing Deno.

{% hint style="info" %}
Older versions of Deno used `package.json` as the configuration file, just like Node.

So, for backward compatibility it can work.
{% endhint %}

{% hint style="warning" %}
If both `deno.json` and `package.json` are present Deno will understand dependencies specified in both.

Use `deno.json` for Deno-specific configurations.

Also check more info in [#reloading-modules](#reloading-modules "mention").
{% endhint %}

### deno.json

Check a full example of the configuration file [here](https://docs.deno.com/runtime/fundamentals/configuration/#full-example).

#### [Dependencies](https://docs.deno.com/runtime/fundamentals/configuration/#dependencies)

The `"imports"` field in your `deno.json` allows you to specify dependencies used in your project.

You can use it to map bare specifiers to URLs or file paths making it easier to manage dependencies and module resolution in your applications.

#### [Tasks](https://docs.deno.com/runtime/fundamentals/configuration/#tasks) <a href="#tasks" id="tasks"></a>

The `"tasks"` field in your `deno.json` file is used to define custom commands that can be executed with the `deno task` command and allows you to tailor commands and permissions to the specific needs of your project. *(Just like* `"scripts"` *from Node)*

#### [Linting](https://docs.deno.com/runtime/fundamentals/configuration/#linting)

The `"lint"` field in the `deno.json` file is used to configure the behavior of Deno’s built-in linter.

This allows you to specify which files to include or exclude from linting, as well as customize the linting rules to suit your project’s needs.

#### [Formatting](https://docs.deno.com/runtime/fundamentals/configuration/#formatting)

The `"fmt"` field in the `deno.json` file is used to configure the behavior of Deno’s built-in code formatter.

This allows you to customize how your code is formatted, ensuring consistency across your project, making it easier to read and collaborate on.

{% hint style="info" %}
Read more about Deno default [Linting and Formatting](https://docs.deno.com/runtime/fundamentals/linting_and_formatting/).

Say goodbye to `Prettier`.
{% endhint %}

#### [Lockfile](https://docs.deno.com/runtime/fundamentals/configuration/#lockfile)

The `"lock"` field in the `deno.json` file is used to specify configuration of the lock file that Deno uses to ensure the integrity of your dependencies.

You can disable Deno from creating the `deno.lock` file with:

{% code title="deno.json" %}

```json
{
    "lock": false
}
```

{% endcode %}

Since Deno by default always add new added dependencies to the lockfile, it is also possible to freeze this lockfile *(ex. CI pipelines or production environments)* so that Deno will error when it encounter dependencies it's never seen before.

To do this you can pass the `--frozen` flag or add the configuration to `deno.json`.

{% code title="" %}

```json
{
    "lock": {
        "frozen": true
    }
}
```

{% endcode %}

#### [Typescript compiler option](https://docs.deno.com/runtime/fundamentals/configuration/#typescript-compiler-options)

The `"compilerOptions"` field in the `deno.json` file is used to configure [TypeScript compiler settings](https://www.typescriptlang.org/tsconfig) for your Deno project.

#### [Include and Exclude properties](https://docs.deno.com/runtime/fundamentals/configuration/#include-and-exclude)

Many of the configurations in `deno.json` can accept `include` and `exclude` properties.&#x20;

Check more detailed info on the docs.\\

## Node and Npm Support

### Node.js

Deno provides a compatibility layer that allows the use of Node.js built-in APIs within Deno programs.

However, in order to use them, you will need to add the `node:` specifier to any import statements that use them.

And run it with `deno run main.mjs`.

```typescript
import * as os from "node:os";
console.log(os.cpus());
```

### Npm

Deno has native support for importing npm packages by using `npm:` specifiers. For example:

```typescript
import * as emoji from "npm:node-emoji";
console.log(emoji.emojify(`:sauropod: :heart:  npm`));
```

No `npm install` is necessary before the `deno run` command and no `node_modules` folder is created.

#### Importing types

Many npm packages ship with types, you can import these and use them with types directly:

```typescript
import chalk from "npm:chalk@5";
```

### [Node to Deno Cheatcheat](https://docs.deno.com/runtime/fundamentals/node/#node-to-deno-cheatsheet)

| Node.js                                | Deno                          |
| -------------------------------------- | ----------------------------- |
| `node file.js`                         | `deno file.js`                |
| `ts-node file.ts`                      | `deno file.ts`                |
| `nodemon`                              | `deno run --watch`            |
| `node -e`                              | `deno eval`                   |
| `npm i` / `npm install`                | `deno install`                |
| `npm install -g`                       | `deno install -g`             |
| `npm run`                              | `deno task`                   |
| `eslint`                               | `deno lint`                   |
| `prettier`                             | `deno fmt`                    |
| `package.json`                         | `deno.json` or `package.json` |
| `tsc`                                  | `deno check`                  |
| `typedoc`                              | `deno doc`                    |
| `jest` / `ava` / `mocha` / `tap` / etc | `deno test`                   |
| `nexe` / `pkg`                         | `deno compile`                |
| `npm explain`                          | `deno info`                   |
| `nvm` / `n` / `fnm`                    | `deno upgrade`                |
| `tsserver`                             | `deno lsp`                    |
| `nyc` / `c8` / `istanbul`              | `deno coverage`               |
| benchmarks                             | `deno bench`                  |

## [Security & Permissions](https://docs.deno.com/runtime/fundamentals/security/)

Unless specifically enabled, a Deno script has no access to sensitive APIs like `file system access`, `network connectivity`, or `environment access`.

To do so, it is necessary to grant access to these resources with command line flags or with a runtime permission prompt.

{% hint style="danger" %}
This is a major difference from Node, where dependencies are automatically granted full access to all system I/O, potentially introducing hidden vulnerabilities into your project.
{% endhint %}

### Key Principles

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><strong>No access to I/O by default.</strong></td><td>Code executing in a Deno runtime has no access to read or write arbitrary files on the file system, to make network requests or open network listeners, to access environment variables, or to spawn subprocesses.</td><td></td></tr><tr><td><strong>No limits on the execution of code at the same privilege level.</strong></td><td></td><td></td></tr><tr><td><strong>Multiple invocations of the same application can share data.</strong></td><td>Deno provides a mechanism for multiple invocations of the same application to share data, through built in caching and KV storage APIs. Different applications can not see each other's data.</td><td></td></tr><tr><td><strong>All code executing on the same thread shares the same privilege level.</strong></td><td></td><td></td></tr><tr><td><strong>Code can not escalate its privileges without user consent.</strong></td><td></td><td></td></tr><tr><td><strong>The initial static module graph can import local files without restrictions.</strong></td><td></td><td></td></tr></tbody></table>

### Permissions

By default, access to most system I/O is denied. There are some I/O operations that are allowed in a limited capacity, even by default.

To enable these operations, the user must explicitly grant permission to the Deno runtime. This is done by passing flags to the `deno` command:

* [`--allow-read` or `--allow-write`](https://docs.deno.com/runtime/fundamentals/security/#file-system-access)
* [`--allow-net`](https://docs.deno.com/runtime/fundamentals/security/#network-access)
* [`--allow-env`](https://docs.deno.com/runtime/fundamentals/security/#environment-variables)
* [`--allow-run`](https://docs.deno.com/runtime/fundamentals/security/#subprocesses)
* [`--allow-sys`](https://docs.deno.com/runtime/fundamentals/security/#system-information)
* [`--allow-ffi`](https://docs.deno.com/runtime/fundamentals/security/#ffi)
* [`--allow-import`](https://docs.deno.com/runtime/fundamentals/security/#importing-from-the-web)

Also, during script execution, a user can grant permissions when prompted by the runtime. *(Prompts are not shown if stdout/stderr are not a TTY)*

## [Modules and Dependencies](https://docs.deno.com/runtime/fundamentals/modules/)

### Reloading Modules

By default, Deno uses a global cache directory (`DENO_DIR`) for downloaded dependencies. This cache is shared across all projects.

{% hint style="danger" %}
Have this in mind when starting projects:

* If project only have `deno.json` file, `node_modules` folder will NOT be created and dependencies will be downloaded to this global cache.
  * *It may be possible to force* `deno.json` *to create* `node_modules` *check more at docs.*
* If project have `deno.json` and `package.json` files, `node_modules` is created and dependencies are downloaded to it.
  {% endhint %}

You can force deno to refetch and recompile modules into the cache using the `--reload` flag.

```bash
# Reload everything
deno run --reload my_module.ts

# Reload a specific module
deno run --reload=jsr:@std/fs my_module.ts
```

### Third party packages

Can be imported with `jsr`, `npm` and (`https` and `http`).

#### Directly in the `.ts` files

```typescript
import { camelCase } from "jsr:@luca/cases@1.0.0";
import { say } from "npm:cowsay@1.6.0";
import { pascalCase } from "https://deno.land/x/case/mod.ts";
```

{% hint style="info" %}
Deno recommends [JSR](https://jsr.io/), the modern JavaScript registry, for third party modules. There, you'll find plenty of well documented ES modules for your projects, including the [Deno Standard Library](https://docs.deno.com/runtime/fundamentals/standard_library/).
{% endhint %}

#### In `deno.json`

To better maintain code you can also map these imports in the `"imports"` section of `deno.json`.

{% code title="deno.json" %}

```json
{
    "imports": {
        "@luca/cases": "jsr:@luca/cases@^1.0.0",
        "cowsay": "npm:cowsay@^1.6.0",
        "cases": "https://deno.land/x/case/mod.ts"
    }
}
```

{% endcode %}

```typescript
import { camelCase } from "@luca/cases";
import { say } from "cowsay";
import { pascalCase } from "cases";
```

#### With `deno add`

An even better way is to use the CLI to import these packages. It will automatically add them to the `deno.json` as `"imports"` and get the latest versions.

```bash
deno add jsr:@luca/cases
```

### [Package Version Managing](https://docs.deno.com/runtime/fundamentals/modules/#package-versions)

It is possible to be specific in what versions of packages you may want to import.

```
@scopename/mypackage           # highest version
@scopename/mypackage@16.1.0    # exact version
@scopename/mypackage@16        # highest 16.x version >= 16.0.0
@scopename/mypackage@^16.1.0   # highest 16.x version >= 16.1.0
@scopename/mypackage@~16.1.0   # highest 16.1.x version >= 16.1.0
```

### [Private Repositories](https://docs.deno.com/runtime/fundamentals/modules/#private-repositories)

Deno can also load modules from private repositories like on Github.

Deno supports sending bearer tokens when requesting a remote module.

Check more info in the docs.

## [Standard Library](https://docs.deno.com/runtime/fundamentals/standard_library/)

Deno provides a standard library written in TypeScript.

This standard library provide some packages for dealing with `json`, `path`, and many other.

The standard library is hosted on JSR and is available at: <https://jsr.io/@std>.

To install packages from the Deno Standard Library, you can use the `deno add` subcommand to add the package to your `deno.json` import map.

```bash
deno add jsr:@std/fs jsr:@std/path
```

```typescript
import { copy } from "@std/fs";
import { join } from "@std/path";
```

## [Environment Variables](https://docs.deno.com/runtime/reference/env_variables/)

There is built-in support for environment variables with `Deno.env`.

There are `getter` and `setter` methods.

```typescript
Deno.env.set("FIREBASE_API_KEY", "examplekey123");
Deno.env.set("FIREBASE_AUTH_DOMAIN", "firebasedomain.com");

console.log(Deno.env.get("FIREBASE_API_KEY")); // examplekey123
console.log(Deno.env.get("FIREBASE_AUTH_DOMAIN")); // firebasedomain.com
console.log(Deno.env.has("FIREBASE_AUTH_DOMAIN")); // true
```

#### Special Deno Environment Variables

Check [here](https://docs.deno.com/runtime/reference/env_variables/#special-environment-variables).

### `.env` Files

You can cause Deno to read environment variables from `.env` using the `--env-file` flag.

This will read `.env` by default.

```bash
deno run --env-file <script>
```

If you want or need to load environment variables from a different file, you can specify that file as a parameter to the flag.

```bash
deno run --env-file=.env.one --env-file=.env.two --allow-env <script>
```

{% hint style="warning" %}
When multiple declarations for the same environment variable exist within a single `.env` file, the first occurrence is applied.

However, if the same variable is defined across multiple `.env` files (using multiple `--env-file` arguments), the value from the last file specified takes precedence.
{% endhint %}

## [Writing Tests](https://docs.deno.com/runtime/fundamentals/testing/)

Deno have its own Test library, so there is no need to use external tools like `Jest` or others.

### Tests structures

#### Simple test

```typescript
Deno.test('', () => {});
```

#### Test steps

Deno also supports test steps, which allow you to break down tests into smaller, manageable parts.

```typescript
Deno.test("database operations", async (t) => {
    using db = await openDatabase();
    await t.step("insert user", async () => {
        // Insert user logic
    });
    await t.step("insert book", async () => {
        // Insert book logic
    });
});
```

### Assertions

Deno provides a function `assertEqual` and others for asserting expected values.

But it also provides an assert function like `Jest` `expect`.

### Running tests

Run `deno test` without a file name or directory name, this subcommand will automatically find and execute all tests in the current directory (recursively).

```bash
# Run all tests in the current directory and all sub-directories
deno test

# Run all tests in the util directory
deno test util/

# Run just my_test.ts
deno test my_test.ts

# Run test modules in parallel
deno test --parallel

# Pass additional arguments to the test file that are visible in `Deno.args`
deno test my_test.ts -- -e --foo --bar

# Provide permission for deno to read from the filesystem, which is necessary
# for the final test above to pass
deno test --allow-read my_test.ts
```

## [Debugging](https://docs.deno.com/runtime/fundamentals/debugging/)

Check the docs for more info on debugging with [VSCode](https://docs.deno.com/runtime/fundamentals/debugging/#vscode).

## Examples

Bellow some examples on doing things with Deno.

| Task                                                                                                                              |
| --------------------------------------------------------------------------------------------------------------------------------- |
| **Files**                                                                                                                         |
| [Reading a text file (`Deno.readTextFile`)](https://docs.deno.com/examples/reading_files/)                                        |
| [Writing a text file (`Deno.writeTextFile`)](https://docs.deno.com/examples/writing_files/)                                       |
| [Reading files in streams](https://docs.deno.com/examples/file_server_tutorial/)                                                  |
| **Network**                                                                                                                       |
| [Connect to the hostname and port (`Deno.connect`)](https://docs.deno.com/api/deno/~/Deno.connect)                                |
| [Announcing on the local transport address (`Deno.listen`)](https://docs.deno.com/api/deno/~/Deno.listen)                         |
| **Subprocess**                                                                                                                    |
| [Creating a subprocess (`Deno.Command`)](https://docs.deno.com/runtime/tutorials/subprocess/)                                     |
| **Error Handling**                                                                                                                |
| [Deno error classes](https://docs.deno.com/runtime/reference/deno_namespace_apis/#errors)                                         |
| **Permissions**                                                                                                                   |
| [Check at TS level if a permission was given](https://docs.deno.com/runtime/reference/deno_namespace_apis/#query-permissions)     |
| [Requesting permissions to User via CLI prompt](https://docs.deno.com/runtime/reference/deno_namespace_apis/#request-permissions) |
| [Revoking permissions at runtime](https://docs.deno.com/runtime/reference/deno_namespace_apis/#revoke-permissions)                |
| **Storage**                                                                                                                       |
| [Using LocalStorage in Deno](https://docs.deno.com/runtime/reference/web_platform_apis/#web-storage)                              |
| [Using WebWorkers in Deno](https://docs.deno.com/runtime/reference/web_platform_apis/#web-workers)                                |
| **NodeJs Modules**                                                                                                                |
| [Using node:crypto module](https://docs.deno.com/runtime/reference/node_apis/#node%3Acrypto)                                      |
| [Using node:os module](https://docs.deno.com/runtime/reference/node_apis/#node%3Aos)                                              |
| **Continuos Integration (CI)**                                                                                                    |
| [Setting up a basic pipeline](https://docs.deno.com/runtime/reference/continuous_integration/)                                    |
