Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating documentation around module usage with Deno #578

Merged
merged 10 commits into from
Jul 16, 2024
Merged
6 changes: 2 additions & 4 deletions runtime/_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ export const sidebar = [
label: "Using & Publishing Modules",
items: [
"/runtime/manual/basics/modules/",
"/runtime/manual/basics/modules/remote_modules/",
"/runtime/manual/basics/modules/publishing_modules/",
"/runtime/manual/basics/modules/reloading_modules/",
"/runtime/manual/basics/modules/proxies/",
"/runtime/manual/basics/modules/integrity_checking/",
"/runtime/manual/advanced/publishing/",
"/runtime/manual/advanced/publishing/dnt/",
"/runtime/manual/advanced/private_repositories/",
],
},
Expand Down Expand Up @@ -299,7 +298,6 @@ export const sidebar = [
label: "Basic Examples",
items: [
"/runtime/tutorials/hello_world/",
"/runtime/tutorials/manage_dependencies/",
"/runtime/tutorials/fetch_data/",
"/runtime/tutorials/read_write_files/",
"/runtime/tutorials/hashbang/",
Expand Down
14 changes: 0 additions & 14 deletions runtime/manual/advanced/publishing/dnt.md

This file was deleted.

76 changes: 0 additions & 76 deletions runtime/manual/advanced/publishing/index.md

This file was deleted.

84 changes: 0 additions & 84 deletions runtime/manual/basics/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ title: "ECMAScript Modules in Deno"
- [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
allows you to include and use modules held elsewhere, on your local file
system or remotely.
- Imports are URLs or file system paths.
- [export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)
allows you to specify which parts of your module are accessible to users who
import your module.
Expand Down Expand Up @@ -48,29 +47,6 @@ console.log(totalCost(19, 31, 1.2)); // 60
console.log(totalCost(45, 27, 1.15)); // 82.8
```

## Remote Import

In the local import example above an `add` and `multiply` method are imported
from a locally stored arithmetic module. The same functionality can be created
by importing `add` and `multiply` methods from a remote module too.

In this case the Ramda module is referenced, including the version number. Also
note a JavaScript module is imported directly into a TypeScript module, Deno has
no problem handling this.

**Command:** `deno run ./remote.ts`

```ts
import { add, multiply } from "https://deno.land/x/[email protected]/mod.ts";

function totalCost(outbound: number, inbound: number, tax: number): number {
return multiply(add(outbound, inbound), tax);
}

console.log(totalCost(19, 31, 1.2)); // 60
console.log(totalCost(45, 27, 1.15)); // 82.8
```

## Export

In the local import example above the `add` and `multiply` functions are
Expand All @@ -94,63 +70,3 @@ All functions, classes, constants and variables which need to be accessible
inside external modules must be exported. Either by prepending them with the
`export` keyword or including them in an export statement at the bottom of the
file.

## FAQ
thisisjofrank marked this conversation as resolved.
Show resolved Hide resolved

### How do I import a specific version of a module?

Specify the version in the URL. For example, this URL fully specifies the code
being run: `https://unpkg.com/[email protected]/dist/liltest.js`.

### 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 assertion library across a large
project. Rather than importing `"https://deno.land/std/assert/mod.ts"`
everywhere, you could create a `deps.ts` file that exports the third-party code:

**deps.ts**

```ts
export {
assert,
assertEquals,
assertStringIncludes,
} from "https://deno.land/[email protected]/assert/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 { assertEquals, runTests, test } from "./deps.ts";
```

This design circumvents a plethora of complexity spawned by package management
software, centralized code repositories, and superfluous file formats.

### How can I trust a URL that may change?

By using a lock file (with the `--lock` command line flag), you can ensure that
the code pulled from a URL is the same as it was during initial development. You
can learn more about this [here](./integrity_checking.md).

### But what if the host of the URL goes down? The source won't be available.

This, like the above, is a problem faced by _any_ remote dependency system.
Relying on external servers is convenient for development but brittle in
production. Production software should always vendor its dependencies. In Node
this is done by checking `node_modules` into source control. In Deno this is
done by adding a [vendor field](/vendoring) to your `deno.json` file:

```bash
{
"vendor": true
}
```

before running your project.
80 changes: 80 additions & 0 deletions runtime/manual/basics/modules/module_metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: "Module Metadata"
oldUrl:
- /runtime/manual/examples/module_metadata/
---

## Concepts

- [import.meta](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import.meta)
can provide information on the context of the module.
- The boolean [import.meta.main](https://deno.land/api?s=ImportMeta#prop_main)
will let you know if the current module is the program entry point.
- The string [import.meta.url](https://deno.land/api?s=ImportMeta#prop_url) will
give you the URL of the current module.
- The string
[import.meta.filename](https://deno.land/api?s=ImportMeta#prop_filename) will
give you the fully resolved path to the current module. _For local modules
only_.
- The string
[import.meta.dirname](https://deno.land/api?s=ImportMeta#prop_dirname) will
give you the fully resolved path to the directory containing the current
module. _For local modules only_.
- The [import.meta.resolve](https://deno.land/api?s=ImportMeta#prop_resolve)
allows you to resolve specifier relative to the current module. This function
takes into account an import map (if one was provided on startup).
- The string [Deno.mainModule](https://deno.land/api?s=Deno.mainModule) will
give you the URL of the main module entry point, i.e. the module invoked by
the deno runtime.

## Example

The example below uses two modules to show the difference between
`import.meta.url`, `import.meta.main` and `Deno.mainModule`. In this example,
`module_a.ts` is the main module entry point:

```ts title="module_b.ts"
export function outputB() {
console.log("Module B's import.meta.url", import.meta.url);
console.log("Module B's mainModule url", Deno.mainModule);
console.log(
"Is module B the main module via import.meta.main?",
import.meta.main,
);
}
```

```ts title="module_a.ts"
import { outputB } from "./module_b.ts";

function outputA() {
console.log("Module A's import.meta.url", import.meta.url);
console.log("Module A's mainModule url", Deno.mainModule);
console.log(
"Is module A the main module via import.meta.main?",
import.meta.main,
);
console.log(
"Resolved specifier for ./module_b.ts",
import.meta.resolve("./module_b.ts"),
);
}

outputA();
console.log("");
outputB();
```

If `module_a.ts` is located in `/home/alice/deno` then the output of
`deno run --allow-read module_a.ts` is:

```console
Module A's import.meta.url file:///home/alice/deno/module_a.ts
Module A's mainModule url file:///home/alice/deno/module_a.ts
Is module A the main module via import.meta.main? true
Resolved specifier for ./module_b.ts file:///home/alice/deno/module_b.ts

Module B's import.meta.url file:///home/alice/deno/module_b.ts
Module B's mainModule url file:///home/alice/deno/module_a.ts
Is module B the main module via import.meta.main? false
```
89 changes: 89 additions & 0 deletions runtime/manual/basics/modules/publishing_modules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
Title: Publishing Modules
thisisjofrank marked this conversation as resolved.
Show resolved Hide resolved
---

Any Deno program that defines an export can be published as a module. This
allows other developers to import and use your code in their own projects.
Modules can be published to [JSR](https://jsr.io).

## Configuring your module

To configure your module for publishing, you need to ensure you have the
following properties defined in a `deno.json` file at the root of your project:

```json title="deno.json"
{
"name": "@my-scope/my-module",
"version": "1.0.0",
"exports": "./mod.ts"
}
```

In order to publish, you need a
[JSR scope and a new package](https://jsr.io/docs/publishing-packages#creating-a-scope-and-package)
to identify your module. You can create your scope and package at
[jsr.io/new](https://jsr.io/new).

The `name` property in your `deno.json` file is a concatenation of your scope
and package name, separated by a `/`. The `exports` property should point to the
main entry point of your module.

## Publishing your module

Packages can be published to JSR in the CLI with the
[`deno publish` command](https://jsr.io/docs/publishing-packages#publishing-from-your-local-machine).

To publish your module, run the following command in the root of your project:

```bash
deno publish
```

Before publishing, you can use the `--dry-run` flag locally to test the
publishing process, without actually publishing your module. This will print out
a list of all of the files that will be published and can be used to verify that
your module is set up correctly:

```bash
deno publish --dry-run
```

By default, interactive authentication is used to publish - this means that a
browser window will open to authenticate you with JSR. If you want to publish
without the interactive browser window, you can use the `--token` flag to
provide a JSR auth token:

```bash
deno publish --token <your-auth-token>
```

You can create a new auth token at
[jsr.io/account/tokens](https://jsr.io/account/tokens).

If you're configuring a CI pipeline to publish your module, you can use the
`--token` flag to authenticate with JSR but it's important to ensure that your
token is kept secure.

If you're publishing a package from GitHub Actions it is recommended to link
your repository by following the instructions at
[jsr.io/docs/publishing-packages#publishing-from-github-actions](https://jsr.io/docs/publishing-packages#publishing-from-github-actions).
This will allow you to publish packages without needing to provide an auth token
and instead uses OIDC authentication from GitHub itself.
thisisjofrank marked this conversation as resolved.
Show resolved Hide resolved

## Other publishing methods

You can publish your modules from the browser at
[jsr.io/new](https://jsr.io/new).

## Publishing for Node

Library authors may want to make their Deno modules available to Node.js users.
This is possible by using the [dnt](https://github.com/denoland/dnt) build tool.

dnt allows you to develop your Deno module mostly as-is and use a single Deno
script to build, type check, and test an npm package in an output directory.
Once built, you only need to `npm publish` the output directory to distribute it
to Node.js users.

For more details, see
[https://github.com/denoland/dnt](https://github.com/denoland/dnt).
Loading