惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
Cloudbric
Cloudbric
Schneier on Security
Schneier on Security
V2EX - 技术
V2EX - 技术
N
News and Events Feed by Topic
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
W
WeLiveSecurity
博客园 - 司徒正美
Jina AI
Jina AI
S
Secure Thoughts
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 三生石上(FineUI控件)
The Last Watchdog
The Last Watchdog
S
Security @ Cisco Blogs
S
SegmentFault 最新的问题
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
SecWiki News
SecWiki News
Google DeepMind News
Google DeepMind News
T
Troy Hunt's Blog
H
Heimdal Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News and Events Feed by Topic
雷峰网
雷峰网
Last Week in AI
Last Week in AI
IT之家
IT之家
Project Zero
Project Zero
O
OpenAI News
腾讯CDC
The Hacker News
The Hacker News
L
Lohrmann on Cybersecurity
T
Tenable Blog
博客园_首页
C
Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
S
Schneier on Security
Scott Helme
Scott Helme
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
人人都是产品经理
人人都是产品经理
P
Privacy International News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Deno

Deno 2.8 | Deno Claw Patrol: an open-source security firewall for agents | Deno Fresh 2.3: Zero JS by default, View Transitions, and Temporal support | Deno Deno 2.7: Temporal API, Windows ARM, and npm overrides | Deno Build a dinosaur runner game with Deno, pt. 6 | Deno Build a dinosaur runner game with Deno, pt. 5 | Deno Deno Deploy is Generally Available | Deno Introducing Deno Sandbox | Deno Build a dinosaur runner game with Deno, pt. 4 | Deno Build a dinosaur runner game with Deno, pt. 3 | Deno Build a dinosaur runner game with Deno, pt. 2 | Deno React / Next.js Denial-of-Service Vulnerability: Deno Deploy users protected | Deno Deno 2.6: dx is the new npx | Deno Build a dinosaur runner game with Deno, pt. 1 | Deno React Server Functions / Next.js Vulnerability: Deno Deploy users protected | Deno My highlights from the new Deno Deploy | Deno Deno's Other Open Source Projects | Deno How Deno protects against npm exploits | Deno Help Us Raise $200k to Free JavaScript from Oracle | Deno Deno 2.5: Permissions in the config file | Deno Fresh 2.0 Graduates to Beta, Adds Vite Support | Deno Deno 2.4: deno bundle is back | Deno JavaScript™ Trademark Update | Deno What's coming to JavaScript | Deno A brief history of JavaScript | Deno Reports of Deno's Demise Have Been Greatly Exaggerated | Deno An Update on Fresh | Deno How Plaid migrated 100 services to a new database platform 5x faster with Deno | Deno Deno 2.3: Improved deno compile, local npm packages, and more | Deno Add JSR packages with pnpm and Yarn | Deno Zero-config Debugging with Deno and OpenTelemetry | Deno Exploring Art with TypeScript, Jupyter, Polars, and Observable Plot | Deno Deno v Oracle Update 3: Fighting the JavaScript Trademark | Deno Build a custom RAG AI agent in TypeScript and Jupyter | Deno How to get deep traces in your Node.js backend with OTel and Deno | Deno toranoana.deno #20 登録受付中(2025年3月14日) | Deno Node just added TypeScript support. What does that mean for Deno? | Deno The Dino 🦕, the Llama 🦙, and the Whale 🐋 | Deno Publish a lint rule, get a prize | Deno Deno 2.2: OpenTelemetry, Lint Plugins, node:sqlite | Deno If you're not using npm specifiers, you're doing it wrong | Deno How Deno's documentation is evolving | Deno Oracle justified its JavaScript trademark with Node.js—now it wants that ignored | Deno Introducing the JSR open governance board | Deno Intro to Wasm in Deno | Deno Announcing OpenAI on JSR | Deno Deno in 2024 | Deno Goodbye WinterCG, welcome WinterTC | Deno Build a SolidJS app with Deno | Deno Run your Next.js SSR app on Deno Deploy | Deno Solve Advent of Code 2024 with Deno and Win Prizes! | Deno Deno v. Oracle: Canceling the JavaScript Trademark | Deno Deno 2.1: Wasm Imports and other enhancements | Deno Build a Typesafe API with tRPC and Deno | Deno Self-contained Executable Programs with Deno Compile | Deno Build a Database App with Drizzle ORM and Deno | Deno Introducing your new JavaScript package manager: Deno | Deno Announcing Growthbook on JSR | Deno Build an Astro site with Deno | Deno How to convert CommonJS to ESM | Deno Announcing Deno 2 | Deno The Final Touches: What’s New In v2.0.0-rc.10 | Deno Announcing Stable V8 Bindings for Rust | Deno Deno 2.0 Release Candidate | Deno Secure, efficient private npm registries with Cloudsmith and Deno | Deno Painting the Plane as We Fly It: Designing JSR | Deno Introducing Web Cache API support on Deno Deploy | Deno Deno 1.46: The Last 1.x Release | Deno Protect your cloud spend with new Deno Deploy spend limits | Deno What we got wrong about HTTP imports | Deno Benchmarking AWS Lambda Cold Starts Across JavaScript Runtimes | Deno Announcing Supabase on JSR | Deno Deno 1.45: Workspace and Monorepo Support | Deno Introducing KV Backup for Deno Subhosting | Deno A Gentle Intro to TypeScript | Deno Announcing Hono on JSR | Deno How We Made the Deno Language Server Ten Times Faster | Deno How the Guardian uses Deno to audit accessibility and performance across their 2.7 million articles | Deno Introducing More Flexible Domain Association for Deno Subhosting | Deno The stabilization process of the Standard Library has begun | Deno Deno 1.44: Private npm registries, improved Node.js compat, and performance boosts | Deno How we built a secure, performant, multi-tenant cloud platform to run untrusted code | Deno The Deno Standard Library is now available on JSR | Deno How to document your JavaScript package | Deno Your Low Code Solution Needs an Escape Hatch | Deno Deno 1.43: Improved Language Server performance | Deno How Slack used Deno to save months of engineering effort in launching their new platform | Deno JSR Is Not Another Package Manager | Deno Announcing the Hookdeck SDK on JSR | Deno Announcing the Neon Serverless Driver on JSR | Deno An intro to TSConfig for JavaScript Developers | Deno How we built JSR | Deno How Netlify used Deno Subhosting to build a successful edge functions product | Deno Introducing Simpler Project Creation in Deno Deploy | Deno Deno 1.42: Better dependency management with JSR | Deno Introducing deployctl, the command line interface for Deno Deploy | Deno Introducing JSR - the JavaScript Registry | Deno How to add Monaco to a Next.js app and securely run untrusted user code | Deno Survey Results and Roadmap | Deno Deno 1.41: smaller deno compile binaries | Deno
dnt — the easiest way to publish a hybrid npm module for ESM and CommonJS | Deno
Andy Jiang · 2023-07-31 · via Deno

