[[📒Articles]] > [[📒2021 Articles]]
![[2021-09-20.jpg|cover-picture]]
[[Obsidianプラグイン]]を開発しているとき、コードベースに変更があったら自動で[[Obsidian]]をリロードする仕組みを整えました。
> [!caution]
> 2022-02-19追記: 記事執筆時は[[Rollup]]でしたが、最新では[[esbuild]]が使われています。本記事の流れに大きな支障はありませんが、置き換えてお読みください。
## はじめに
### 経緯
[[Obsidianプラグイン]]の開発では[[TypeScript]]コードを変更すると、[[Rollup]]によって自動で[[JavaScript]]に[[トランスパイル]]されます。しかし、以下の作業は自動で行われません。
1. [[Obsidian]]のプラグインリロード
2. [[JavaScript]]、[[CSS]]、[[JSON]]ファイルを[[#プラグインディレクトリ]]に移動
1は[[Hot Reload (Obsidian)|Hot Reload]]プラグインを使うことで実現できます。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
GitHub - pjeby/hot-reload: Automatically reload Obsidian plugins in development when their files are changed
</div>
<div class="link-card-v2-content">
Automatically reload Obsidian plugins in development when their files are changed - pjeby/hot-reload
</div>
<img class="link-card-v2-image" src="https://repository-images.githubusercontent.com/334343202/9f7fa280-62a5-11eb-817b-ae184bd5b1d5" />
<a href="https://github.com/pjeby/hot-reload"></a>
</div>
2は[[#プラグインディレクトリ]]配下で開発すれば必要ありません。ただ、[[Obsidian Sync]]を使っている場合は`node_modules`ディレクトリも含めて多量の無駄データが同期されてしまいます。[[Obsidian Sync]]の設定で、特定プラグインの特定ディレクトリを同期しない設定はありませんでした。
回避策として、必要な成果物だけ[[シンボリックリンク]]でリンクする方法があります。ところが、[[シンボリックリンク]]を使うと1の[[Hot Reload (Obsidian)|Hot Reload]]プラグインが動作しません。[[Obsidian]]のファイル検知機構が、少なくとも[[Windows 10]]と[[PowerShell]]の環境では動作しないようです。
本記事では、それらをまとめて解決する手法を紹介します。
### 対象読者
本記事は[[Obsidianプラグイン]]を開発したことがある読者を想定しています。[[Obsidianプラグイン]]の作り方から知りたい方は、[[📕Obsidianプラグイン開発チュートリアル]] をご覧下さい。
## 概要
今回作成した仕組みの概要図です。
![[obsidian-hotreload.png]]
- ⚫黒は既存の仕組み
- 🔵青は[[Hot Reload (Obsidian)|Hot Reload]]プラグインの仕組み
- 🟢緑は今回自作した仕組み
また、本文中に登場する変数[^1]、用語を以下のように定義します。
[^1]: ユーザーの環境によって異なる値が入る部分. `<`と`>`で囲まれて表現される
### 変数
| 変数名 | 意味 |
| --------------- | ------------------------------ |
| `<vault>` | [[Obsidian]]の[[Vault]]パス |
| `<your-plugin>` | 開発中のプラグインディレクトリ名 |
### 用語
#### プラグインディレクトリ
- `<vault>/.obsidian/plugins`のこと
#### 開発中プラグインディレクトリ
- [[#プラグインディレクトリ]]配下にある開発中のプラグインディレクトリ
- 上の図では`<vault>/.obsidian/plugins/<your-plugin>`
#### プラグインリポジトリ
- [[Git]]管理されているリポジトリのディレクトリ
- 上の図では`your-plugin-repository`
#### コードベース
[[Obsidianプラグイン]]に必要なファイル群のこと。本記事では以下3ファイルを指す。
- `main.js`
- `styles.css`
- `manifest.json`
## [[#コードベース]]が変更されたらコピーする
図では緑の大きな矢印部分です。
![[Pasted image 20210920153452.png]]
[[#コードベース]]の監視に[[watchexec]]を使います。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
GitHub - watchexec/watchexec: Executes commands in response to file modifications
</div>
<div class="link-card-v2-content">
Executes commands in response to file modifications - watchexec/watchexec
</div>
<img class="link-card-v2-image" src="https://repository-images.githubusercontent.com/68546136/c9e9cc00-a6eb-11eb-9576-ad5891c0550f" />
<a href="https://github.com/watchexec/watchexec"></a>
</div>
[[#プラグインリポジトリ]]配下で以下のコマンドを実行します。
```console:powershell
watchexec --exts "js,json,css" `
cp main.js styles.css manifest.json `
<vault>/.obsidian/plugins/<your-plugin>
```
ファイルごとに3コマンド実行した方が無駄はありません。今回の場合は大した処理ではないため、複数コマンド管理する手間の方をコストとみなし、敢えて1コマンドにしています。
## [[#コードベース]]が変更されたらリロードする
図では右側の青い部分です。
![[Pasted image 20210920154040.png]]
まずは[[Hot Reload (Obsidian)|Hot Reload]]プラグインをインストールします。ただ、開発専用プラグインであるため[[Obsidian]]からはインストールできません。直接[[GitHub]]からソースコードを持ってきます。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
GitHub - pjeby/hot-reload: Automatically reload Obsidian plugins in development when their files are changed
</div>
<div class="link-card-v2-content">
Automatically reload Obsidian plugins in development when their files are changed - pjeby/hot-reload
</div>
<img class="link-card-v2-image" src="https://repository-images.githubusercontent.com/334343202/9f7fa280-62a5-11eb-817b-ae184bd5b1d5" />
<a href="https://github.com/pjeby/hot-reload"></a>
</div>
```ls:<vault>/.obsidian/plugins/hot-reload
.
├── main.js // GitHubからとってくる
└── manifest.json // GitHubからとってくる
```
開発中プラグインに対して[[ホットリロード]]を有効にするため、[[#開発中プラグインディレクトリ]]配下に空ファイル`.hotreload`を作ります。
最後に[[Obsidian]]の設定から[[Hot Reload (Obsidian)|Hot Reload]]プラグインを`enabled`にします。そのあと、[[#開発中プラグインディレクトリ]]のファイルを変更してみましょう。右上にトーストが表示されればOKです。
![[Pasted image 20210920154444.png]]
## 1コマンドで監視をONにする
[[Hot Reload (Obsidian)|Hot Reload]]は[[Obsidian]]を起動すると自動で監視を始めます。一方、開発時の[[Rollup]]と[[watchexec]]はコマンドで実行が必要です。2つのコマンドをそれぞれ実行でも問題ありませんが、シンプルにするため[[Task]]を使って1コマンドにします。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
GitHub - go-task/task: A task runner / simpler Make alternative written in Go
</div>
<div class="link-card-v2-content">
A task runner / simpler Make alternative written in Go - go-task/task
</div>
<img class="link-card-v2-image" src="https://opengraph.githubassets.com/921e52e538d7b6f35338ff9845f665fc26ce19c0778c20ae7bc6b829d3ff1079/go-task/task" />
<a href="https://github.com/go-task/task"></a>
</div>
図では左側、緑の部分です。
![[Pasted image 20210920155035.png]]
以下の`Taskfile.yml`を作成します。
```yaml:Taskfile.yml
version: "3"
tasks:
default:
- task: help
help:
silent: true
cmds:
- task -l
build:dev: npm run dev
watch: watchexec --no-vcs-ignore --exts "js,json,css" cp main.js styles.css manifest.json <vault>/.obsidian/plugins/obsidian-another-quick-switcher/
dev:
desc: Build and copy files when they are updated.
deps:
- build:dev
- watch
```
> [!add] #2022/09/11 追記
> [[watchexec]]のコマンドに`--no-vcs-ignore`オプションを追加しました。理由は [[📝watchexecでmain.jsの変更が検知されない]] をご覧ください。
`deps`に指定したタスクは[[並列]]に実行されるため、[[Rollup]][^2]と[[watchexec]]が同時に起動します。
[^2]: `Taskfile.yml`では[[npm]]になっているが `npm run dev`が[[Rollup]]を使ったコマンドになっている
## まとめ
[[Obsidianプラグイン]]の[[#コードベース]]に変更があったら、自動で[[Obsidian]]をリロードする仕組みを紹介しました。初回の仕込みは少々面倒ですが、それ以降は`task dev`コマンドだけで[[ホットリロード]]の恩恵に授かることができます。
![[obsidian-hotreload.png]]
特に[[CSS]]でスタイルの調整をするときは快適さが段違いです。開発速度だけでなくモチベーションアップにも繋がりますので是非試してみてください😊
### オマケ1
今回の対応を入れたリポジトリ、[[🦉Another Quick Switcher]]です。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">GitHub</span>
</div>
<div class="link-card-v2-title">
GitHub - tadashi-aikawa/obsidian-another-quick-switcher: This is an Obsidian plugin which is another choice of Quick switcher.
</div>
<div class="link-card-v2-content">
This is an Obsidian plugin which is another choice of Quick switcher. - tadashi-aikawa/obsidian-another-quick-sw ...
</div>
<img class="link-card-v2-image" src="https://opengraph.githubassets.com/057f28c95c481e64e73d5b94bd200def0d2d18a3469901c007fdc2e7f13904ed/tadashi-aikawa/obsidian-another-quick-switcher" />
<a href="https://github.com/tadashi-aikawa/obsidian-another-quick-switcher"></a>
</div>
### オマケ2
[[Task]]の`watch`機能を使えば、[[watchexec]]を使わずに本記事の内容を実現することも可能です。具体的には以下のような設定をします。
```yaml:Taskfile.yml
dev:
desc: Build and copy files when they are updated.
cmds:
- npm run build:dev
- cp main.js styles.css manifest.json $USERPROFILE/work/minerva/.obsidian/plugins/obsidian-another-quick-switcher/
sources:
- src/**/*.ts
- styles.css
- manifest.json
generates:
- main.js
- styles.css
- manifest.json
```
以下のコマンドでソースを監視しつつ、変更があったら[[Rollup]]のビルドとファイルのコピーが実行されます。
```console
task dev -w
```
しかし、この方法には2つのデメリットがあります。
- [[watchexec]]に比べて変更検知が遅い
- 1秒強かかる
- [[Rollup]]のビルドを毎回1から行うため少し遅い
- 1秒強かかる
本記事の方式に比べて、平均すると1~2秒余計に待たされるイメージです。特に[[CSS]]や[[JSON]]は顕著です。
たかが2秒程度と思うかもしれませんが、すぐ確認したい場合は思いの他フラストレーションが溜まります。どちらの方法を選ぶべきかは開発者が何を求めるかによっても変わるでしょう。