Slide 1

Slide 1 text

バックエンドNode.js
 × フロントエンドDeno
 で開発して得られた知見
 ayame113
 1

Slide 2

Slide 2 text

自己紹介
 2

Slide 3

Slide 3 text

自己紹介
 ● ayame113
 ● 所属:株式会社ヴァル研究所
 ○ 「駅すぱあと」乗換案内の会社です 
 
 ● 新卒1年目です!
 ● 業務ではNode.jsでバックエンドを書いてます
 ● DenoにOSSコントリビュートしてました
 3

Slide 4

Slide 4 text

Node.js × Deno構成で得られた知見
 4

Slide 5

Slide 5 text

つくっていたもの
 ● 単純な予約ツール
 ● バックエンド:Node.js / Firebase / Cloud Run
 ● フロントエンド:Deno Fresh
 5

Slide 6

Slide 6 text

なぜこの構成にした?
 ● Denoが使いたかった
 ● 最初は全部Denoで書くつもりだった
 ● 途中でDenoで使えないnpmライブラリに遭遇し、
 バックエンドのみNode.jsに移行
 ○ 当時はFirebase Authenticationが動かなかった(1年くらい前) 
 6

Slide 7

Slide 7 text

今日話したいこと
 1. Node.jsとDenoを共存させるための設定
 2. よかったポイント、つらみポイント
 
 こういう人に聞いてほしい: 
 Node.jsを使っている人で、これから徐々にDenoを導入していきたい人 
 7

Slide 8

Slide 8 text

Node.jsとDenoを
 1プロジェクトで組み合わせるには?
 8

Slide 9

Slide 9 text

ディレクトリ構成
 .
 ├── backend バックエンド(Node.js)
 │ ├── src
 │ ├── package.json
 │ └── tsconfig.json
 └── frontend フロントエンド(Deno)
 ├── src
 └── deno.json
 9

Slide 10

Slide 10 text

Node.jsとDenoを共存させる方法
 1. エディタの設定
 2. フロントエンドとバックエンドで型を共有する
 10

Slide 11

Slide 11 text

①エディタの設定
 ● 前提:何も設定しないと、エディタは全部Node.jsのコードだと思って解釈する
 ○ Denoのコードだと教えてあげる設定が必要 
 11

Slide 12

Slide 12 text

①エディタの設定
 ● .vscode/settings.json
 ○ deno.enablePathsを使う 
 
 
 
 
 
 
 ○ この設定で、frontendディレクトリ内だけDenoが有効になる 
 // .vscode/settings.json { "deno.enablePaths": [ "./frontend" ], } 12

Slide 13

Slide 13 text

②フロントエンドとバックエンドで型を共有する
 ● 難しい
 ● 同じ言語とはいえ、Node.jsとDenoでは、モジュール解決や使える変数などが異なる
 ○ URL import
 ○ JSR
 ○ グローバル変数
 ■ globalThis.Deno → Denoだけで使える 
 ■ globalThis.Buffer → Node.jsだけで使える (Denoで使うには--unstable-node-globals) 
 13

Slide 14

Slide 14 text

②フロントエンドとバックエンドで型を共用する
 ● やり方は2パターン考えられる
 14 Deno
 Node.js
 Node.js
 Deno
 共通
 モジュール
 import
 import
 import


Slide 15

Slide 15 text

②フロントエンドとバックエンドで型を共用する
 ● やり方は2パターン考えられる
 15 Deno
 Node.js
 Node.js
 Deno
 共通
 モジュール
 import
 import
 import
 Deno側からNode.js側を 
 直接importする
 
 DenoのNode.js互換モードなら、 
 Node.jsのコードを解釈できる! 
 HonoのRPCモードみ たいな感じ


Slide 16

Slide 16 text

②フロントエンドとバックエンドで型を共用する
 ● やり方は2パターン考えられる
 16 Deno
 Node.js
 Node.js
 Deno
 共通
 モジュール
 import
 import
 import
 共通モジュールを作って、 
 それぞれからimportする 
 共通モジュールは、Node.jsと Denoの両方から実行できる ようにしておく


Slide 17

Slide 17 text

②フロントエンドとバックエンドで型を共用する
 ● どっちのパターンにする?
 ● Deno側からNode.js側をimportするのは色々大変
 ○ DenoにはNode.js互換モードがあるとはいえ、まだ完全な互換ではない 
 ○ 先人
 ■ Denoでnpm用フレームワークを含めたモノレポを作るのは渋い 
 ○ git dependencyやpeer dependency、CJSの解決周りで動かないことがある 
 ■ 1年後くらいには動くようになってそうだが、、、 
 →共通モジュールを使う方を選択!
 17

Slide 18

Slide 18 text

②フロントエンドとバックエンドで型を共用する
 ● せっかくなので(?) GraphQLも使う
 18 Node.js
 Deno
 共通
 モジュール
 import
 import
 GraphQL


Slide 19

Slide 19 text

