Deno が workspace に対応したので試してみたら Fresh とは相性が悪いようなので暫定対応

Deno 1.45 で workspace に対応した。
Fresh でも使えないかと思い、試してみたら相性が良くないようなので暫定対応した。

参考

やってみた、一部動かなかった

以下のようなディレクトリ構成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├─app-a
│ ├─components
│ ├─islands
│ ├─routes
│ │ ├─api
│ │ `─greet
│ `─static
├─app-b
│ ├─components
│ ├─islands
│ ├─routes
│ │ ├─api
│ │ └─greet
│ `─static
├─share <= app-a, app-b で共通のモジュール
`─deno.json <= workspace の設定がされる deno.json

app-a, app-b はそれぞれ独立したアプリケーションで、共通の share ディレクトリにあるモジュールを参照する。

./deno.json 以下のように記述する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"lock": false,
"lint": {
"rules": {
"tags": [
"fresh",
"recommended"
]
}
},
"exclude": [
"**/_fresh/*"
],
"imports": {
"$fresh/": "https://deno.land/x/fresh@1.6.8/",
"preact": "https://esm.sh/preact@10.19.6",
"preact/": "https://esm.sh/preact@10.19.6/",
"@preact/signals": "https://esm.sh/*@preact/signals@1.2.2",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1",
"tailwindcss": "npm:tailwindcss@3.4.1",
"tailwindcss/": "npm:/tailwindcss@3.4.1/",
"tailwindcss/plugin": "npm:/tailwindcss@3.4.1/plugin.js",
"$std/": "https://deno.land/std@0.216.0/",
"share": "./share/lib.ts"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
},
"nodeModulesDir": false,
"workspace": ["./app-a", "./app-b"]
}

./app-a/deno.json には以下のように記述する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"tasks": {
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
"cli": "echo \"import '\\$fresh/src/dev/cli.ts'\" | deno run --unstable -A -",
"manifest": "deno task cli manifest $(pwd)",
"start": "deno run -A --watch=static/,routes/ dev.ts",
"build": "deno run -A dev.ts build",
"preview": "deno run -A main.ts",
"update": "deno run -A -r https://fresh.deno.dev/update ."
},
"lint": { "rules": { "tags": ["fresh", "recommended"] } },
"exclude": ["**/_fresh/*"],
"imports": {
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}

この状態で app-a ディレクトリから、deno task start すると、以下のエラーが発生する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Error: Build failed with 1 error:
components/Button.tsx:2:27: ERROR: [plugin: deno-resolver] specifier was a bare specifier, but was not remapped to anything by importMap.
at failureErrorWithLog (https://deno.land/x/esbuild@v0.20.2/mod.js:1626:15)
at https://deno.land/x/esbuild@v0.20.2/mod.js:1034:25
at runOnEndCallbacks (https://deno.land/x/esbuild@v0.20.2/mod.js:1461:45)
at buildResponseToResult (https://deno.land/x/esbuild@v0.20.2/mod.js:1032:7)
at https://deno.land/x/esbuild@v0.20.2/mod.js:1061:16
at responseCallbacks.<computed> (https://deno.land/x/esbuild@v0.20.2/mod.js:679:9)
at handleIncomingPacket (https://deno.land/x/esbuild@v0.20.2/mod.js:739:9)
at readFromStdout (https://deno.land/x/esbuild@v0.20.2/mod.js:655:7)
at https://deno.land/x/esbuild@v0.20.2/mod.js:1974:11
at eventLoopTick (ext:core/01_core.js:168:7) {
errors: [Getter/Setter],
warnings: [Getter/Setter]
}

これに対応するには、app-a/deno.json に以下のような記述を追加する。

1
2
3
4
5
6
7
8
{
"imports": {
"preact": "https://esm.sh/preact@10.19.6",
"preact/": "https://esm.sh/preact@10.19.6/",
"@preact/signals": "https://esm.sh/*@preact/signals@1.2.2",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1",
}
}

これで、エラーが解消される。
確認してみると、islands で参照しているようなモジュールは、deno.json に記述の必要があった。

しかし、こうなるとimportsを上書きするわけでもないのに、importsに書く必要がある。
islands で最近はHonoRPCをよく使うが、これも同様に記述が必要になる。
というわけで、workspace の導入は、Freshにはまだよくなさそうである。
Issueを出してみたので、経過は見守りたい。

暫定対応

仕方ないので、app-aapp-b から share を参照する際は、相対パスで指定することにした。

1
2
3
4
5
{
"imports": {
"share": "../share/lib.ts"
}
}

また、deno deploy 展開用のgithub actionは、以下のように記述する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
name: Deploy-App-A
on:
push:
branches: main
pull_request:
branches: main

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read

steps:
- name: Clone repository
uses: actions/checkout@v4

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

- name: Build step
run: "cd app-a && deno task build"

- name: Upload to Deno Deploy
uses: denoland/deployctl@v1
with:
project: "hogehoge"
entrypoint: "app-a/main.ts"
root: "./"

これで、共通部分のモジュールを参照できる。
(app-bも同様にする)


というわけで、暫定対応で乗り切ることにした。
暫定対応といいつつ、何も解決してないのではという感はある。
fresh.gen.ts のように、islands 用のmoduleのload用のファイルは自動作成が望ましいように考えられる。

では。