Denoをソースからビルドする
最近 Deno の npm support および Node.js compability について知っておきたくなったので、まずは Deno を手元で動かせるようにしてみる。
- Building deno from Source
https://deno.land/manual@v1.29.4/references/contributing/building_from_source
基本的にはこのマニュアル通りに進めれば一発でビルドは通る、素晴らしい。
ビルドに際しては mold
がビルド速度に寄与するのでこちらも活用されたい。
mold -run cargo build -q
- moldを使うとRustのビルドが速くなる
https://keens.github.io/blog/2021/12/20/moldwotsukautorustnobirudogahayakunaru/
このままでは毎度 ./target/debug/deno run
でビルドした deno バイナリを実行する必要があるので
alias mydeno='path/to/deno/target/debug/deno'
と ailias を作っておくのも良いかもしれない。
deno_land/deno repository は denoland/deno_std を git submodule として登録しているようで、
cli などのツール群と共に std
をデバッグしたい場合の正攻法がイマイチ分からなかった。
deno および deno_std を両方 fork しておいて、.gitmodules
を以下のように書き換えた。
[submodule "deno_third_party"]
path = third_party
url = https://github.com/denoland/deno_third_party.git
shallow = true
[submodule "test_util/std"]
path = test_util/std
- url = https://github.com/denoland/deno_std
+ url = https://github.com/YOUR_NAME/deno_std
shallow = true
[submodule "test_util/wpt"]
path = test_util/wpt
url = https://github.com/web-platform-tests/wpt.git
- submodule の向き先 url を変更する
https://qiita.com/8mamo10/items/fd11d8c7a2d928b39173
submodule の情報を更新した後、git submodule update --init --recursive
で
ローカルの deno のプロジェクトルートから test_util/std
にフォークした std
のリポジトリが入るようになる。
以下不要
ここからさらに cli/deno_std.rs
を見てみるとこんな記述がある。
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use deno_core::url::Url;
use once_cell::sync::Lazy;
// WARNING: Ensure this is the only deno_std version reference as this
// is automatically updated by the version bump workflow.
static CURRENT_STD_URL_STR: &str = "https://deno.land/std@0.173.0/";
pub static CURRENT_STD_URL: Lazy<Url> =
Lazy::new(|| Url::parse(CURRENT_STD_URL_STR).expect("invalid std url"));
なので、このまま test_util/std/**
以下のソースを変更して cli 経由の動作をデバッグしようにも公式にホストされた std
がインストールされてしまう。
まずは以下のようにディレクトリをホストする書き捨てスクリプトを用意しておき、deno run -A server.ts
で起動する。
import { serve } from "https://deno.land/std@0.173.0/http/server.ts";
import { serveDir } from "https://deno.land/std@0.173.0/http/file_server.ts";
import { resolve } from "https://deno.land/std@0.173.0/path/mod.ts";
serve((req) => {
const pathname = new URL(req.url).pathname;
if (pathname.startsWith("/")) {
return serveDir(req, {
fsRoot: resolve(...[Deno.cwd(), "std"]),
});
}
// Do dynamic responses
return new Response();
}, {
addr: `:8080`
});
そして cli/deno_std.rs
の "https://deno.land/std@0.173.0/"
を "http://localhost:8000/"
に書き換えてしまう。
この状態で mydeno run -A npm:cowsay Hi!
などのコマンドを打つと、
download http://localhost:8000/node/_stream.d.ts
のようなログが見られ、ローカルのソースから std
を引っ張ってくれるようになる。
これらは実行時に /home/USER_NAME/.cache/deno/deps/http/localhost_PORT8000
へキャッシュされるので
この運用だとソースを変更してコマンドを打つ前に毎度キャッシュクリアをする必要がある。
このやり方で良いのだろうか。。?
動作環境
上記でとりあえずのデバッグ体制が整ったので動かしてみたい npm ライブラリを試していく。
以下は alias を通した下記の構成でバイナリを動かしていくこととする。
$ uname -a
Linux foobar 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ deno --version
deno 1.29.4 (debug, x86_64-unknown-linux-gnu)
v8 10.9.194.5
typescript 4.9.4
$ mydeno --version
deno 1.29.4 (debug, x86_64-unknown-linux-gnu)
v8 10.9.194.5
typescript 4.9.4
また、 std へのパスを環境変数に設定する。
$ export DENO_NODE_COMPAT_URL=file:///path/to/deno_std/
$ echo "${DENO_NODE_COMPAT_URL}"
file:///path/to/deno_std/
std は 0.173.0
で検証する。
Storybook
上記の deno repository とは別の適当な deno プロジェクト用のディレクトリを作成したのちに
deno run -A sb@latest init --builder=vite
を実行する。プロジェクトの設定などを選択したのちに下記のエラーが出た。
Error: Empty filepath.
$ deno run -A npm:sb@next init --builder=vite
Error: Empty filepath.
at pathDirname (deno:ext/node/02_require.js:50:13)
at new Module (deno:ext/node/02_require.js:257:17)
at Function.Module._resolveFilename (deno:ext/node/02_require.js:566:30)
at Function.resolve (deno:ext/node/02_require.js:824:21)
at getRendererDir (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:1:6676)
at componentsPath (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:11:1474)
at copyComponents (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:11:2661)
at async baseGenerator (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:37:682)
at async generator4 (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:46:1926)
at async doInitiate (file:///path/to/.cache/deno/npm/registry.npmjs.org/@storybook/cli/7.0.0-beta.31/dist/generate.js:371:78)
この issue と関係してそうな雰囲気がある。
- npm:ts-node doesn't work in Deno
https://github.com/denoland/deno/issues/17176- PR が出ているが、現時点では merge および release されていないのでローカルのソースの記述を PR と同期する。
- [WIP] feat(npm): add missing APIs to run ts-node
https://github.com/denoland/deno/pull/17191
ソースを変更した後は適宜ビルドをかける。
- [WIP] feat(npm): add missing APIs to run ts-node
- PR が出ているが、現時点では merge および release されていないのでローカルのソースの記述を PR と同期する。
could not find npm package
次に、mydeno run -A npm:sb@next init --builder=vite
で変更後の内容を適用した状態でコマンドを打つ。
諸々のインストールが済んだのちに下記のエラーが出た。
$ mydeno run -A npm:sb@next init --builder=vite
..
Error 'could not find npm package for 'file:///path/to/repository/github/ntd/test/.storybook/main.js'' contains boxed error of unknown type:
"could not find npm package for 'file:///path/to/repository/github/ntd/test/.storybook/main.js'"
これはおそらくStorybook側の問題で、この issue と関係してそうな雰囲気がある。
- Storybook cannot be built on packages using "type": "module"
https://github.com/storybookjs/storybook/issues/11587#issuecomment-1192326066-
npm:sb init
コマンドの時点では現状 ESM 形式での.storybook/main.mjs
生成に対応していなさそうな雰囲気なので、ここは
.storybook/package.json{ .. "type": "module" .. }
-
Top-level await promise never resolved
再度、mydeno run -A npm:sb@next init --builder=vite
を実行する。(上書きになるので -f オプションを付与する。)
$ mydeno run -A npm:sb@next init --builder=vite -f
..
🔎 checking possible migrations..
error: Uncaught (in worker "$DENO_STD_NODE_WORKER_THREAD") Top-level await promise never resolved
[{ threadId, workerData, environmentData }] = await once(
^
at <anonymous> (http://localhost:8000/node/worker_threads.ts:178:49)
error: Uncaught Error: Unhandled error. ('Top-level await promise never resolved')
この issue(std) と関係してそうな雰囲気がある。
- node: Get rid of Top-Level Await in "node/worker_threads.ts"
https://github.com/denoland/deno_std/issues/2921- PR が出ているが、現時点では merge および release されていないのでローカルのソースの記述を PR と同期する。
- refactor(node): don't use top level await in worker_threads.ts
https://github.com/denoland/deno_std/pull/3108
- refactor(node): don't use top level await in worker_threads.ts
- PR が出ているが、現時点では merge および release されていないのでローカルのソースの記述を PR と同期する。
コマンドラインが進まなくなる
再度、mydeno run -A npm:sb@next init --builder=vite
を実行する。(上書きになるので -f オプションを付与する。)
$ mydeno run -A npm:sb@next init --builder=vite -f
..
To run your Storybook, type:
npm run storybook
For more information visit: https://storybook.js.org
- Storybook の cli に対応する部分のコードを見てデバッグした限りは
init
コマンド自体は正常に終了しているものの、 deno のプロセスが正しく終了していないように見える。
TypeError: worker.unref is not a function
さきほどのプロセスが終了しないというのはさておき、いったん必要なものはインストールされたので
次は dev
コマンドを試してみる。
その前に、下記工程を済ませておく。
-
.storybook/package.json
- もう不要なので削除する
-
.storybook/main.js
-
.storybook/main.mjs
にリネームする - 中身を
export default
にする
.storybook/main.mjsexport default { "stories": [ "../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions" ], "framework": { "name": "@storybook/react-vite", "options": {} }, "docs": { "autodocs": "tag" } }
-
この状態で mydeno run -A npm:sb@next dev
で開発サーバーを起動する。
$ mydeno run -A npm:sb@next dev
@storybook/cli v7.0.0-beta.31
ERR! TypeError: worker.unref is not a function
ERR! at startWorkerThreadService (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild/0.16.17/lib/main.js:2280:10)
ERR! at transformSync (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild/0.16.17/lib/main.js:2008:29)
ERR! at compile2 (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:4851:43)
ERR! at Module._compile (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:2254:31)
ERR! at Module._extensions..js (deno:ext/node/02_require.js:780:12)
ERR! at Object.newLoader [as .mjs] (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:2262:9)
ERR! at Module.load (deno:ext/node/02_require.js:658:34)
ERR! at Function.Module._load (deno:ext/node/02_require.js:515:14)
ERR! at Module.require (deno:ext/node/02_require.js:680:21)
ERR! at require (deno:ext/node/02_require.js:820:18)
ERR! TypeError: worker.unref is not a function
ERR! at startWorkerThreadService (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild/0.16.17/lib/main.js:2280:10)
ERR! at transformSync (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild/0.16.17/lib/main.js:2008:29)
ERR! at compile2 (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:4851:43)
ERR! at Module._compile (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:2254:31)
ERR! at Module._extensions..js (deno:ext/node/02_require.js:780:12)
ERR! at Object.newLoader [as .mjs] (file:///home/hajime/.cache/deno/npm/registry.npmjs.org/esbuild-register/3.4.2/dist/node.js:2262:9)
ERR! at Module.load (deno:ext/node/02_require.js:658:34)
ERR! at Function.Module._load (deno:ext/node/02_require.js:515:14)
ERR! at Module.require (deno:ext/node/02_require.js:680:21)
ERR! at require (deno:ext/node/02_require.js:820:18)
Node.js の Worker
インターフェースには ref
というメソッドが定義されているが、Deno の Node.js 互換 Worker
インターフェースには現時点で実装されていないようだ。
https://github.com/nodejs/node/blob/v18.12.1/lib/internal/worker.js#L378
https://github.com/denoland/deno_std/blob/0.173.0/node/worker_threads.ts#L34
Deno は現在 Node.js の LTSである 18.12.1
を互換の対象としている。