ディレクトリ構成
 .
 ├── backend バックエンド(Node.js)
 │ ├── src
 │ ├── package.json
 │ └── tsconfig.json
 └── frontend フロントエンド(Deno)
 │ ├── src
 │ └── deno.json
 └── shared バックエンド/フロントエンド共通モジュール
 ├── schema.ts
 └── schema.graphql
 19

Slide 20

Slide 20 text

Node.js & Deno どちらでも実行できるモジュール
 ● zodのスキーマをバックエンドとフロントエンドで共有したい
 ● このコード、Node.jsからもimportできるし、Denoからもimportできるようにするに は?
 20 import { z } from "zod"; export const ParameterSchema = z.object({ page: z.number(), limit: z.number(), });

Slide 21

Slide 21 text

Node.js & Deno どちらでも実行できるモジュール
 21 import { z } from "zod"; export const ParameterSchema = z.object({ page: z.number(), limit: z.number(), }); { "dependencencies": { "zod": "^3.24.2" } } { "imports": { "zod": "npm:zod@^3.24.2" } } Node.js - package.json
 Deno - deno.json


Slide 22

Slide 22 text

Node.js & Deno どちらでも実行できるモジュール
 ● TypeScriptの設定も合わせておく
 ○ allowImportingTsExtensionsオプションを設定すると、 
 Node.js側でも拡張子.tsでimportできるようになる 
 22 // tsconfig.json { "compilerOptions": { "allowImportingTsExtensions": true, } }

Slide 23

Slide 23 text

Node.jsとDenoの併用、
 つらみ&うれしかったこと
 23

Slide 24

Slide 24 text

つらみ&うれしかったこと
 ● つらみ
 ○ 一部のnpmライブラリはまだDenoで動かない 
 ○ node_modulesから逃れられない 
 ● うれしかったこと
 ○ フォーマッター、リンターはDenoに組み込み 
 ○ 両者のいいとこ取りできる 
 ○ deno deployのデプロイが爆速 
 24

Slide 25

Slide 25 text

つらみ① - 一部のnpmライブラリはまだDenoで動かない
 うまく動かなかった事例
 ● git dependencyは非対応
 ○ ライブラリの依存関係を辿っていった先に1つでもgit dependencyがあると、型エラーが起きる (vscode上)
 ● peerDependency周りでたまにエラー出る
 ○ インストールのタイミングによってエラーが出たり出なかったりした 
 ● CommonJSの型定義が解決できないことがある(?)
 ○ if文の中でmodule.exportしているとany型になる? 
 ● npmのCLIの設定ファイルをTSで書く場合
 ○ 設定ファイル内からjsrライブラリをimportできない? 
 25

Slide 26

Slide 26 text

つらみ① - 一部のnpmライブラリはまだDenoで動かない
 うまく動かなかった事例
 ● git dependencyは非対応
 ○ ライブラリの依存関係を辿っていった先に1つでもgit dependencyがあると、型エラーが起きる (vscode上)
 ● peerDependency周りでたまにエラー出る
 ○ インストールのタイミングによってエラーが出たり出なかったりした 
 ● CommonJSの型定義が解決できないことがある(?)
 ○ if文の中でmodule.exportしているとany型になる? 
 ● npmのCLIの設定ファイルをTSで書く場合
 ○ 設定ファイル内からjsrライブラリをimportできない? 
 26 エラーが出たら
 とりあえずesm.shを使っておけば解決しました


Slide 27

Slide 27 text

つらみ② - node_modulesからは逃れられない
 ● ライブラリによっては"nodeModulesDir": "auto"を指定するように指示される
 ○ 結局Deno側でもnode_modulesができてしまう 
 ● Node.js側とDeno側、それぞれにnode_modulesができる
 27

Slide 28

Slide 28 text

うれしかったこと① - ツール周り
 ● フォーマッターやリンターなどはDeno組み込みの ものを使える
 ○ deno fmt
 ○ deno lint
 ○ Node.js側でも使える! 
 ● prettierやeslintの設定不要!
 28

Slide 29

Slide 29 text

うれしかったこと② - Node.jsとDenoのいいとこ取り
 ● 簡単なスクリプトはDenoで書く
 ● CLIツールはDenoで動かせばセキュリティ周り安心
 ○ –allow-read
 ○ –allow-env
 ● Denoで動かないものはNode.jsで動かす
 29

Slide 30

Slide 30 text

うれしかったこと③ - deno deployのデプロイが爆速
 ● Node.jsバックエンドをCloud Runにデプロイすると2〜3分かかる
 ● deno deployにデプロイすると10秒以下
 ○ 開発体験最高!
 30

Slide 31

Slide 31 text

まとめ
 31

Slide 32

Slide 32 text

まとめ
 ● Node.jsとDenoは1プロジェクト内で共存できる?→できる!
 ○ deno.enablePaths
 ○ フロントエンド/バックエンドで型を共有するには一手間かける必要あり 
 ● Node.jsプロジェクトにも徐々にDenoを導入できる
 ○ Denoの辛いところ→Node.js互換性があと一歩惜しい 
 ○ Denoのいいところ→ツール周り、セキュリティ、デプロイ爆速 
 ○ Node.jsとDenoでいいとこ取りしていきましょう! 
 32

Slide 33

Slide 33 text

33