Though browsers and JavaScript have come a long way, writing and publishing JavaScript modules is still painful. To maximize adoption, your module should support CommonJS and ESM, JavaScript with TypeScript declarations, and work in Deno, Node.js, and web browsers. To achieve that, many resort to complex release pipelines or maintaining two copies of code with slightly different module syntax.

What if you could write your module once with modern tooling like TypeScript and transform it to support all use cases?

dnt — Deno to Node transform

dnt is a build tool that transforms Deno modules into Node.js/npm-compatible packages. Not only that, the transformed package:

  • supports both CommonJS and ESM,
  • can work in Node.js, Deno, browers,
  • runs tests in both CommonJS and ESM,
  • supports TypeScript and JavaScript

How does it work? At a high level:

  • Transforms Deno code to Node.js compatible TypeScript code
    • Rewrites Deno’s extensioned module specifiers to ones compatible with Node.js module resolution.
    • Injects shims for any Deno namespaces APIs detected, as well as other globals which can be configured.
    • Rewrites remote imports from Skypack or esm.sh as bare specifier imports and adds them to the package.json as dependencies.
    • Other remote imports are downloaded and included in the package.
  • Type checks the transformed TypeScript code with tsc.
  • Writes out the package as a set of ESM, CommonJS and TypeScript type declaration files along with a package.json.
  • Runs the final output in Node.js through a test runner which supports the Deno.test() API.

You can develop and test all your code in Deno and TypeScript. When it’s time to publish, you can use dnt to export it to Node.js/npm-compatible format.

Let’s run through an example with my module, is-42. (You can also view the final source code here.)

Write, transform, publish

We’ve created a simple and totally real module that tests whether a variable is the number 42. The main logic will be in mod.ts:


export function is42(num: number): boolean {
  return num === 42;
}

We’ll write some tests in mod_test.ts:


import { assertEquals } from "https://deno.land/std@0.192.0/testing/asserts.ts";
import { is42 } from "./mod.ts";

Deno.test("42 should return true", () => {
  assertEquals(true, is42(42));
});

Deno.test("1 should return false", () => {
  assertEquals(false, is42(1));
});

We can run the tests without any additional configuration with deno test:

