diff options
Diffstat (limited to 'std/manual.md')
-rw-r--r-- | std/manual.md | 1280 |
1 files changed, 1280 insertions, 0 deletions
diff --git a/std/manual.md b/std/manual.md new file mode 100644 index 000000000..045aaab34 --- /dev/null +++ b/std/manual.md @@ -0,0 +1,1280 @@ +# Deno Manual + +[toc] + +## Project Status / Disclaimer + +**A word of caution: Deno is very much under development.** + +We encourage brave early adopters, but expect bugs large and small. The API is +subject to change without notice. +[Bug reports](https://github.com/denoland/deno/issues) do help! + +We are +[actively working towards 1.0](https://github.com/denoland/deno/issues/2473), +but there is no date guarantee. + +## Introduction + +Deno is a JavaScript/TypeScript runtime with secure defaults and a great +developer experience. + +It's built on V8, Rust, and Tokio. + +### Feature Highlights + +- Secure by default. No file, network, or environment access (unless explicitly + enabled). +- Supports TypeScript out of the box. +- Ships a single executable (`deno`). +- Has built in utilities like a dependency inspector (`deno info`) and a code + formatter (`deno fmt`). +- Has + [a set of reviewed (audited) standard modules](https://github.com/denoland/deno/tree/master/std) + that are guaranteed to work with Deno. +- Scripts can be bundled into a single javascript file. + +### Philosophy + +Deno aims to be a productive and secure scripting environment for the modern +programmer. + +Deno will always be distributed as a single executable. Given a URL to a Deno +program, it is runnable with nothing more than +[the 10 megabyte zipped executable](https://github.com/denoland/deno/releases). +Deno explicitly takes on the role of both runtime and package manager. It uses a +standard browser-compatible protocol for loading modules: URLs. + +Among other things, Deno is a great replacement for utility scripts that may +have been historically written with bash or python. + +### Goals + +- Only ship a single executable (`deno`). +- Provide Secure Defaults + - Unless specifically allowed, scripts can't access files, the environment, or + the network. +- Browser compatible: The subset of Deno programs which are written completely + in JavaScript and do not use the global `Deno` namespace (or feature test for + it), ought to also be able to be run in a modern web browser without change. +- Provide built-in tooling like unit testing, code formatting, and linting to + improve developer experience. +- Does not leak V8 concepts into user land. +- Be able to serve HTTP efficiently + +### Comparison to Node.js + +- Deno does not use `npm` + - It uses modules referenced as URLs or file paths +- Deno does not use `package.json` in its module resolution algorithm. +- All async actions in Deno return a promise. Thus Deno provides different APIs + than Node. +- Deno requires explicit permissions for file, network, and environment access. +- Deno always dies on uncaught errors. +- Uses "ES Modules" and does not support `require()`. Third party modules are + imported via URLs: + +```javascript +import * as log from "https://deno.land/std/log/mod.ts"; +``` + +### Other key behaviors + +- Remote code is fetched and cached on first execution, and never updated until + the code is run with the `--reload` flag. (So, this will still work on an + airplane.) +- Modules/files loaded from remote URLs are intended to be immutable and + cacheable. + +## Built-in Deno Utilities / Commands + +<!-- prettier-ignore-start --> +<!-- prettier incorrectly moves the coming soon links to new lines --> + +- dependency inspector (`deno info`) +- code formatter (`deno fmt`) +- bundling (`deno bundle`) +- runtime type info (`deno types`) +- test runner (`deno test`) +- command-line debugger (`--debug`) [coming soon](https://github.com/denoland/deno/issues/1120) +- linter (`deno lint`) [coming soon](https://github.com/denoland/deno/issues/1880) + +<!-- prettier-ignore-end --> + +## Setup + +### Binary Install + +Deno works on OSX, Linux, and Windows. Deno is a single binary executable. It +has no external dependencies. + +[deno_install](https://github.com/denoland/deno_install) provides convenience +scripts to download and install the binary. + +Using Shell: + +```shell +curl -fsSL https://deno.land/x/install/install.sh | sh +``` + +Using PowerShell: + +```shell +iwr https://deno.land/x/install/install.ps1 -useb | iex +``` + +Using [Scoop](https://scoop.sh/) (windows): + +```shell +scoop install deno +``` + +Using [Homebrew](https://brew.sh/) (mac): + +```shell +brew install deno +``` + +To install from source: + +```shell +cargo install deno_cli +``` + +Deno binaries can also be installed manually, by downloading a tarball or zip +file at +[github.com/denoland/deno/releases](https://github.com/denoland/deno/releases). +These packages contain just a single executable file. You will have to set the +executable bit on Mac and Linux. + +Once it's installed and in your `$PATH`, try it: + +```shell +deno https://deno.land/welcome.ts +``` + +### Build from source + +Clone on Linux or Mac: + +```bash +git clone --recurse-submodules https://github.com/denoland/deno.git +``` + +On Windows, a couple extra steps are required to clone because we use symlinks +in the repository. First +[enable "Developer Mode"](https://www.google.com/search?q=windows+enable+developer+mode) +(otherwise symlinks would require administrator privileges). Then you must set +`core.symlinks=true` before the checkout is started. + +```bash +git config --global core.symlinks=true +git clone --recurse-submodules https://github.com/denoland/deno.git +``` + +Now we can start the build: + +```bash +# Build. +cargo build -vv + +# Run. +./target/debug/deno tests/002_hello.ts + +# Test. +cargo test + +# Format code. +./tools/format.py +``` + +#### Prerequisites + +To ensure reproducible builds, Deno has most of its dependencies in a git +submodule. However, you need to install separately: + +1. [Rust](https://www.rust-lang.org/en-US/install.html) >= 1.36.0 +2. Python 2. + [Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578). + +Extra steps for Mac users: install [XCode](https://developer.apple.com/xcode/) +:( + +Extra steps for Windows users: + +<!-- prettier-ignore-start --> +<!-- see https://github.com/prettier/prettier/issues/3679 --> + +1. Add `python.exe` to `PATH` (e.g. `set PATH=%PATH%;C:\Python27\python.exe`) +2. Get [VS Community 2017](https://www.visualstudio.com/downloads/) with + "Desktop development with C++" toolkit and make sure to select the following + required tools listed below along with all C++ tools. + - Windows 10 SDK >= 10.0.17134 + - Visual C++ ATL for x86 and x64 + - Visual C++ MFC for x86 and x64 + - C++ profiling tools +3. Enable "Debugging Tools for Windows". Go to "Control Panel" → "Programs" → + "Programs and Features" → Select "Windows Software Development Kit - Windows + 10" → "Change" → "Change" → Check "Debugging Tools For Windows" → "Change" -> + "Finish". +4. Make sure you are using git version 2.19.2.windows.1 or newer. + +<!-- prettier-ignore-end --> + +#### Other useful commands + +```bash +# Call ninja manually. +ninja -C target/debug + +# Build a release binary. +cargo build --release + +# List executable targets. +gn --root=core/libdeno ls target/debug "//:*" --as=output --type=executable + +# List build configuration. +gn --root=core/libdeno args target/debug/ --list + +# Edit build configuration. +gn --root=core/libdeno args target/debug/ + +# Describe a target. +gn --root=core/libdeno desc target/debug/ :deno +gn help + +# Update third_party modules +git submodule update + +# Skip downloading binary build tools and point the build +# to the system provided ones (for packagers of deno ...). +export DENO_BUILD_ARGS="clang_base_path=/usr clang_use_chrome_plugins=false" +DENO_NO_BINARY_DOWNLOAD=1 DENO_GN_PATH=/usr/bin/gn cargo build +``` + +Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`, +`DENO_DIR`, `DENO_GN_PATH`, `DENO_NO_BINARY_DOWNLOAD`. + +## API reference + +### deno types + +To get an exact reference of deno's runtime API, run the following in the +command line: + +```shell +$ deno types +``` + +[This is what the output looks like.](https://gist.github.com/ry/46da4724168cdefa763e13207d27ede5) + +### Reference websites + +[TypeScript Deno API](https://deno.land/typedoc/index.html). + +If you are embedding deno in a Rust program, see +[Rust Deno API](https://docs.rs/deno). + +The Deno crate is hosted on [crates.io](https://crates.io/crates/deno). + +## Examples + +### An implementation of the unix "cat" program + +In this program each command-line argument is assumed to be a filename, the file +is opened, and printed to stdout. + +```ts +for (let i = 1; i < Deno.args.length; i++) { + let filename = Deno.args[i]; + let file = await Deno.open(filename); + await Deno.copy(Deno.stdout, file); + file.close(); +} +``` + +The `copy()` function here actually makes no more than the necessary kernel -> +userspace -> kernel copies. That is, the same memory from which data is read +from the file, is written to stdout. This illustrates a general design goal for +I/O streams in Deno. + +Try the program: + +```shell +$ deno --allow-read https://deno.land/std/examples/cat.ts /etc/passwd +``` + +### TCP echo server + +This is an example of a simple server which accepts connections on port 8080, +and returns to the client anything it sends. + +```ts +const listener = Deno.listen({ port: 8080 }); +console.log("listening on 0.0.0.0:8080"); +while (true) { + const conn = await listener.accept(); + Deno.copy(conn, conn); +} +``` + +When this program is started, it throws PermissionDenied error. + +```shell +$ deno https://deno.land/std/examples/echo_server.ts +error: Uncaught PermissionDenied: run again with the --allow-net flag +► $deno$/dispatch_json.ts:40:11 + at DenoError ($deno$/errors.ts:20:5) + ... +``` + +For security reasons, Deno does not allow programs to access the network without +explicit permission. To allow accessing the network, use a command-line flag: + +```shell +$ deno --allow-net https://deno.land/std/examples/echo_server.ts +``` + +To test it, try sending data to it with netcat: + +```shell +$ nc localhost 8080 +hello world +hello world +``` + +Like the `cat.ts` example, the `copy()` function here also does not make +unnecessary memory copies. It receives a packet from the kernel and sends back, +without further complexity. + +### Inspecting and revoking permissions + +Sometimes a program may want to revoke previously granted permissions. When a +program, at a later stage, needs those permissions, it will fail. + +```ts +const { permissions, revokePermission, open, remove } = Deno; + +// lookup a permission +if (!permissions().write) { + throw new Error("need write permission"); +} + +const log = await open("request.log", "a+"); + +// revoke some permissions +revokePermission("read"); +revokePermission("write"); + +// use the log file +const encoder = new TextEncoder(); +await log.write(encoder.encode("hello\n")); + +// this will fail. +await remove("request.log"); +``` + +### File server + +This one serves a local directory in HTTP. + +```bash +deno install file_server https://deno.land/std/http/file_server.ts --allow-net --allow-read +``` + +Run it: + +```shell +$ file_server . +Downloading https://deno.land/std/http/file_server.ts... +[...] +HTTP server listening on http://0.0.0.0:4500/ +``` + +And if you ever want to upgrade to the latest published version: + +```shell +$ file_server --reload +``` + +### Reload specific modules + +Sometimes we want to upgrade only some modules. You can control it by passing an +argument to a `--reload` flag. + +To reload everything + +`--reload` + +To reload all standard modules + +`--reload=https://deno.land/std` + +To reload specific modules (in this example - colors and file system utils) use +a comma to separate URLs + +`--reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts` + +### Permissions whitelist + +Deno also provides permissions whitelist. + +This is an example to restrict File system access by whitelist. + +```shell +$ deno --allow-read=/usr https://deno.land/std/examples/cat.ts /etc/passwd +error: Uncaught PermissionDenied: run again with the --allow-read flag +► $deno$/dispatch_json.ts:40:11 + at DenoError ($deno$/errors.ts:20:5) + ... +``` + +You can grant read permission under `/etc` dir + +```shell +$ deno --allow-read=/etc https://deno.land/std/examples/cat.ts /etc/passwd +``` + +`--allow-write` works same as `--allow-read`. + +This is an example to restrict host. + +```ts +const result = await fetch("https://deno.land/"); +``` + +```shell +$ deno --allow-net=deno.land https://deno.land/std/examples/curl.ts https://deno.land/ +``` + +### Run subprocess + +[API Reference](https://deno.land/typedoc/index.html#run) + +Example: + +```ts +// create subprocess +const p = Deno.run({ + args: ["echo", "hello"] +}); + +// await its completion +await p.status(); +``` + +Run it: + +```shell +$ deno --allow-run ./subprocess_simple.ts +hello +``` + +Here a function is assigned to `window.onload`. This function is called after +the main script is loaded. This is the same as +[onload](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload) +of the browsers, and it can be used as the main entrypoint. + +By default when you use `Deno.run()` subprocess inherits `stdin`, `stdout` and +`stderr` of parent process. If you want to communicate with started subprocess +you can use `"piped"` option. + +```ts +const fileNames = Deno.args.slice(1); + +const p = Deno.run({ + args: [ + "deno", + "run", + "--allow-read", + "https://deno.land/std/examples/cat.ts", + ...fileNames + ], + stdout: "piped", + stderr: "piped" +}); + +const { code } = await p.status(); + +if (code === 0) { + const rawOutput = await p.output(); + await Deno.stdout.write(rawOutput); +} else { + const rawError = await p.stderrOutput(); + const errorString = new TextDecoder().decode(rawError); + console.log(errorString); +} + +Deno.exit(code); +``` + +When you run it: + +```shell +$ deno run --allow-run ./subprocess.ts <somefile> +[file content] + +$ deno run --allow-run ./subprocess.ts non_existent_file.md + +Uncaught NotFound: No such file or directory (os error 2) + at DenoError (deno/js/errors.ts:22:5) + at maybeError (deno/js/errors.ts:41:12) + at handleAsyncMsgFromRust (deno/js/dispatch.ts:27:17) +``` + +### Linking to third party code + +In the above examples, we saw that Deno could execute scripts from URLs. Like +browser JavaScript, Deno can import libraries directly from URLs. This example +uses a URL to import a test runner library: + +```ts +import { test, runIfMain } from "https://deno.land/std/testing/mod.ts"; +import { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + +test(function t1() { + assertEquals("hello", "hello"); +}); + +test(function t2() { + assertEquals("world", "world"); +}); + +runIfMain(import.meta); +``` + +Try running this: + +```shell +$ deno run test.ts +running 2 tests +test t1 ... ok +test t2 ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + +``` + +Note that we did not have to provide the `--allow-net` flag for this program, +and yet it accessed the network. The runtime has special access to download +imports and cache them to disk. + +Deno caches remote imports in a special directory specified by the `$DENO_DIR` +environmental variable. It defaults to the system's cache directory if +`$DENO_DIR` is not specified. The next time you run the program, no downloads +will be made. If the program hasn't changed, it won't be recompiled either. The +default directory is: + +- On Linux/Redox: `$XDG_CACHE_HOME/deno` or `$HOME/.cache/deno` +- On Windows: `%LOCALAPPDATA%/deno` (`%LOCALAPPDATA%` = `FOLDERID_LocalAppData`) +- On macOS: `$HOME/Library/Caches/deno` +- If something fails, it falls back to `$HOME/.deno` + +**But what if `https://deno.land/` goes down?** Relying on external servers is +convenient for development but brittle in production. Production software should +always bundle its dependencies. In Deno this is done by checking the `$DENO_DIR` +into your source control system, and specifying that path as the `$DENO_DIR` +environmental variable at runtime. + +**How do you import to a specific version?** Simply specify the version in the +URL. For example, this URL fully specifies the code being run: +`https://unpkg.com/liltest@0.0.5/dist/liltest.js`. Combined with the +aforementioned technique of setting `$DENO_DIR` in production to stored code, +one can fully specify the exact code being run, and execute the code without +network access. + +**It seems unwieldy to import URLs everywhere. What if one of the URLs links to +a subtly different version of a library? Isn't it error prone to maintain URLs +everywhere in a large project?** The solution is to import and re-export your +external libraries in a central `deps.ts` file (which serves the same purpose as +Node's `package.json` file). For example, let's say you were using the above +testing library across a large project. Rather than importing +`"https://deno.land/std/testing/mod.ts"` everywhere, you could create a +`deps.ts` file that exports the third-party code: + +```ts +export { test, assertEquals } from "https://deno.land/std/testing/mod.ts"; +``` + +And throughout the same project, you can import from the `deps.ts` and avoid +having many references to the same URL: + +```ts +import { test, assertEquals } from "./deps.ts"; +``` + +This design circumvents a plethora of complexity spawned by package management +software, centralized code repositories, and superfluous file formats. + +### Using external type definitions + +Deno supports both JavaScript and TypeScript as first class languages at +runtime. This means it requires fully qualified module names, including the +extension (or a server providing the correct media type). In addition, Deno has +no "magical" module resolution. + +The out of the box TypeScript compiler though relies on both extension-less +modules and the Node.js module resolution logic to apply types to JavaScript +modules. + +In order to bridge this gap, Deno supports compiler hints that inform Deno the +location of `.d.ts` files and the JavaScript code they relate to. A compiler +hint looks like this: + +```ts +// @deno-types="./foo.d.ts" +import * as foo from "./foo.js"; +``` + +Where the hint affects the next `import` statement (or `export ... from` +statement) where the value of the `@deno-types` will be substituted at compile +time instead of the specified module. Like in the above example, the Deno +compiler will load `./foo.d.ts` instead of `./foo.js`. Deno will still load +`./foo.js` when it runs the program. + +**Not all type definitions are supported.** + +Deno will use the compiler hint to load the indicated `.d.ts` files, but some +`.d.ts` files contain unsupported features. Specifically, some `.d.ts` files +expect to be able to load or reference type definitions from other packages +using the module resolution logic. For example a type reference directive to +include `node`, expecting to resolve to some path like +`./node_modules/@types/node/index.d.ts`. Since this depends on non-relative +"magical" resolution, Deno cannot resolve this. + +**Why not use the triple-slash type reference?** + +The TypeScript compiler supports triple-slash directives, including a type +reference directive. If Deno used this, it would interfere with the behavior of +the TypeScript compiler. + +### Testing if current file is the main program + +To test if the current script has been executed as the main input to the program +check `import.meta.main`. + +```ts +if (import.meta.main) { + console.log("main"); +} +``` + +## Command line interface + +### Flags + +Use `deno help` to see the help text. + +``` +deno +A secure runtime for JavaScript and TypeScript built with V8, Rust, and Tokio. + +Docs: https://deno.land/manual.html +Modules: https://deno.land/x/ +Bugs: https://github.com/denoland/deno/issues + +To run the REPL: + + deno + +To execute a sandboxed script: + + deno https://deno.land/welcome.ts + +To evaluate code from the command line: + + deno eval "console.log(30933 + 404)" + +To get help on the another subcommands (run in this case): + + deno help run + +USAGE: + deno [OPTIONS] [SUBCOMMAND] + +OPTIONS: + -A, --allow-all Allow all permissions + --allow-env Allow environment access + --allow-hrtime Allow high resolution time measurement + --allow-net=<allow-net> Allow network access + --allow-read=<allow-read> Allow file system read access + --allow-run Allow running subprocesses + --allow-write=<allow-write> Allow file system write access + -c, --config <FILE> Load compiler configuration file + --current-thread Use tokio::runtime::current_thread + -h, --help Prints help information + --importmap <FILE> Load import map file + -L, --log-level <log-level> Set log level [possible values: debug, info] + --no-fetch Do not download remote modules + -r, --reload=<CACHE_BLACKLIST> Reload source code cache (recompile TypeScript) + --seed <NUMBER> Seed Math.random() + --v8-flags=<v8-flags> Set V8 command line options + --v8-options Print V8 command line options + -v, --version Print the version + +SUBCOMMANDS: + [SCRIPT] Script to run + bundle Bundle module and dependencies into single file + completions Generate shell completions + eval Eval script + fetch Fetch the dependencies + fmt Format files + help Prints this message or the help of the given subcommand(s) + info Show info about cache or info related to source file + install Install script as executable + run Run a program given a filename or url to the source code + test Run tests + types Print runtime TypeScript declarations + version Print the version + xeval Eval a script on text segments from stdin + +ENVIRONMENT VARIABLES: + DENO_DIR Set deno's base directory + NO_COLOR Set to disable color + HTTP_PROXY Set proxy address for HTTP requests (module downloads, fetch) + HTTPS_PROXY Set proxy address for HTTPS requests (module downloads, fetch) +``` + +### Environmental variables + +There are several env vars that control how Deno behaves: + +`DENO_DIR` defaults to `$HOME/.deno` but can be set to any path to control where +generated and cached source code is written and read to. + +`NO_COLOR` will turn off color output if set. See https://no-color.org/. User +code can test if `NO_COLOR` was set without having `--allow-env` by using the +boolean constant `Deno.noColor`. + +### Shell completion + +You can generate completion script for your shell using the +`deno completions <shell>` command. The command outputs to stdout so you should +redirect it to an appropriate file. + +The supported shells are: + +- zsh +- bash +- fish +- powershell +- elvish + +Example: + +```shell +deno completions bash > /usr/local/etc/bash_completion.d/deno.bash +source /usr/local/etc/bash_completion.d/deno.bash +``` + +### V8 flags + +V8 has many many internal command-line flags, that you can see with +`--v8-options`. +[It looks like this.](https://gist.github.com/ry/1c5b080dcbdc6367e5612392049c9ee7) + +Particularly useful ones: + +``` +--async-stack-trace +``` + +### Bundling + +`deno bundle [URL]` will output a single JavaScript file, using +[AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition), which +includes all dependencies of the specified input. + +``` +> deno bundle https://deno.land/std/examples/colors.ts +Bundling "colors.bundle.js" +Emitting bundle to "colors.bundle.js" +9.2 kB emitted. +``` + +To run then bundle in Deno use + +``` +deno https://deno.land/std/bundle/run.ts colors.bundle.js +``` + +Bundles can also be loaded in the web browser with the assistance of +[RequireJS](https://requirejs.org/). Suppose we have a bundle called +`website.bundle.js`, then the following HTML should be able to load it: + +```html +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script> +<script src="website.bundle.js"></script> +<script> + requirejs(["website"], website => website.main()); +</script> +``` + +Here we assume there's an exported function `main()` from `website.ts`. + +```js +// website.ts +export main() { + console.log("hello from the web browser"); +} +``` + +### Installing executable scripts + +Deno provides ability to easily install and distribute executable code via +`deno install` command. + +`deno install [EXE_NAME] [URL] [FLAGS...]` will install script available at +`URL` with name `EXE_NAME`. + +This command is a thin wrapper that creates executable shell scripts which +invoke `deno` with specified permissions and CLI flags. + +Example: + +```shell +$ deno install file_server https://deno.land/std/http/file_server.ts --allow-net --allow-read +[1/1] Compiling https://deno.land/std/http/file_server.ts + +✅ Successfully installed file_server. +/Users/deno/.deno/bin/file_server +``` + +By default scripts are installed at `$HOME/.deno/bin` and that directory must be +added to the path manually. + +```shell +$ echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc +``` + +Installation directory can be changed using `-d/--dir` flag: + +```shell +$ deno install --dir /usr/local/bin prettier https://deno.land/std/prettier/main.ts --allow-write --allow-read +``` + +When installing a script you can specify permissions that will be used to run +the script. They are placed after the script URL and can be mixed with any +additional CLI flags you want to pass to the script. + +Example: + +```shell +$ deno install format_check https://deno.land/std/prettier/main.ts --allow-write --allow-read --check --print-width 88 --tab-width 2 +``` + +Above command creates an executable called `format_check` that runs `prettier` +with write and read permissions. When you run `format_check` deno will run +prettier in `check` mode and configured to use `88` column width with `2` column +tabs. + +It is a good practice to use `import.meta.main` idiom for an entry point for +executable file. See +[Testing if current file is the main program](#testingifcurrentfileisthemainprogram) +section. + +Example: + +```ts +// https://example.com/awesome/cli.ts +async function myAwesomeCli(): Promise<void> { + -- snip -- +} + +if (import.meta.main) { + myAwesomeCli(); +} +``` + +When you create executable script make sure to let users know by adding example +installation command to your repository: + +```shell +# Install using deno install + +$ deno install awesome_cli https://example.com/awesome/cli.ts +``` + +## Proxies + +Deno supports proxies for module downloads and `fetch` API. + +Proxy configuration is read from environmental variables: `HTTP_PROXY` and +`HTTPS_PROXY`. + +In case of Windows if environmental variables are not found Deno falls back to +reading proxies from registry. + +## Import maps + +Deno supports [import maps](https://github.com/WICG/import-maps). + +One can use import map with `--importmap=<FILE>` CLI flag. + +Current limitations: + +- single import map +- no fallback URLs +- Deno does not support `std:` namespace +- Does supports only `file:`, `http:` and `https:` schemes + +Example: + +```js +// import_map.json + +{ + "imports": { + "http/": "https://deno.land/std/http/" + } +} +``` + +```ts +// hello_server.ts + +import { serve } from "http/server.ts"; + +window.onload = async function() { + const body = new TextEncoder().encode("Hello World\n"); + for await (const req of serve(":8000")) { + req.respond({ body }); + } +}; +``` + +```shell +$ deno run --importmap=import_map.json hello_server.ts +``` + +## Program lifecycle + +Deno supports browser compatible lifecycle events: `load` and `unload`. You can +use these event to provide setup and cleanup code in your program. + +`load` event listener supports asynchronous functions and will await these +functions. `unload` event listener supports only synchronous code. Both events +are not cancellable. + +Example: + +```typescript +// main.ts +import "./imported.ts"; + +const handler = (e: Event): void => { + console.log(`got ${e.type} event in event handler (main)`); +}; + +window.addEventListener("load", handler); + +window.addEventListener("unload", handler); + +window.onload = (e: Event): void => { + console.log(`got ${e.type} event in onload function (main)`); +}; + +window.onunload = (e: Event): void => { + console.log(`got ${e.type} event in onunload function (main)`); +}; + +// imported.ts +const handler = (e: Event): void => { + console.log(`got ${e.type} event in event handler (imported)`); +}; + +window.addEventListener("load", handler); +window.addEventListener("unload", handler); + +window.onload = (e: Event): void => { + console.log(`got ${e.type} event in onload function (imported)`); +}; + +window.onunload = (e: Event): void => { + console.log(`got ${e.type} event in onunload function (imported)`); +}; + +console.log("log from imported script"); +``` + +Note that you can use both `window.addEventListener` and +`window.onload`/`window.onunload` to define handlers for events. There is a +major difference between them, let's run example: + +```shell +$ deno main.ts +log from imported script +log from main script +got load event in onload function (main) +got load event in event handler (imported) +got load event in event handler (main) +got unload event in onunload function (main) +got unload event in event handler (imported) +got unload event in event handler (main) +``` + +All listeners added using `window.addEventListener` were run, but +`window.onload` and `window.onunload` defined in `main.ts` overridden handlers +defined in `imported.ts`. + +## Internal details + +### Deno and Linux analogy + +| **Linux** | **Deno** | +| ------------------------------: | :------------------------------- | +| Processes | Web Workers | +| Syscalls | Ops | +| File descriptors (fd) | [Resource ids (rid)](#resources) | +| Scheduler | Tokio | +| Userland: libc++ / glib / boost | https://deno.land/std/ | +| /proc/\$\$/stat | [Deno.metrics()](#metrics) | +| man pages | deno types | + +#### Resources + +Resources (AKA `rid`) are Deno's version of file descriptors. They are integer +values used to refer to open files, sockets, and other concepts. For testing it +would be good to be able to query the system for how many open resources there +are. + +```ts +const { resources, close } = Deno; +console.log(resources()); +// output like: { 0: "stdin", 1: "stdout", 2: "stderr", 3: "repl" } + +// close resource by rid +close(3); +``` + +#### Metrics + +Metrics is Deno's internal counters for various statics. + +```shell +> console.table(Deno.metrics()) +┌──────────────────┬────────┐ +│ (index) │ Values │ +├──────────────────┼────────┤ +│ opsDispatched │ 9 │ +│ opsCompleted │ 9 │ +│ bytesSentControl │ 504 │ +│ bytesSentData │ 0 │ +│ bytesReceived │ 856 │ +└──────────────────┴────────┘ +``` + +### Schematic diagram + +<img src="images/schematic_v0.2.png"> + +### Profiling + +To start profiling, + +```sh +# Make sure we're only building release. +# Build deno and V8's d8. +ninja -C target/release d8 + +# Start the program we want to benchmark with --prof +./target/release/deno tests/http_bench.ts --allow-net --v8-flags=--prof & + +# Exercise it. +third_party/wrk/linux/wrk http://localhost:4500/ +kill `pgrep deno` +``` + +V8 will write a file in the current directory that looks like this: +`isolate-0x7fad98242400-v8.log`. To examine this file: + +```sh +D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor +isolate-0x7fad98242400-v8.log > prof.log +# on macOS, use ./third_party/v8/tools/mac-tick-processor instead +``` + +`prof.log` will contain information about tick distribution of different calls. + +To view the log with Web UI, generate JSON file of the log: + +```sh +D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor +isolate-0x7fad98242400-v8.log --preprocess > prof.json +``` + +Open `third_party/v8/tools/profview/index.html` in your browser, and select +`prof.json` to view the distribution graphically. + +Useful V8 flags during profiling: + +- --prof +- --log-internal-timer-events +- --log-timer-events +- --track-gc +- --log-source-code +- --track-gc-object-stats + +Note that you might need to run Deno with `--current-thread` flag to capture +full V8 profiling output. + +To learn more about `d8` and profiling, check out the following links: + +- [https://v8.dev/docs/d8](https://v8.dev/docs/d8) +- [https://v8.dev/docs/profile](https://v8.dev/docs/profile) + +### Debugging with LLDB + +We can use LLDB to debug Deno. + +```shell +$ lldb -- target/debug/deno run tests/worker.js +> run +> bt +> up +> up +> l +``` + +To debug Rust code, we can use `rust-lldb`. It should come with `rustc` and is a +wrapper around LLDB. + +```shell +$ rust-lldb -- ./target/debug/deno run --allow-net tests/http_bench.ts +# On macOS, you might get warnings like +# `ImportError: cannot import name _remove_dead_weakref` +# In that case, use system python by setting PATH, e.g. +# PATH=/System/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH +(lldb) command script import "/Users/kevinqian/.rustup/toolchains/1.36.0-x86_64-apple-darwin/lib/rustlib/etc/lldb_rust_formatters.py" +(lldb) type summary add --no-value --python-function lldb_rust_formatters.print_val -x ".*" --category Rust +(lldb) type category enable Rust +(lldb) target create "../deno/target/debug/deno" +Current executable set to '../deno/target/debug/deno' (x86_64). +(lldb) settings set -- target.run-args "tests/http_bench.ts" "--allow-net" +(lldb) b op_start +(lldb) r +``` + +### Deno Core + +The core binding layer for Deno. It is released as a +[standalone crate](https://crates.io/crates/deno). Inside of core is V8 itself, +with a binding API called "libdeno". See the crate documentation for more +details. + +### Updating prebuilt binaries + +```shell +$ ./third_party/depot_tools/upload_to_google_storage.py -b denoland \ + -e ~/.config/gcloud/legacy_credentials/ry@tinyclouds.org/.boto `which sccache` +$ mv `which sccache`.sha1 prebuilt/linux64/ +$ gsutil acl ch -u AllUsers:R gs://denoland/608be47bf01004aa11d4ed06955414e93934516e +``` + +### Continuous Benchmarks + +See our benchmarks [over here](https://deno.land/benchmarks.html) + +The benchmark chart supposes `//website/data.json` has the type +`BenchmarkData[]` where `BenchmarkData` is defined like the below: + +```ts +interface ExecTimeData { + mean: number; + stddev: number; + user: number; + system: number; + min: number; + max: number; +} + +interface BenchmarkData { + created_at: string; + sha1: string; + benchmark: { + [key: string]: ExecTimeData; + }; + binarySizeData: { + [key: string]: number; + }; + threadCountData: { + [key: string]: number; + }; + syscallCountData: { + [key: string]: number; + }; +} +``` + +### Logos + +These Deno logos, like the Deno software, are distributed under the MIT license +(public domain and free for use) + +- [A hand drawn one by @ry](https://github.com/denoland/deno/blob/master/website/images/deno_logo.png) + +- [An animated one by @hashrock](https://github.com/denolib/animated-deno-logo/) + +- [A high resolution SVG one by @kevinkassimo](https://github.com/denolib/high-res-deno-logo) + +- [A pixelated animation one by @tanakaworld](https://github.com/denoland/deno/blob/master/website/images/deno_logo_4.gif) + +## Contributing + +[Style Guide](style_guide.html) + +Progress towards future releases is tracked +[here](https://github.com/denoland/deno/milestones). + +Please don't make [the benchmarks](https://deno.land/benchmarks.html) worse. + +Ask for help in the [community chat room](https://gitter.im/denolife/Lobby). + +If you are going to work on an issue, mention so in the issue comments _before_ +you start working on the issue. + +### Submitting a pull request + +Before submitting, please make sure the following is done: + +1. That there is a related issue and it is referenced in the PR text. +2. There are tests that cover the changes. +3. Ensure `cargo test` passes. +4. Format your code with `tools/format.py` +5. Make sure `./tools/lint.py` passes. + +### Changes to `third_party` + +[`deno_third_party`](https://github.com/denoland/deno_third_party) contains most +of the external code that Deno depends on, so that we know exactly what we are +executing at any given time. It is carefully maintained with a mixture of manual +labor and private scripts. It's likely you will need help from @ry or +@piscisaureus to make changes. + +### Adding Ops (aka bindings) + +We are very concerned about making mistakes when adding new APIs. When adding an +Op to Deno, the counterpart interfaces on other platforms should be researched. +Please list how this functionality is done in Go, Node, Rust, and Python. + +As an example, see how `Deno.rename()` was proposed and added in +[PR #671](https://github.com/denoland/deno/pull/671). + +### Documenting APIs + +It is important to document public APIs and we want to do that inline with the +code. This helps ensure that code and documentation are tightly coupled +together. + +#### Utilize JSDoc + +All publicly exposed APIs and types, both via the `deno` module as well as the +global/`window` namespace should have JSDoc documentation. This documentation is +parsed and available to the TypeScript compiler, and therefore easy to provide +further downstream. JSDoc blocks come just prior to the statement they apply to +and are denoted by a leading `/**` before terminating with a `*/`. For example: + +```ts +/** A simple JSDoc comment */ +export const FOO = "foo"; +``` |