Claude CodeにDeno 2のコードを正しく書かせる──CommonJS混入・旧URL import・外部serve()関数をCLAUDE.mdで封じる

# Claude CodeにDeno 2のコードを正しく書かせる──CommonJS混入・旧URL import・外部serve()関数をCLAUDE.mdで封じる

## はじめに

Claude CodeにDeno 2のコードを生成させると`require()`が出てきたり、`deno.land/x`の古いURLが使われたりする。Deno 2は2024年10月にNode.js互換を大幅強化したため「どちらのパターンでも動く」環境になり、Node.jsスタイルが混入しやすい。BunやPythonとは異なるDeno 2固有の問題だ。CLAUDE.mdでルールを定義すれば最初からDeno 2ネイティブなコードが生成される。

---

## Claude CodeがDeno 2で生成しやすいパターンを正す

### CommonJS `require()` → ESM + `node:` prefix

Deno 2はCJSも一応動作するが、TypeScriptの型解決とモジュール解決で問題が生じる。`node:` prefixなしのNode.js組み込みモジュールimportは型解決で失敗しやすい。

```typescript
// ❌ CommonJSスタイル(型解決で問題が生じる)
const fs = require('fs');
const data = fs.readFileSync('data.json', 'utf8');
module.exports = { data };
```

```typescript
// ✅ ESM + node: prefix でNode.js互換モジュールを明示
import { readFile } from "node:fs/promises";
import { join } from "node:path";

const data = await readFile(join('data.json'), 'utf8');
export { data };
```

外部パッケージの追加は`deno add npm:パッケージ名`または`deno add jsr:@スコープ/パッケージ名`を使う。`npm install`は不要だ。

### `deno.land/x` URL import → `jsr:` specifier

旧形式のURL importが生成されるケース。Deno標準ライブラリはJSRに移行済みで、`deno.land/x`の旧URLはバージョン管理・依存解決で問題が出る。

```typescript
// ❌ Deno 1.x時代の形式(各ファイルにバージョンが散在)
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
```

```typescript
// ✅ deno.json の imports で一元管理 + jsr: specifier
// deno.json: { "imports": { "@std/assert": "jsr:@std/assert@^1.0.0" } }
// → deno add jsr:@std/assert で自動追加される
import { assertEquals } from "@std/assert";
import { Hono } from "hono"; // npm:hono も同様にdeno.jsonで管理
```

### 外部 `serve()` 関数 → ビルトイン `Deno.serve()`

旧来の外部import版`serve()`関数が生成されるケース。Deno 1.35以降、`Deno.serve()`がビルトインAPIとして提供されており外部importは不要だ。

```typescript
// ❌ deno.land/std の外部serve()(旧形式)
import { serve } from "https://deno.land/std/http/server.ts";
serve((req) => new Response("Hello"));
```

```typescript
// ✅ ビルトインDeno.serve()(外部import不要)
Deno.serve({ port: 8000, hostname: "localhost" }, async (req) => {
const body = await req.text();
return new Response(`Received: ${body}`);
});
```

---

## CLAUDE.mdとPostToolUseでDeno 2パターンを自動担保する

```markdown
## Deno 2プロジェクトルール

### モジュールとimport
- importは必ずESM形式(require()禁止・module.exports禁止)
- Node.js組み込みモジュールは `node:` prefix を付ける(node:fs/promises, node:path)
- 外部パッケージのspecifier: `jsr:` > `npm:` > HTTPS URL の優先順位
- `https://deno.land/x/...` 形式のURL importは使わない
- import URLはdeno.jsonのimportsフィールドで一元管理する

### パッケージ管理
- パッケージ追加: `deno add npm:パッケージ名` または `deno add jsr:@スコープ/パッケージ名`
- `npm install` コマンド禁止

### HTTPサーバー
- `Deno.serve()` ビルトインAPIを使う(外部importのserve()関数禁止)
- 形式: `Deno.serve({ port: 8000, hostname: "localhost" }, handler)`
```

`.ts`ファイル編集後に`deno check`で型チェックを自動実行する。`tsc`のように外部設定が不要で、Deno固有の型も正しく検証できる。

```json
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "deno check 2>&1 | head -20" }]
}]
}
}
```

---

## EM視点──Deno 2採用でClaude Codeを活用する戦略

Deno 2のNode.js互換強化は採用の障壁を下げたが、同時にClaude Codeが「どちらでも動く」コードを生成しやすくなった。CLAUDE.mdで「Denoパターン」を明示的に定義しないとコードベースにNode.jsスタイルが混入する。既存コードは`require(`がないか・`deno.land/x`のURL importがないか・外部`serve()`がないかの3点をgrepで確認するとよい。deno.jsonのimportsフィールドでパッケージを一元管理すれば、バージョン管理の混乱も防げる。

---

## まとめ

Claude CodeがDeno 2で踏む地雷はCommonJS混入・`deno.land/x` URL import・外部serve()だ。CLAUDE.mdに本記事のテンプレートを追記して今すぐリポジトリにコミットしてほしい。`deno check`のPostToolUseフックを合わせて設定すれば、型定義ミスもその場で自動修正される。

コメント

タイトルとURLをコピーしました