$ deno test
Check file:///Users/andyjiang/Developer/deno/is-42/mod_test.ts
running 2 tests from ./mod_test.ts
42 should return true ... ok (13ms)
1 should return false ... ok (7ms)

ok | 2 passed | 0 failed (142ms)

Finally, let’s also add a LICENSE and README.md file in the directory root, because it’s a real module:

a screenshot of the directory

That’s it!

Let’s transform this to an npm package by creating the build script, build_npm.ts:

import { build, emptyDir } from "https://deno.land/x/dnt@0.37.0/mod.ts";

await emptyDir("./npm");

await build({
  entryPoints: ["./mod.ts"],
  outDir: "./npm",
  shims: {
    deno: true,
  },
  package: {
    name: "is-42",
    version: Deno.args[0],
    description:
      "Boolean function that returns whether or not parameter is the number 42",
    license: "MIT",
    repository: {
      type: "git",
      url: "git+https://github.com/lambtron/is-42.git",
    },
    bugs: {
      url: "https://github.com/lambtron/is-42/issues",
    },
  },
  postBuild() {
    Deno.copyFileSync("LICENSE", "npm/LICENSE");
    Deno.copyFileSync("README.md", "npm/README.md");
  },
});

This script creates a new npm folder as the output directory, where it outputs an entire npm package from your module.

In the build() options, we set the entry file, output directory, shims, and all the context needed to build out a package.json file.

In the postBuild() function, we include filesystem operations to copy our LICENSE and README.md files accordingly.

Let’s run build_npm.ts script with the version as a parameter:

$ deno run -A build_npm.ts 0.0.1
[dnt] Transforming...
[dnt] Running npm install...

added 6 packages, and audited 7 packages in 2s

found 0 vulnerabilities
[dnt] Building project...
[dnt] Type checking ESM...
[dnt] Emitting ESM package...
[dnt] Emitting script package...
[dnt] Running post build action...
[dnt] Running tests...

> test
> node test_runner.js

Running tests in ./script/mod_test.js...

test 42 should return true ... ok
test 1 should return false ... ok

Running tests in ./esm/mod_test.js...

test 42 should return true ... ok
test 1 should return false ... ok
[dnt] Complete!

If you’re following along, your directory should have a new subdirectory npm, in it contains your transformed npm package (which supports CJS and ESM) as well as tests in both formats.

screenshot of our new npm subdirectory

Not only are tests generated for CJS and ESM, they’re also run using both Deno and Node, so you can be confident your code runs in both runtimes.

Now, publishing your CommonJS/ESM compatible npm package is as simple as:

Check out the published package on npm.

With dnt transforming your module to support CommonJS and ES Modules, maintaining your module is easier, as your code base is smaller.

Automate with GitHub Actions

To make it easier to publish everytime we tag a release, we can use GitHub Actions with dnt. Note that the below is an extremely simplified version, but should get you started in the right direction.

Create a .github/workflows/action.yml directory and file, which will perform the following steps anytime a new release is tagged and published:

  • check out the repo
  • parse the release version
  • setup Deno
  • run the build_npm.ts script with release version number
  • setup Node and npm with an npm auth token
  • publish with npm publish npm/
name: Publish to registry
on:
  release:
    types: [published]

jobs:
  publish_to_npm:
    name: Publish to npm
    runs-on: ubuntu-latest
    steps:
      - name: Checkout is-42
        uses: actions/checkout@v3

      - name: Set env
        run: echo "RELEASE_VERSION=${GITHUB_REF

      - name: Setup Deno
        uses: denoland/setup-deno@v1
        with:
          deno-version: v1.x

      - name: Build npm package
        run: deno run -A build_npm.ts $RELEASE_VERSION

      - name: Setup Node/npm
        uses: actions/setup-node@v3
        with:
          node-version: 18
          registry-url: "https://registry.npmjs.org"
          scope: "@lambtron"

      - name: Publish to npm
        run: npm publish npm/ --access=public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

Note that you will need to create a Classic Token (type Automation) from npmjs.com and save that as a GitHub Actions secret as NPM_AUTH_TOKEN.

Now, everytime you publish a new tagged release, it will trigger this action and publish your module to npm.

For more details on using GitHub Actions with dnt, check out the documentation.

What’s next?

Writing software should be productive, simple, and fun. It shouldn’t also include managing complex build pipelines or intricate code bases to support the widest user base.

And while we believe ESM is the future, we recognize that many npm modules still use CommonJS. Module authors unfortunately bear the brunt of needing to support both CommonJS and ESM. So we like abstractions that make creating and publishing software simpler, such as dnt.

Are you using dnt? Let us know on Twitter or Discord.