1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-21 23:04:45 -05:00

web design (#1728)

This commit is contained in:
Ryan Dahl 2019-02-11 17:41:13 -05:00 committed by GitHub
parent 489c69f8e1
commit a4dec944bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1407 additions and 972 deletions

View file

@ -1,98 +0,0 @@
# Contributing To Deno
Check [the roadmap](https://github.com/denoland/deno/blob/master/Roadmap.md)
before contributing.
Please don't make [the benchmarks](https://denoland.github.io/deno/) worse.
Ask for help in the issues or on the
[chat room](https://gitter.im/denolife/Lobby).
Progress towards future releases is tracked
[here](https://github.com/denoland/deno/milestones).
Docs are [here](https://github.com/denoland/deno/blob/master/Docs.md).
## Submitting a pull request
Before submitting, please make sure the following is done:
1. There are tests that cover the changes.
2. Ensure `./tools/test.py` passes.
3. Format your code with `PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run`.
<!-- TODO: set PYTHONPATH in format.ts when run API has env option -->
4. Make sure `./tools/lint.py` passes.
## Changes to `third_party`
Changes to `third_party` including any changes in the `package.json` will impact
the [denoland/deno_third_party](https://github.com/denoland/deno_third_party)
repository as well.
## 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";
```
### JSDoc style guide
- It is important that documentation is easily human readable, but there is also
a need to provide additional styling information to ensure generated
documentation is more rich text. Therefore JSDoc should generally follow
markdown markup to enrich the text.
- While markdown supports HTML tags, it is forbidden in JSDoc blocks.
- Code string literals should be braced with the back-tick (\`) instead of
quotes. For example:
```ts
/** Import something from the `deno` module. */
```
- Do not document function arguments unless they are non-obvious of their intent
(though if they are non-obvious intent, the API should be considered anyways).
Therefore `@param` should generally not be used.
- Vertical spacing should be minimized whenever possible. Therefore single line
comments should be written as:
```ts
/** This is a good single line JSDoc */
```
And not:
```ts
/**
* This is a bad single line JSDoc
*/
```
- Code examples should not utilise the triple-back tick (\`\`\`) notation or
tags. They should just be marked by indentation, which requires a break before
the block and 6 additional spaces for each line of the example. This is 4 more
than the first column of the comment. For example:
```ts
/** A straight forward comment and an example:
*
* import { foo } from "deno";
* foo("bar");
*/
```
- Code examples should not contain additional comments. It is already inside a
comment. If it needs further comments is not a good example.

View file

@ -1,3 +1,3 @@
<!--
https://github.com/denoland/deno/blob/master/.github/CONTRIBUTING.md
Before submitting a PR read https://deno.land/manual.html#contributing
-->

440
Docs.md
View file

@ -1,439 +1 @@
# Deno Documentation
## 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!
## 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:
```
curl -fL https://deno.land/x/install/install.sh | sh
```
Or using PowerShell:
```powershell
iex (iwr https://deno.land/x/install/install.ps1)
```
_Note: Depending on your security settings, you may have to run
`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded
scripts to be executed._
With [Scoop](https://scoop.sh/):
```
scoop install deno
```
Deno 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.
Try it:
```
> deno https://deno.land/thumb.ts
```
## API Reference
To get an exact reference of deno's runtime API, run the following in the
command line:
```
> deno --types
```
Or see the [doc website](https://deno.land/typedoc/index.html).
If you are embedding deno in a Rust program, see
[the rust docs](https://deno.land/rustdoc/deno/index.html).
## Build Instructions
### 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.31.1
2. [Node](https://nodejs.org/)
3. Python 2.
[Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578).
Extra steps for Mac users:
1. [XCode](https://developer.apple.com/xcode/)
2. Openssl 1.1: `brew install openssl@1.1` (TODO: shouldn't be necessary)
Extra steps for Windows users:
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`.
### Build:
# Fetch deps.
git clone --recurse-submodules https://github.com/denoland/deno.git
cd deno
./tools/setup.py
# You may need to ensure that sccache is running.
# (TODO it's unclear if this is necessary or not.)
# prebuilt/mac/sccache --start-server
# Build.
./tools/build.py
# Run.
./target/debug/deno tests/002_hello.ts
# Test.
./tools/test.py
# Format code.
PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run
<!-- TODO: set PYTHONPATH in format.ts when run API has env option -->
Other useful commands:
# Call ninja manually.
./third_party/depot_tools/ninja -C target/debug
# Build a release binary.
DENO_BUILD_MODE=release ./tools/build.py :deno
# List executable targets.
./third_party/depot_tools/gn ls target/debug //:* --as=output --type=executable
# List build configuration.
./third_party/depot_tools/gn args target/debug/ --list
# Edit build configuration.
./third_party/depot_tools/gn args target/debug/
# Describe a target.
./third_party/depot_tools/gn desc target/debug/ :deno
./third_party/depot_tools/gn help
# Update third_party modules
git submodule update
Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`,
`DENO_DIR`.
## Tutorial
### 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
import * as deno from "deno";
(async () => {
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:
```
> deno https://deno.land/x/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
import { listen, copy } from "deno";
(async () => {
const addr = "0.0.0.0:8080";
const listener = listen("tcp", addr);
console.log("listening on", addr);
while (true) {
const conn = await listener.accept();
copy(conn, conn);
}
})();
```
When this program is started, the user is prompted for permission to listen on
the network:
```
> deno https://deno.land/x/examples/echo_server.ts
⚠️ Deno requests network access to "listen". Grant? [yN] y
listening on 0.0.0.0:8080
```
For security reasons, deno does not allow programs to access the network without
explicit permission. To avoid the console prompt, use a command-line flag:
```
> deno https://deno.land/x/examples/echo_server.ts --allow-net
```
To test it, try sending a HTTP request to it by using curl. The request gets
written directly back to the client.
```
> curl http://localhost:8080/
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*
```
It's worth noting that 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.
### 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, assertEqual } from "https://deno.land/x/testing/mod.ts";
test(function t1() {
assertEqual("hello", "hello");
});
test(function t2() {
assertEqual("world", "world");
});
```
Try running this:
```
> deno https://deno.land/x/examples/example_test.ts
Compiling /Users/rld/src/deno_examples/example_test.ts
Downloading https://deno.land/x/testing/mod.ts
Compiling https://deno.land/x/testing/mod.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 default to `$HOME/.deno` 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.
**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 `package.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/x/testing/mod.ts"` everywhere, you could create a
`package.ts` file the exports the third-party code:
```ts
export { test, assertEqual } from "https://deno.land/x/testing/mod.ts";
```
And throughout project one can import from the `package.ts` and avoid having
many references to the same URL:
```ts
import { test, assertEqual } from "./package.ts";
```
This design circumvents a plethora of complexity spawned by package management
software, centralized code repositories, and superfluous file formats.
## 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`.
## Browser compatibility
The subset of Deno programs which are written completely in JavaScript and do
not import the special `"deno"` module, ought to also be able to be run in a
modern web browser without change.
## Useful command line flags
V8 has many many command-line flags, that you can see with `--v8-options`. Here
are a few particularly useful ones:
```
--async-stack-traces
```
## How to Profile deno
To start profiling,
```sh
# Make sure we're only building release.
export DENO_BUILD_MODE=release
# Build deno and V8's d8.
./tools/build.py d8 deno
# Start the program we want to benchmark with --prof
./target/release/deno tests/http_bench.ts --allow-net --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 brower, and select
`prof.json` to view the distribution graphically.
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)
## How to Debug deno
We can use LLDB to debug deno.
```sh
lldb -- target/debug/deno 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.
```sh
rust-lldb -- ./target/debug/deno tests/http_bench.ts --allow-net
# 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.30.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
```
## Internals
### Internal: libdeno API.
deno's privileged side will primarily be programmed in Rust. However there will
be a small C API that wraps V8 to 1) define the low-level message passing
semantics, 2) provide a low-level test target, 3) provide an ANSI C API binding
interface for Rust. V8 plus this C API is called "libdeno" and the important
bits of the API is specified here:
https://github.com/denoland/deno/blob/master/libdeno/deno.h
https://github.com/denoland/deno/blob/master/js/libdeno.ts
### Internal: Flatbuffers provide shared data between Rust and V8
We use Flatbuffers to define common structs and enums between TypeScript and
Rust. These common data structures are defined in
https://github.com/denoland/deno/blob/master/src/msg.fbs
### Internal: Updating prebuilt binaries
```
./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
```
## Contributing
See
[CONTRIBUTING.md](https://github.com/denoland/deno/blob/master/.github/CONTRIBUTING.md).
Moved to https://deno.land/manual.html

View file

@ -4,91 +4,7 @@
| :------------------------: | :------------------------: |
| [![][tci badge]][tci link] | [![][avy badge]][avy link] |
## A new way to JavaScript.
- Supports TypeScript out of the box. Uses a recent version of V8. That is, it's
very modern JavaScript.
- No `package.json`. No npm. Not explicitly compatible with Node.
- Imports reference source code URLs only.
```typescript
import { test } from "https://unpkg.com/deno_testing@0.0.5/testing.ts";
import { log } from "./util.ts";
```
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. See `~/.deno/src` for details on the cache.)
- File system and network access can be controlled in order to run sandboxed
code. Defaults to read-only file system access and no network access. Access
between V8 (unprivileged) and Rust (privileged) is only done via serialized
messages defined in this
[flatbuffer](https://github.com/denoland/deno/blob/master/src/msg.fbs). This
makes it easy to audit. To enable write access explicitly use `--allow-write`
and `--allow-net` for network access.
- Single executable:
```
> ls -lh target/release/deno
-rwxr-xr-x 1 rld staff 48M Aug 2 13:24 target/release/deno
> otool -L target/release/deno
target/release/deno:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.50.4)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 58286.51.6)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.0)
>
```
- Always dies on uncaught errors.
- [Aims to support top-level `await`.](https://github.com/denoland/deno/issues/471)
- Aims to be browser compatible.
See the website for more info [deno.land](https://deno.land).
## Install
With Shell:
```
curl -L https://deno.land/x/install/install.sh | bash
```
With PowerShell:
```powershell
iex (iwr https://deno.land/x/install/install.ps1)
```
_Note: Depending on your security settings, you may have to run
`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded
scripts to be executed._
With [Scoop](https://scoop.sh/):
```
scoop install deno
```
Try it:
```
> deno https://deno.land/thumb.ts
```
See [deno_install](https://github.com/denoland/deno_install) for more
installation methods..
## Build locally (advanced users only)
For instructions to build this project locally, please see
[the docs](https://github.com/denoland/deno/blob/master/Docs.md#build-instructions-for-advanced-users-only).
See documentation at https://deno.land/
<!-- prettier-ignore -->
[avy badge]: https://ci.appveyor.com/api/projects/status/yel7wtcqwoy0to8x?branch=master&svg=true

View file

@ -1,61 +0,0 @@
# Deno Roadmap
API and Feature requests should be submitted as PRs to this document.
## Security Model (partially implemented)
- We want to be secure by default; user should be able to run untrusted code,
like the web.
- Threat model:
- Modifiying/deleting local files
- Leaking private information
- Disallowed default:
- Network access
- Local write access
- Non-JS extensions
- Subprocesses
- Env access
- Allowed default:
- Local read access.
- argv, stdout, stderr, stdin access always allowed.
- Maybe: temp dir write access. (But what if they create symlinks there?)
- The user gets prompted when the software tries to do something it doesn't have
the privilege for.
- Have an option to get a stack trace when access is requested.
- Worried that granting access per file will give a false sense of security due
to monkey patching techniques. Access should be granted per program (js
context).
Example security prompts. Options are: YES, NO, PRINT STACK
```
Program requests write access to "~/.ssh/id_rsa". Grant? [yNs]
http://gist.github.com/asdfasd.js requests network access to "www.facebook.com". Grant? [yNs]
Program requests access to environment variables. Grant? [yNs]
Program requests to spawn `rm -rf /`. Grant? [yNs]
```
- cli flags to grant access ahead of time --allow-all --allow-write --allow-net
--allow-env --allow-exec
- in version two we will add ability to give finer grain access
--allow-net=facebook.com
## Top-level Await (Not Implemented)
[#471](https://github.com/denoland/deno/issues/471)
This will be put off until at least deno2 Milestone1 is complete. One of the
major problems is that top-level await calls are not syntactically valid
TypeScript.
### [Broken] List dependencies of a program.
Currently broken: https://github.com/denoland/deno/issues/1011
```
% deno --deps http://gist.com/blah.js
http://gist.com/blah.js
http://gist.com/dep.js
https://github.com/denoland/deno/master/testing.js
%
```

View file

@ -61,7 +61,7 @@ async function run(...args: string[]): Promise<void> {
"--allow-write",
"js/deps/https/deno.land/x/std/prettier/main.ts",
"rollup.config.js",
...findFiles(["."], [".json", ".md"], { depth: 1 }),
...findFiles([".", "website"], [".json", ".md"], { depth: 1 }),
...findFiles(
[".github", "js", "tests", "tools", "website"],
[".js", ".json", ".ts", ".md"],

View file

@ -1,32 +0,0 @@
## About benchmark data
The benchmark chart supposes `//website/data.json` has the type
`BenchmarkData[]` where `BenchmarkData` is defined like the below:
```typescript
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;
};
}
```

View file

@ -1,44 +0,0 @@
<!-- Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -->
<!DOCTYPE html>
<html>
<head>
<title>all benchmark data | deno</title>
<link rel="stylesheet" href="https://unpkg.com/c3@0.6.7/c3.min.css">
<link rel="stylesheet" href="style.css">
<meta content='width=device-width, initial-scale=1.0' name='viewport' />
</head>
<body>
<main>
<h1>all benchmark data</h1>
<p><a href="./">back</a>
<h2>Execution time</h2>
<div id="exec-time-chart"></div>
<h2>Throughput</h2>
<div id="throughput-chart"></div>
<h2>Req/Sec</h2>
<div id="req-per-sec-chart"></div>
<h2>Executable size</h2>
<div id="binary-size-chart"></div>
<h2>Thread count</h2>
<div id="thread-count-chart"></div>
<h2>Syscall count</h2>
<div id="syscall-count-chart"></div>
</main>
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<script src="https://unpkg.com/c3@0.6.7/c3.min.js"></script>
<script type="module">
import { drawCharts } from "./app.js";
window.chartWidth = 800
drawCharts("./data.json");
</script>
</body>
</html>

View file

@ -126,6 +126,7 @@ function generate(
) {
const yAxis = {
padding: { bottom: 0 },
min: 0,
label: yLabel
};
if (yTickFormat) {
@ -133,6 +134,7 @@ function generate(
format: yTickFormat
};
if (yTickFormat == logScale) {
delete yAxis.min;
for (let col of columns) {
for (let i = 1; i < col.length; i++) {
if (col[i] == null) {
@ -221,7 +223,7 @@ export async function drawChartsFromBenchmarkData(dataUrl) {
}
gen("#exec-time-chart", execTimeColumns, "seconds", logScale);
gen("#throughput-chart", throughputColumns, "seconds");
gen("#throughput-chart", throughputColumns, "seconds", logScale);
gen("#req-per-sec-chart", reqPerSecColumns, "1000 req/sec", formatReqSec);
gen("#binary-size-chart", binarySizeColumns, "megabytes", formatMB);
gen("#thread-count-chart", threadCountColumns, "threads");

137
website/benchmarks.html Normal file
View file

@ -0,0 +1,137 @@
<!-- Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -->
<!DOCTYPE html>
<html>
<head>
<title>Deno Benchmarks</title>
<link rel="stylesheet" href="https://unpkg.com/c3@0.6.7/c3.min.css" />
<link rel="stylesheet" href="style.css" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
</head>
<body>
<main>
<h1>Deno Continuous Benchmarks</h1>
<p>
These plots are updated on every commit to
<a href="https://github.com/denoland/deno">master branch</a>.
</p>
<p><a href="#recent">recent data</a></p>
<p><a href="#all">all data</a> (takes a moment to load)</p>
<h3 id="exec-time">Execution time <a href="#exec-time">#</a></h3>
<p>
This shows how much time total it takes to run a few simple deno
programs:
<a
href="https://github.com/denoland/deno/blob/master/tests/002_hello.ts"
>
tests/002_hello.ts
</a>
and
<a
href="https://github.com/denoland/deno/blob/master/tests/003_relative_import.ts"
>tests/003_relative_import.ts</a
>. For deno to execute typescript, it must first compile it to JS. A
warm startup is when deno has a cached JS output already, so it should
be fast because it bypasses the TS compiler. A cold startup is when deno
must compile from scratch.
</p>
<div id="exec-time-chart"></div>
<h3 id="throughput">Throughput <a href="#throughput">#</a></h3>
<p>
Time it takes to pipe a certain amount of data through Deno.
<a
href="https://github.com/denoland/deno/blob/master/tests/echo_server.ts"
>
echo_server.ts
</a>
and
<a href="https://github.com/denoland/deno/blob/master/tests/cat.ts">
cat.ts </a
>. Smaller is better.
</p>
<div id="throughput-chart"></div>
<h3 id="req-per-sec">Req/Sec <a href="#req-per-sec">#</a></h3>
<p>
Tests HTTP server performance. 10 keep-alive connections do as many
hello-world requests as possible. Bigger is better.
</p>
<ul>
<!-- TODO rename "deno" to "deno_tcp". -->
<li>
<a
href="https://github.com/denoland/deno/blob/master/tests/http_bench.ts"
>
deno
</a>
is a fake http server that doesn't parse HTTP. It is comparable to
<a
href="https://github.com/denoland/deno/blob/master/tools/node_tcp.js"
>
node_tcp
</a>
.
</li>
<li>
<a
href="https://github.com/denoland/deno_std/blob/master/http/http_bench.ts"
>
deno_net_http
</a>
is a web server written in TypeScript. It is comparable to
<a
href="https://github.com/denoland/deno/blob/master/tools/node_http.js"
>
node_http
</a>
.
</li>
<li>
<a
href="https://github.com/denoland/deno/blob/master/tools/hyper_hello.rs"
>
hyper
</a>
is a Rust HTTP server and represents an upper bound.
</li>
</ul>
<div id="req-per-sec-chart"></div>
<h3 id="size">Executable size <a href="#size">#</a></h3>
<p>deno ships only a single binary. We track its size here.</p>
<div id="binary-size-chart"></div>
<h3 id="threads">Thread count <a href="#threads">#</a></h3>
<p>How many threads various programs use.</p>
<div id="thread-count-chart"></div>
<h3 id="syscalls">Syscall count <a href="#syscalls">#</a></h3>
<p>
How many total syscalls are performed when executing a given script.
</p>
<div id="syscall-count-chart"></div>
</main>
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<script src="https://unpkg.com/c3@0.6.7/c3.min.js"></script>
<script type="module">
import { drawCharts } from "./app.js";
window.chartWidth = 800;
let u = window.location.hash.match("all") ? "./data.json" : "recent.json";
drawCharts(u);
</script>
</body>
</html>

View file

@ -3,26 +3,21 @@
<html>
<head>
<title>Deno</title>
<link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="https://unpkg.com/c3@0.6.7/c3.min.css" />
<link rel="stylesheet" href="style.css" />
<meta
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
name="viewport"
/>
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
</head>
<body>
<main>
<img id="logo" src="deno_logo_2.gif" width="150" />
<!-- Logo by hashrock https://denolib.github.io/animated-deno-logo/ -->
<header>
<a href="https://github.com/denolib/animated-deno-logo/"
><img id="logo" src="deno_logo_2.gif" width="150"
/></a>
<!-- Logo by hashrock -->
<div>
<h1>Deno</h1>
<p>
A new way to JavaScript
<!-- TODO(ry) add the registry badges. -->
</p>
</div>
</header>
<table>
<tr>
@ -31,30 +26,32 @@
<th>Windows</th>
</tr>
<tr>
<th>
<a href="https://github.com/denoland/deno">deno</a>
</th>
<th><a href="https://github.com/denoland/deno">deno</a></th>
<td>
<a class="badge" href="https://travis-ci.com/denoland/deno">
<img src="https://travis-ci.com/denoland/deno.svg?branch=master"/>
<img
src="https://travis-ci.com/denoland/deno.svg?branch=master"
/>
</a>
</td>
<td>
<a class="badge" href="https://ci.appveyor.com/project/deno/deno">
<img src="https://ci.appveyor.com/api/projects/status/yel7wtcqwoy0to8x/branch/master?svg=true"/>
<img
src="https://ci.appveyor.com/api/projects/status/yel7wtcqwoy0to8x/branch/master?svg=true"
/>
</a>
</td>
</tr>
<tr>
<th>
<a href="https://github.com/denoland/deno_std">deno_std</a>
</th>
<th><a href="https://github.com/denoland/deno_std">deno_std</a></th>
<td colspan="2">
<a
class="badge"
href="https://dev.azure.com/denoland/deno_std/_build?definitionId=2"
>
<img src="https://dev.azure.com/denoland/deno_std/_apis/build/status/denoland.deno_std?branchName=master"/>
<img
src="https://dev.azure.com/denoland/deno_std/_apis/build/status/denoland.deno_std?branchName=master"
/>
</a>
</td>
</tr>
@ -64,7 +61,9 @@
</th>
<td>
<a class="badge" href="https://travis-ci.com/denoland/deno_install">
<img src="https://travis-ci.com/denoland/deno_install.svg?branch=master"/>
<img
src="https://travis-ci.com/denoland/deno_install.svg?branch=master"
/>
</a>
</td>
<td>
@ -72,166 +71,73 @@
class="badge"
href="https://ci.appveyor.com/project/deno/deno-install"
>
<img src="https://ci.appveyor.com/api/projects/status/gtekeaf7r60xa896?branch=master&svg=true"/>
<img
src="https://ci.appveyor.com/api/projects/status/gtekeaf7r60xa896?branch=master&svg=true"
/>
</a>
</td>
</tr>
<tr>
<th>
<a href="https://github.com/denoland/registry">registry</a>
</th>
<th><a href="https://github.com/denoland/registry">registry</a></th>
</tr>
</table>
<h2 id="install"><a href="#install">#</a>Install</h2>
<h2 id="install">Install <a href="#install">#</a></h2>
<p>With Shell</p>
<pre>curl -fL https://deno.land/x/install/install.sh | sh</pre>
<p>With PowerShell</p>
<pre>iex (iwr https://deno.land/x/install/install.ps1)</pre>
<p>Mac or Linux</p>
<pre>curl -fL <a
href="https://github.com/denoland/deno_install/blob/master/install.sh">https://deno.land/x/install/install.sh</a> | sh</pre>
<p>Windows (PowerShell)</p>
<pre>iex (iwr <a
href="https://github.com/denoland/deno_install/blob/master/install.ps1">https://deno.land/x/install/install.ps1</a>)</pre>
<h2 id="mini-tutorial"><a href="#mini-tutorial">#</a>Mini-tutorial</h2>
<h2 id="example">Example <a href="#example">#</a></h2>
<p>Try running a simple program:</p>
<pre>deno https://deno.land/welcome.js</pre>
<p>Or a more complex one:</p>
<p>Try a Deno program. This one serves a local directory in HTTP.</p>
<pre>
alias file_server="deno \
https://deno.land/x/http/file_server.ts --allow-net"
</pre>
import { serve } from "<a
href="https://github.com/denoland/deno_std/blob/master/http/server.ts">https://deno.land/x/http/server.ts</a>";
const s = serve("0.0.0.0:8000");
<p>Run it:</p>
<pre>
% file_server .
Downloading https://deno.land/x/http/file_server.ts...
[...]
HTTP server listening on http://0.0.0.0:4500/
</pre>
<p>And if you ever want to upgrade to the latest published version:</p>
<pre>file_server --reload</pre>
async function main() {
for await (const req of s) {
req.respond({ body: new TextEncoder().encode("Hello World\n") });
}
}
<h2 id="dig-in"><a href="#dig-in">#</a>Dig in...</h2>
main(); </pre>
<a href="https://github.com/denoland/deno/blob/master/Docs.md">
Documentation
</a>
<h2 id="dig-in">Dig in... <a href="#dig-in">#</a></h2>
<p>
<a href="typedoc/index.html">API Reference</a>
<b><a href="manual.html">Manual</a></b>
</p>
<p>
<a href="https://github.com/denolib/awesome-deno">
Links to other Deno resources.
</a>
</p>
<p><a href="https://deno.land/typedoc">API Reference</a></p>
<h2 id="benchmarks"><a href="#benchmarks">#</a>Continuous Benchmarks</h2>
<p><a href="style_guide.html">Style Guide</a></p>
<p>These plots are updated on every commit to</p>
<p>
<a href="https://github.com/denoland/deno">master branch</a>
</p>
<p><a href="https://deno.land/x/">Module repository</a></p>
<h3 id="exec-time"><a href="#exec-time">#</a>Execution time</h3>
<p>This shows how much time total it takes to run a few simple deno programs:</p>
<a href="https://github.com/denoland/deno/blob/master/tests/002_hello.ts">
tests/002_hello.ts
</a>
<p>and</p>
<p>
<a
href="https://github.com/denoland/deno/blob/master/tests/003_relative_import.ts"
<a href="https://github.com/denoland/deno/blob/master/Releases.md"
>Release notes</a
>
tests/003_relative_import.ts
</a>
</p>
<p>
For deno to execute typescript, it must first compile it to JS. A warm
startup is when deno has a cached JS output already, so it should be fast
because it bypasses the TS compiler. A cold startup is when deno must
compile from scratch.
</p>
<div id="exec-time-chart"></div>
<h3 id="throughput"><a href="#throughput">#</a>Throughput</h3>
<p>Time it takes to pipe a certain amount of data through Deno.</p>
<a href="https://github.com/denoland/deno/blob/master/tests/echo_server.ts">
echo_server.ts
</a>
<p>and</p>
<a href="https://github.com/denoland/deno/blob/master/tests/cat.ts">
cat.ts
</a>
<p>Smaller is better.</p>
<div id="throughput-chart"></div>
<h3 id="req-per-sec"><a href="#req-per-sec">#</a>Req/Sec</h3>
<p>
Tests HTTP server performance. 10 keep-alive connections do as many
hello-world requests as possible. Bigger is better.
</p>
<ul>
<!-- TODO rename "deno" to "deno_tcp". -->
<li>
<a href="https://github.com/denoland/deno/blob/master/tests/http_bench.ts">
deno
</a>
is a fake http server that doesn't parse HTTP. It is comparable to
<a href="https://github.com/denoland/deno/blob/master/tools/node_tcp.js">
node_tcp
</a>
.
</li>
<p><a href="https://gitter.im/denolife/Lobby">Community chat room</a></p>
<li>
<a href="https://github.com/denoland/deno_std/blob/master/http/http_bench.ts">
deno_net_http
</a>
is a web server written in TypeScript. It is comparable to
<a href="https://github.com/denoland/deno/blob/master/tools/node_http.js">
node_http
</a>
.
</li>
<li>
<a href="https://github.com/denoland/deno/blob/master/tools/hyper_hello.rs">
hyper
</a>
is a Rust HTTP server and represents an upper bound.
</li>
</ul>
<div id="req-per-sec-chart"></div>
<h3 id="size"><a href="#size">#</a>Executable size</h3>
<p>deno ships only a single binary. We track its size here.</p>
<div id="binary-size-chart"></div>
<h3 id="threads"><a href="#threads">#</a>Thread count</h3>
<p>How many threads various programs use.</p>
<div id="thread-count-chart"></div>
<h3 id="syscalls"><a href="#syscalls">#</a>Syscall count</h3>
<p>How many total syscalls are performed when executing a given script.</p>
<div id="syscall-count-chart"></div>
<p><a href="benchmarks.html">Benchmarks</a></p>
<p>
<a href="./all_benchmark.html">Historical benchmark data</a>
<a href="https://github.com/denolib/awesome-deno"
>A curated list of awesome Deno things</a
>
</p>
</main>
<script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
<script src="https://unpkg.com/c3@0.6.7/c3.min.js"></script>
<script type="module">
import { drawCharts } from "./app.js";
drawCharts("recent.json");
</script>
</body>
</html>

View file

@ -1,13 +0,0 @@
{
"dir": "ltr",
"lang": "en",
"name": "Deno",
"scope": "/",
"display": "browser",
"start_url": "/",
"short_name": "Deno",
"theme_color": "#F0F0F0",
"description": "A new way to JavaScript",
"orientation": "any",
"background_color": "#F0F0F0"
}

40
website/manual.html Normal file
View file

@ -0,0 +1,40 @@
<!-- Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -->
<!DOCTYPE html>
<html>
<head>
<title>Deno Manual</title>
<link rel="stylesheet" href="style.css" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
</head>
<body>
<main>
<div id="manual"></div>
<script src="https://unpkg.com/showdown@1.9.0/dist/showdown.js"></script>
<script src="showdown_toc.js"></script>
<script>
const url = "manual.md";
async function main() {
const response = await fetch(url);
const content = await response.text();
let converter = new showdown.Converter({ extensions: ["toc"] });
let html = converter.makeHtml(content);
const manual = document.getElementById("manual");
manual.innerHTML = html;
// To make anchor links work properly, we have to manually scroll
// since the markdown is rendered dynamically.
if (window.location.hash) {
let el = document.getElementById(window.location.hash.slice(1));
window.scrollTo({ top: el.offsetTop });
}
}
main();
</script>
</main>
</body>
</html>

656
website/manual.md Normal file
View file

@ -0,0 +1,656 @@
# Deno Manual
[toc]
## 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!
## Introduction
### Philosophy
Deno aims to be a useful multitool tool for the modern programmer.
It will always be distributed as a single executable - and that executable will
be sufficient software to run any deno program. Given a URL to a deno program,
you should be able to execute it with nothing more than <a
href="https://deno.land/benchmarks.html#size">the 50M deno executable</a>.
Deno explicitly takes on the role of both runtime and package manager. It uses a
standard browser-compatible protocol for loading modules: URLs.
Deno provides security guarantees about how programs can access your system with
the default being the most restrictive secure sandbox.
Deno provides <a href="https://github.com/denoland/deno_std">a set of reviewed
(audited) standard modules</a> that are guaranteed to work with Deno.
Deno is opinionated and defines <a
href="https://github.com/denoland/deno_std#style-guide">style guides</a> and has
<a href="https://github.com/denoland/deno_std/tree/master/prettier">automated
formatters</a>.
### Design goals
- Support TypeScript out of the box.
- No `package.json`. No npm. Not explicitly compatible with Node.
- Like the browser, allows imports from URLs:
```typescript
import * as log from "https://deno.land/x/std/log/mod.ts";
```
- 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. See `~/.deno/src` for details on the cache.)
- Uses "ES Modules" and does not support `require()`.
- File system and network access can be controlled in order to run sandboxed
code. Access between V8 (unprivileged) and Rust (privileged) is only done via
serialized messages defined in this
[flatbuffer](https://github.com/denoland/deno/blob/master/src/msg.fbs). This
makes it easy to audit. For example, to enable write access use the flag
`--allow-write` or for network access `--allow-net`.
- Only ship a single executable.
- Always dies on uncaught errors.
- [Aims to support top-level `await`.](https://github.com/denoland/deno/issues/471)
### Browser compatibility
The subset of Deno programs which are written completely in JavaScript and do
not import the special `"deno"` module, ought to also be able to be run in a
modern web browser without change.
## 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:
```
curl -fL https://deno.land/x/install/install.sh | sh
```
Or using PowerShell:
```powershell
iex (iwr https://deno.land/x/install/install.ps1)
```
_Note: Depending on your security settings, you may have to run
`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded
scripts to be executed._
With [Scoop](https://scoop.sh/):
```
scoop install deno
```
Deno 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:
```
deno https://deno.land/welcome.js
```
### Build from source
```
# Fetch deps.
git clone --recurse-submodules https://github.com/denoland/deno.git
cd deno
./tools/setup.py
# You may need to ensure that sccache is running.
# (TODO it's unclear if this is necessary or not.)
# prebuilt/mac/sccache --start-server
# Build.
./tools/build.py
# Run.
./target/debug/deno tests/002_hello.ts
# Test.
./tools/test.py
# Format code.
# TODO: set PYTHONPATH in format.ts when run API has env option.
PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run
```
#### 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.31.1
2. [Node](https://nodejs.org/)
3. Python 2.
[Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578).
Extra steps for Mac users:
1. [XCode](https://developer.apple.com/xcode/)
2. Openssl 1.1: `brew install openssl@1.1` (TODO: shouldn't be necessary)
Extra steps for Windows users:
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`.
#### Other useful commands
```
# Call ninja manually.
./third_party/depot_tools/ninja -C target/debug
# Build a release binary.
DENO_BUILD_MODE=release ./tools/build.py :deno
# List executable targets.
./third_party/depot_tools/gn ls target/debug //:* --as=output --type=executable
# List build configuration.
./third_party/depot_tools/gn args target/debug/ --list
# Edit build configuration.
./third_party/depot_tools/gn args target/debug/
# Describe a target.
./third_party/depot_tools/gn desc target/debug/ :deno
./third_party/depot_tools/gn help
# Update third_party modules
git submodule update
```
Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`,
`DENO_DIR`.
## API reference
### deno --types
To get an exact reference of deno's runtime API, run the following in the
command line:
```
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://deno.land/rustdoc/deno/index.html).
## 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
import * as deno from "deno";
(async () => {
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:
```
> deno https://deno.land/x/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
import { listen, copy } from "deno";
(async () => {
const addr = "0.0.0.0:8080";
const listener = listen("tcp", addr);
console.log("listening on", addr);
while (true) {
const conn = await listener.accept();
copy(conn, conn);
}
})();
```
When this program is started, the user is prompted for permission to listen on
the network:
```
> deno https://deno.land/x/examples/echo_server.ts
⚠️ Deno requests network access to "listen". Grant? [yN] y
listening on 0.0.0.0:8080
```
For security reasons, deno does not allow programs to access the network without
explicit permission. To avoid the console prompt, use a command-line flag:
```
> deno https://deno.land/x/examples/echo_server.ts --allow-net
```
To test it, try sending a HTTP request to it by using curl. The request gets
written directly back to the client.
```
> curl http://localhost:8080/
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*
```
It's worth noting that 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.
### File server
This one serves a local directory in HTTP.
```
alias file_server="deno --allow-net --allow-read \
https://deno.land/x/http/file_server.ts"
```
Run it:
```
% file_server .
Downloading https://deno.land/x/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:
```
file_server --reload
```
### 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, assertEqual } from "https://deno.land/x/testing/mod.ts";
test(function t1() {
assertEqual("hello", "hello");
});
test(function t2() {
assertEqual("world", "world");
});
```
Try running this:
```
> deno https://deno.land/x/examples/example_test.ts
Compiling /Users/rld/src/deno_examples/example_test.ts
Downloading https://deno.land/x/testing/mod.ts
Compiling https://deno.land/x/testing/mod.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 default to `$HOME/.deno` 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.
**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 `package.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/x/testing/mod.ts"` everywhere, you could create a
`package.ts` file the exports the third-party code:
```ts
export { test, assertEqual } from "https://deno.land/x/testing/mod.ts";
```
And throughout project one can import from the `package.ts` and avoid having
many references to the same URL:
```ts
import { test, assertEqual } from "./package.ts";
```
This design circumvents a plethora of complexity spawned by package management
software, centralized code repositories, and superfluous file formats.
## Command line interface
### Flags
```
> deno -h
Usage: deno script.ts
Options:
--allow-read Allow file system read access.
--allow-write Allow file system write access.
--allow-net Allow network access.
--allow-env Allow environment access.
--allow-run Allow running subprocesses.
-A, --allow-all Allow all permissions.
--recompile Force recompilation of TypeScript code.
-h, --help Print this message.
-D, --log-debug Log debug output.
-v, --version Print the version.
-r, --reload Reload cached remote resources.
--v8-options Print V8 command line options.
--types Print runtime TypeScript declarations.
--prefetch Prefetch the dependencies.
--info Show source file related info
--fmt Format code.
Environment variables:
DENO_DIR Set deno's base directory.
```
### 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`.
### 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
```
## Internal details
### Schematic diagram
<img src="schematic_v0.2.png">
### Profiling
To start profiling,
```sh
# Make sure we're only building release.
export DENO_BUILD_MODE=release
# Build deno and V8's d8.
./tools/build.py d8 deno
# Start the program we want to benchmark with --prof
./target/release/deno tests/http_bench.ts --allow-net --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 brower, and select
`prof.json` to view the distribution graphically.
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.
```sh
lldb -- target/debug/deno 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.
```sh
rust-lldb -- ./target/debug/deno tests/http_bench.ts --allow-net
# 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.30.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
```
### libdeno
deno's privileged side will primarily be programmed in Rust. However there will
be a small C API that wraps V8 to 1) define the low-level message passing
semantics, 2) provide a low-level test target, 3) provide an ANSI C API binding
interface for Rust. V8 plus this C API is called "libdeno" and the important
bits of the API is specified here:
[deno.h](https://github.com/denoland/deno/blob/master/libdeno/deno.h)
[libdeno.ts](https://github.com/denoland/deno/blob/master/js/libdeno.ts)
### Flatbuffers
We use Flatbuffers to define common structs and enums between TypeScript and
Rust. These common data structures are defined in
[msg.fbs](https://github.com/denoland/deno/blob/master/src/msg.fbs)
### Updating prebuilt binaries
```
./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
https://deno.land/benchmarks.html
The benchmark chart supposes `//website/data.json` has the type
`BenchmarkData[]` where `BenchmarkData` is defined like the below:
```typescript
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;
};
}
```
## 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).
### Submitting a pull request
Before submitting, please make sure the following is done:
1. There are tests that cover the changes.
2. Ensure `./tools/test.py` passes.
3. Format your code with
`PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run`.
<!-- TODO: set PYTHONPATH in format.ts when run API has env option -->
4. 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 mantained 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";
```

BIN
website/schematic_v0.2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

142
website/showdown_toc.js Normal file
View file

@ -0,0 +1,142 @@
// Extension loading compatible with AMD and CommonJs
(function(extension) {
"use strict";
if (typeof showdown === "object") {
// global (browser or nodejs global)
showdown.extension("toc", extension());
} else if (typeof define === "function" && define.amd) {
// AMD
define("toc", extension());
} else if (typeof exports === "object") {
// Node, CommonJS-like
module.exports = extension();
} else {
// showdown was not found so we throw
throw Error("Could not find showdown library");
}
})(function() {
function getHeaderEntries(sourceHtml) {
if (typeof window === "undefined") {
return getHeaderEntriesInNodeJs(sourceHtml);
} else {
return getHeaderEntriesInBrowser(sourceHtml);
}
}
function getHeaderEntriesInNodeJs(sourceHtml) {
var cheerio = require("cheerio");
var $ = cheerio.load(sourceHtml);
var headers = $("h1, h2, h3, h4, h5, h6");
var headerList = [];
for (var i = 0; i < headers.length; i++) {
var el = headers[i];
headerList.push(new TocEntry(el.name, $(el).text(), $(el).attr("id")));
}
return headerList;
}
function getHeaderEntriesInBrowser(sourceHtml) {
// Generate dummy element
var source = document.createElement("div");
source.innerHTML = sourceHtml;
// Find headers
var headers = source.querySelectorAll("h1, h2, h3, h4, h5, h6");
var headerList = [];
for (var i = 0; i < headers.length; i++) {
var el = headers[i];
headerList.push(new TocEntry(el.tagName, el.textContent, el.id));
}
return headerList;
}
function TocEntry(tagName, text, anchor) {
this.tagName = tagName;
this.text = text;
this.anchor = anchor;
this.children = [];
}
TocEntry.prototype.childrenToString = function() {
if (this.children.length === 0) {
return "";
}
var result = "<ul>\n";
for (var i = 0; i < this.children.length; i++) {
result += this.children[i].toString();
}
result += "</ul>\n";
return result;
};
TocEntry.prototype.toString = function() {
var result = "<li>";
if (this.text) {
result += '<a href="#' + this.anchor + '">' + this.text + "</a>";
}
result += this.childrenToString();
result += "</li>\n";
return result;
};
function sortHeader(tocEntries, level) {
level = level || 1;
var tagName = "H" + level,
result = [],
currentTocEntry;
function push(tocEntry) {
if (tocEntry !== undefined) {
if (tocEntry.children.length > 0) {
tocEntry.children = sortHeader(tocEntry.children, level + 1);
}
result.push(tocEntry);
}
}
for (var i = 0; i < tocEntries.length; i++) {
var tocEntry = tocEntries[i];
if (tocEntry.tagName.toUpperCase() !== tagName) {
if (currentTocEntry === undefined) {
currentTocEntry = new TocEntry();
}
currentTocEntry.children.push(tocEntry);
} else {
push(currentTocEntry);
currentTocEntry = tocEntry;
}
}
push(currentTocEntry);
return result;
}
return {
type: "output",
filter: function(sourceHtml) {
var headerList = getHeaderEntries(sourceHtml);
// No header found
if (headerList.length === 0) {
return sourceHtml;
}
// Sort header
headerList = sortHeader(headerList);
// Skip the title.
if (headerList.length == 1) {
headerList = headerList[0].children;
}
// Build result and replace all [toc]
var result =
'<div class="toc">\n<ul>\n' + headerList.join("") + "</ul>\n</div>\n";
return sourceHtml.replace(/\[toc\]/gi, result);
}
};
});

View file

@ -1,74 +1,91 @@
body {
color: #111;
color: #444;
background: #f0f0f0;
margin: 1em;
font-family: Arial;
font-size: 20px;
padding: 0;
line-height: 1.5;
font-family: sans-serif;
margin: 5ex 10ex;
max-width: 80ex;
}
main {
#manual img {
width: 100%;
max-width: 800px;
margin: 0px auto;
}
h1, h2, h3, h4 {
font-weight: normal;
margin-bottom: 0;
}
h1, h2, h3, h4, p, table {
margin-left: 8px;
margin-right: 8px;
}
table {
border-collapse: collapse;
}
td, th {
font-weight: normal;
text-align: center;
border: 1px dotted #bbb;
padding: 4px;
}
svg {
margin: 0px auto;
margin: 0px;
width: 100%;
height: 300px;
}
a {
color: #333;
}
a:hover {
color: #488;
color: #106ad5;
}
a.badge {
display: inline-block;
border-radius: 2px;
height: 20px;
transition: .3s box-shadow;
}
a.badge:hover {
box-shadow: 0 0 5px 0 #333;
pre a {
color: #001631;
}
a[href^="#"] { /* Hash links */
text-decoration: none;
h2 a, h3 a {
display: none;
color: #3bace5;
margin-right: 0.5rem;
text-decoration: none;
}
a[href^="#"]:hover {
text-decoration: underline;
color: #3d9bcc;
h2:hover a,
h3:hover a {
display: inline;
}
pre {
background: #ddd;
/* background: rgba(36, 126, 233, 0.03); */
color: #161616;
background: rgba(36, 126, 233, 0.1);
padding: 15px;
word-wrap: normal;
overflow-x: auto;
}
table {
border-collapse: collapse;
border-spacing: 0;
header {
display: flex;
align-items: center;
margin: 16px 4px;
}
td, th {
text-align: center;
vertical-align: middle;
border: 1px solid #aaa;
padding: 6px;
header > * {
margin: 16px;
}
header h1 {
margin: 8px 0;
}
@media only screen and (max-device-width: 480px) {
main {
margin: 15px;
}
body {
margin: 0;
}

40
website/style_guide.html Normal file
View file

@ -0,0 +1,40 @@
<!-- Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -->
<!DOCTYPE html>
<html>
<head>
<title>Deno Style Guide</title>
<link rel="stylesheet" href="style.css" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
</head>
<body>
<main>
<div id="manual"></div>
<script src="https://unpkg.com/showdown@1.9.0/dist/showdown.js"></script>
<script src="showdown_toc.js"></script>
<script>
const url = "style_guide.md";
async function main() {
const response = await fetch(url);
const content = await response.text();
let converter = new showdown.Converter({ extensions: ["toc"] });
let html = converter.makeHtml(content);
const manual = document.getElementById("manual");
manual.innerHTML = html;
// To make anchor links work properly, we have to manually scroll
// since the markdown is rendered dynamically.
if (window.location.hash) {
let el = document.getElementById(window.location.hash.slice(1));
window.scrollTo({ top: el.offsetTop });
}
}
main();
</script>
</main>
</body>
</html>

264
website/style_guide.md Normal file
View file

@ -0,0 +1,264 @@
# Deno Style Guide
[toc]
## Use TypeScript
## Use the term "module" instead of "library" or "package"
For clarity and consistency avoid the terms "library" and "package". Instead use
"module" to refer to a single JS or TS file and also to refer to a directory of
TS/JS code.
## Do not use the filename `index.ts` nor `index.js`
Deno does not treat "index.js" or "index.ts" in a special way. By using these
filenames, it suggests that they can be left out of the module specifier when
they cannot. This is confusing.
If a directory of code needs a default entry point, use the filename `mod.ts`.
The filename `mod.ts` follows Rusts convention, is shorter than `index.ts`, and
doesnt come with any preconceived notions about how it might work.
## Within `deno_std`, do not depend on external code
`deno_std` is intended to be baseline functionality that all Deno programs can
rely on. We want to guarantee to users that this code does not include
potentially unreviewed third party code.
## Within `deno_std`, minimize dependencies; do not make circular imports.
Although `deno_std` is a standalone codebase, we must still be careful to keep
the internal dependencies simple and manageable. In particular, be careful to
not to introduce circular imports.
## For consistency, use underscores, not dashes in filenames.
Example: Instead of `file-server.ts` use `file_server.ts`.
## Format code according using prettier.
More specifically, code should be wrapped at 80 columns and use 2-space
indentation and use camel-case. Use `//format.ts` to invoke prettier.
## Exported functions: max 2 args, put the rest into an options object.
When designing function interfaces, stick to the following rules.
1. A function that is part of the public API takes 0-2 required arguments, plus
(if necessary) an options object (so max 3 total).
2. Optional parameters should generally go into the options object.
An optional parameter that's not in an options object might be acceptable if
there is only one, and it seems inconceivable that we would add more optional
parameters in the future.
3. The 'options' argument is the only argument that is a regular 'Object'.
Other arguments can be objects, but they must be distinguishable from a
'plain' Object runtime, by having either:
- a distinguishing prototype (e.g. `Array`, `Map`, `Date`, `class MyThing`)
- a well-known symbol property (e.g. an iterable with `Symbol.iterator`).
This allows the API to evolve in a backwards compatible way, even when the
position of the options object changes.
```ts
// BAD: optional parameters not part of options object. (#2)
export function resolve(
hostname: string,
family?: "ipv4" | "ipv6",
timeout?: number
): IPAddress[] {}
// GOOD.
export interface ResolveOptions {
family?: "ipv4" | "ipv6";
timeout?: number;
}
export function resolve(
hostname: string,
options: ResolveOptions = {}
): IPAddress[] {}
```
```ts
export interface Environment {
[key: string]: string;
}
// BAD: `env` could be a regular Object and is therefore indistinguishable
// from an options object. (#3)
export function runShellWithEnv(cmdline: string, env: Environment): string {}
// GOOD.
export interface RunShellOptions {
env: Environment;
}
export function runShellWithEnv(
cmdline: string,
options: RunShellOptions
): string {}
```
```ts
// BAD: more than 3 arguments (#1), multiple optional parameters (#2).
export function renameSync(
oldname: string,
newname: string,
replaceExisting?: boolean,
followLinks?: boolean
) {}
// GOOD.
interface RenameOptions {
replaceExisting?: boolean;
followLinks?: boolean;
}
export function renameSync(
oldname: string,
newname: string,
options: RenameOptions = {}
) {}
```
```ts
// BAD: too many arguments. (#1)
export function pwrite(
fd: number,
buffer: TypedArray,
offset: number,
length: number,
position: number
) {}
// BETTER.
export interface PWrite {
fd: number;
buffer: TypedArray;
offset: number;
length: number;
position: number;
}
export function pwrite(options: PWrite) {}
```
## TODO Comments
TODO comments should be include an issue or the author's github username in
parentheses. Example:
```
// TODO(ry) Add tests.
// TODO(#123) Support Windows.
```
## Copyright headers
Most files in `deno_std` should have the following copyright header:
```
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
```
If the code originates elsewhere, ensure that the file has the proper copyright
headers. We only allow MIT, BSD, and Apache licensed code in `deno_std`.
## Top level functions should not use arrow syntax
Top level functions should use the `function` keyword. Arrow syntax should be
limited to closures.
Bad
```
export const foo(): string => {
return "bar";
}
```
Good
```
export function foo(): string {
return "bar";
}
```
## Meta-programming is discouraged. Including the use of Proxy.
Be explicit even when it means more code.
There are some situations where it may make sense to use such techniques, but in
the vast majority of cases it does not.
## If a filename starts with underscore, do not link to it: `_foo.ts`
Sometimes there maybe situations where an internal module is necessary but its
API is not meant to be stable or linked to. In this case prefix it with an
underscore. By convention, only files in its own directory should import it.
## Use JSDoc to document exported machinery
We strive for complete documentation. Every exported symbol ideally should have
a documentation line.
If possible, use a single line for the JS Doc. Example:
```ts
/** foo does bar. */
export function foo() {
// ...
}
```
It is important that documentation is easily human readable, but there is also a
need to provide additional styling information to ensure generated documentation
is more rich text. Therefore JSDoc should generally follow markdown markup to
enrich the text.
While markdown supports HTML tags, it is forbidden in JSDoc blocks.
Code string literals should be braced with the back-tick (\`) instead of quotes.
For example:
```ts
/** Import something from the `deno` module. */
```
Do not document function arguments unless they are non-obvious of their intent
(though if they are non-obvious intent, the API should be considered anyways).
Therefore `@param` should generally not be used.
Vertical spacing should be minimized whenever possible. Therefore single line
comments should be written as:
```ts
/** This is a good single line JSDoc */
```
And not
```ts
/**
* This is a bad single line JSDoc
*/
```
Code examples should not utilise the triple-back tick (\`\`\`) notation or tags.
They should just be marked by indentation, which requires a break before the
block and 6 additional spaces for each line of the example. This is 4 more than
the first column of the comment. For example:
```ts
/** A straight forward comment and an example:
*
* import { foo } from "deno";
* foo("bar");
*/
```
Code examples should not contain additional comments. It is already inside a
comment. If it needs further comments is not a good example.

1
website/welcome.js Normal file
View file

@ -0,0 +1 @@
console.log("Welcome to Deno 🦕");