Denoで作成したCLIツールをdntでNode.js互換に変換するメモ
DenoでCLIツールを作成したのですが、Node.jsでも使用できるようにしたくなりました。できれば二重管理はしたくないため方法を模索したところ、Deno公式からdntという変換用ツールが提供されていたので使用することにしました。CLIツールを変換する際にいくつか気を付けなければならない点があったため、dntを使用してjsrとnpmで公開するGitHub Actionsを設定するまでのメモを備忘のため残しておきます。
前提
$ deno -v
deno 2.2.5
$ grep "jsr:@deno/dnt" deno.lock
"jsr:@deno/dnt@*": "0.41.3",
$ node -v
v22.14.0
$ npm -v
10.9.2
コード変換
公式GitHubに書かれている通りビルド用スクリプトを作成する。変換時にnpm
コマンドが使用可能でなければエラーとなってしまうので、なければ事前にNode.jsをインストールしておく。
ビルドスクリプト例
import { build, emptyDir } from "jsr:@deno/dnt";
import packageInfo from "./deno.json" with { type: "json" };
await emptyDir("./npm");
await build({
entryPoints: [{
kind: "bin",
name: "your-package-cmd",
path: "./mod.ts"
}],
outDir: "./npm",
typeCheck: false,
declaration: false,
scriptModule: false,
shims: { // https://github.com/denoland/dnt?tab=readme-ov-file#shims
deno: true,
},
package: { // definition of package.json to publish to npm
name: "your-package",
version: packageInfo.version,
description: "Description of your-package.",
author: "yourname",
license: "MIT",
repository: {
type: "git",
url: "git+https://github.com/yourname/your-package.git"
},
keywords: [
"some",
"words",
"here"
],
},
postBuild() { // running steps after transpile
Deno.copyFileSync("LICENSE", "npm/LICENSE");
Deno.copyFileSync("README.md", "npm/README.md");
},
});
特筆事項
バージョンの同期
deno.json
内のバージョンと同期させるためにpackageInfo
をインポートしてpackageInfo.version
を使用する。
CLIツールとして変換
公式で言及されている通り、CLIツールとして変換するには#!/usr/bin/env node
を追加したりするためにentryPoints
でそのように指定しなければならない。name
プロパティで指定した内容は生成されるpackage.json
内に以下が追加される。
{
...,
"bin": {
"your-package-cmd": "./esm/mod.js"
},
...
}
CJS対応の無効化
scriptModule: false
を指定することでCJS対応をスキップすることができる。私の場合はfalse
にしなければエラーとなり変換できなかった。CLIツールの場合はわざわざCJSに対応してもあまり意味がないように思われるため、false
に設定するのが無難と思われる。
最低限のファイル出力
CLIツールとして変換する場合、型定義などは通常必要ないためdeclaration: false
を指定して型定義等の出力を抑制する。具体的にはmod.ts
の変換結果が以下のように変化する。
-
declaration: true
(=指定なし)mod.d.ts mod.d.ts.map mod.js
-
declaration: false
mod.js
GitHub Actions
定義ファイル例
name: Publish Package
on:
push:
branches:
- main
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Install Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
registry-url: "https://registry.npmjs.org"
- name: Translate by dnt
run: deno run -A ./build_npm.ts
- name: Publish to npm
run: npm publish --provenance
working-directory: ./npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Publish to jsr
run: deno publish
特筆事項
環境整備
先ほども書いたがコード変換にはnpm
コマンドが使用可能である必要があるため、DenoとNode.js両方の環境をセットアップする。
作業ディレクトリ
変換後のコードはpackage.json
を含めoutDir
で指定したディレクトリに出力される。そのため、npm publish
コマンドを実行する際は作業ディレクトリを出力先ディレクトリにする必要がある。
雑記
CLIツールの場合はentryPoints
で色々指定しなければならないという部分を読んでおらず若干つまずきました。
Discussion