Color mode

3つの Root

外部 Vault や monorepo 構成を扱う場合に重要なのが、

  • appRoot
  • configRoot
  • contentRoot

の違いです。

Diagram source
text
flowchart TD
    App["appRoot<br/>Site Application"]
    Config["configRoot<br/>Config の場所"]
    Content["contentRoot<br/>Content / Vault の場所"]
 
    App -->|"既定"| Config
    App -->|"content.directory を解決"| Content
名前 何を表す? 既定値 / 基準
appRoot HonoX / Vite Site の root Vite root
configRoot riebeckite.config.* を探す場所 appRoot
contentRoot 実際にコンテンツを読む場所 path.resolve(appRoot, content.directory)

この3つは別の役割を持ちます。

appRoot

appRoot は Site Application の基準となるディレクトリです。

たとえば、

text
site/
├─ app/
├─ public/
├─ package.json
├─ vite.config.ts
└─ riebeckite.config.ts

なら通常、

text
appRoot = site/

です。

appRoot は、

  • app/
  • public/
  • route
  • generated styles
  • Build 設定

など Site Application の基準になります。

configRoot

configRoot は、

text
riebeckite.config.ts
riebeckite.config.js
riebeckite.config.mjs

を探す基準です。

通常は appRoot と同じです。

text
appRoot
   └─ riebeckite.config.ts

特殊な repository 構成で config を別の場所へ置く場合のみ変更します。

configRoot を変更しても content.directory の基準は変わらない点に注意してください。

contentRoot

contentRoot は、実際に Markdown や asset を読み込む場所です。

相対 content.directory は常に appRoot を基準に解決されます。

ts
content: {
  directory: "../vault",
}

なら、

text
contentRoot
  = path.resolve(appRoot, "../vault")

となります。

Diagram source
text
flowchart LR
    App["appRoot<br/>workspace/site"]
    Directory["content.directory<br/>../vault"]
    Root["contentRoot<br/>workspace/vault"]
 
    App --> Directory
    Directory --> Root

process.cwd() を基準にするわけではありません。

そのため CLI を別の directory から実行しても、同じ Site Application を解決できれば同じ Vault を参照できます。

外部 Vault を使う

Obsidian Vault を Site と独立して管理したい場合は、Site の外へ置く構成を推奨します。

たとえば、

text
workspace/
├─ site/
│  ├─ package.json
│  ├─ vite.config.ts
│  ├─ riebeckite.config.ts
│  ├─ app/
│  └─ public/
│
└─ vault/
   ├─ index.md
   ├─ notes/
   ├─ attachments/
   └─ media/

という構成です。

Diagram source
text
flowchart LR
    Site["site/<br/>HonoX / Vite Application"]
    Config["riebeckite.config.ts"]
    Vault["vault/<br/>Obsidian Content"]
 
    Site --> Config
    Config -->|"content.directory = ../vault"| Vault

Site と Vault の役割が明確に分離されます。

text
site/
  → Application
 
vault/
  → Source Content

Vault を Vite application root にする必要はありません。

外部 Vault の設定例

ts
// site/riebeckite.config.ts
 
import { defineConfig } from "@riebeckite/core";
import { attachment } from "@riebeckite/plugin-attachment";
import { media } from "@riebeckite/plugin-media";
import { obsidianMarkdown } from "@riebeckite/plugin-obsidian-markdown";
 
export default defineConfig({
  site: {
    title: "My notes",
  },
 
  content: {
    directory: "../vault",
    exclude: [
      ".obsidian/**",
      "Templates/**",
    ],
  },
 
  plugins: [
    obsidianMarkdown(),
    media(),
    attachment(),
  ],
});

この場合、

text
appRoot
  = workspace/site
 
content.directory
  = ../vault
 
contentRoot
  = workspace/vault

となります。

絶対パスを指定することもできます。

ts
content: {
  directory: "C:/Users/example/Documents/vault",
}

ただし絶対パスは開発 PC や CI で場所が変わると使えなくなるため、通常は Site からの相対パスを推奨します。

process.cwd() に依存しない

Content directory を次のように組み立てることは避けてください。

ts
directory: path.resolve(
  process.cwd(),
  "../vault",
)

CLI をどこから実行したかによって結果が変化するためです。

また、

text
appRoot = Vault

とする必要もありません。

Vault は source data、appRoot は Site Application です。

Diagram source
text
flowchart LR
    Vault["Vault<br/>Source Data"]
    Site["Site<br/>Application"]
    Build["Riebeckite"]
 
    Vault --> Build
    Site --> Build
 
    Build --> Output["Generated Site"]

この境界を維持してください。

Application から ContentManager を使う

通常、HonoX Integration が contentRoot を自動的に解決します。解決済みの値は Framework 所有の module として公開されるため、Site が riebeckite.config.ts を読み直す必要はありません。

ts
import { config } from "virtual:riebeckite/config";
import { content } from "virtual:riebeckite/content";

config.content.directory は絶対パスで、content はそれに結びついた ContentManager です。そのため、別の基準からもう一度 path.resolve() しないでください。この module は riebeckiteVite() が解決します。Vite の外で動く script(tsx で起動する Node script など)は @riebeckite/honox/runtime の resolveHonoxConfig で同じ値を解決できます。

ts
import { fileURLToPath } from "node:url";
import { resolveConfigModule } from "@riebeckite/core";
import { resolveHonoxConfig } from "@riebeckite/honox/runtime";
import * as rawConfigModule from "../riebeckite.config";
 
const appRoot = fileURLToPath(new URL("../", import.meta.url));
export const config = resolveHonoxConfig(
  resolveConfigModule(rawConfigModule),
  appRoot,
);
Diagram source
text
flowchart LR
    Relative["../vault"]
    Resolve["appRoot から一度だけ resolve"]
    Absolute["C:/.../vault"]
    Manager["ContentManager"]
 
    Relative --> Resolve
    Resolve --> Absolute
    Absolute --> Manager

Config を Site の外へ置く

通常、

text
appRoot
  = configRoot

ですが、意図的に riebeckite.config.ts を別の directory に置くこともできます。

その場合は riebeckiteVite() に configRoot を指定します。

ただし、

text
appRoot
  → Site Application
 
configRoot
  → Config
 
contentRoot
  → Content / Vault

という役割は変わりません。

特に appRoot を Vault 側へ変更しないでください。

相対 content.directory は、configRoot ではなく引き続き appRoot を基準に指定します。

History

1 changesCollapseExpand
1 + ---
2 + title: 3つの Root と外部 Vault
3 + sidebar:
4 + label: Root と外部 Vault
5 + order: 30
6 + ---
7 + # 3つの Root
8 +
9 + 外部 Vault や monorepo 構成を扱う場合に重要なのが、
10 +
11 + - `appRoot`
12 + - `configRoot`
13 + - `contentRoot`
14 +
15 + の違いです。
16 +
17 + ```mermaid id="w3x2dv"
18 + flowchart TD
19 + App["appRoot<br/>Site Application"]
20 + Config["configRoot<br/>Config の場所"]
21 + Content["contentRoot<br/>Content / Vault の場所"]
22 +
23 + App -->|"既定"| Config
24 + App -->|"content.directory を解決"| Content
25 + ```
26 +
27 + | 名前 | 何を表す? | 既定値 / 基準 |
28 + | --- | --- | --- |
29 + | `appRoot` | HonoX / Vite Site の root | Vite `root` |
30 + | `configRoot` | `riebeckite.config.*` を探す場所 | `appRoot` |
31 + | `contentRoot` | 実際にコンテンツを読む場所 | `path.resolve(appRoot, content.directory)` |
32 +
33 + この3つは別の役割を持ちます。
34 +
35 +
36 + ## appRoot
37 +
38 + `appRoot` は **Site Application の基準となるディレクトリ**です。
39 +
40 + たとえば、
41 +
42 + ```text id="xkjg5v"
43 + site/
44 + ├─ app/
45 + ├─ public/
46 + ├─ package.json
47 + ├─ vite.config.ts
48 + └─ riebeckite.config.ts
49 + ```
50 +
51 + なら通常、
52 +
53 + ```text id="2hwbbd"
54 + appRoot = site/
55 + ```
56 +
57 + です。
58 +
59 + `appRoot` は、
60 +
61 + - `app/`
62 + - `public/`
63 + - route
64 + - generated styles
65 + - Build 設定
66 +
67 + など Site Application の基準になります。
68 +
69 +
70 + ## configRoot
71 +
72 + `configRoot` は、
73 +
74 + ```text id="53pg8g"
75 + riebeckite.config.ts
76 + riebeckite.config.js
77 + riebeckite.config.mjs
78 + ```
79 +
80 + を探す基準です。
81 +
82 + 通常は `appRoot` と同じです。
83 +
84 + ```text id="7uqfyx"
85 + appRoot
86 + └─ riebeckite.config.ts
87 + ```
88 +
89 + 特殊な repository 構成で config を別の場所へ置く場合のみ変更します。
90 +
91 + **`configRoot` を変更しても `content.directory` の基準は変わらない**点に注意してください。
92 +
93 +
94 + ## contentRoot
95 +
96 + `contentRoot` は、実際に Markdown や asset を読み込む場所です。
97 +
98 + 相対 `content.directory` は常に `appRoot` を基準に解決されます。
99 +
100 + ```ts id="jgnfqm"
101 + content: {
102 + directory: "../vault",
103 + }
104 + ```
105 +
106 + なら、
107 +
108 + ```text id="y6zaw5"
109 + contentRoot
110 + = path.resolve(appRoot, "../vault")
111 + ```
112 +
113 + となります。
114 +
115 + ```mermaid id="uupc5x"
116 + flowchart LR
117 + App["appRoot<br/>workspace/site"]
118 + Directory["content.directory<br/>../vault"]
119 + Root["contentRoot<br/>workspace/vault"]
120 +
121 + App --> Directory
122 + Directory --> Root
123 + ```
124 +
125 + `process.cwd()` を基準にするわけではありません。
126 +
127 + そのため CLI を別の directory から実行しても、同じ Site Application を解決できれば同じ Vault を参照できます。
128 +
129 +
130 + ## 外部 Vault を使う
131 +
132 + Obsidian Vault を Site と独立して管理したい場合は、Site の外へ置く構成を推奨します。
133 +
134 + たとえば、
135 +
136 + ```text id="bgmthg"
137 + workspace/
138 + ├─ site/
139 + │ ├─ package.json
140 + │ ├─ vite.config.ts
141 + │ ├─ riebeckite.config.ts
142 + │ ├─ app/
143 + │ └─ public/
144 + │
145 + └─ vault/
146 + ├─ index.md
147 + ├─ notes/
148 + ├─ attachments/
149 + └─ media/
150 + ```
151 +
152 + という構成です。
153 +
154 + ```mermaid id="63njzu"
155 + flowchart LR
156 + Site["site/<br/>HonoX / Vite Application"]
157 + Config["riebeckite.config.ts"]
158 + Vault["vault/<br/>Obsidian Content"]
159 +
160 + Site --> Config
161 + Config -->|"content.directory = ../vault"| Vault
162 + ```
163 +
164 + Site と Vault の役割が明確に分離されます。
165 +
166 + ```text id="wx10hc"
167 + site/
168 + → Application
169 +
170 + vault/
171 + → Source Content
172 + ```
173 +
174 + Vault を Vite application root にする必要はありません。
175 +
176 +
177 + ## 外部 Vault の設定例
178 +
179 + ```ts id="p5vg19"
180 + // site/riebeckite.config.ts
181 +
182 + import { defineConfig } from "@riebeckite/core";
183 + import { attachment } from "@riebeckite/plugin-attachment";
184 + import { media } from "@riebeckite/plugin-media";
185 + import { obsidianMarkdown } from "@riebeckite/plugin-obsidian-markdown";
186 +
187 + export default defineConfig({
188 + site: {
189 + title: "My notes",
190 + },
191 +
192 + content: {
193 + directory: "../vault",
194 + exclude: [
195 + ".obsidian/**",
196 + "Templates/**",
197 + ],
198 + },
199 +
200 + plugins: [
201 + obsidianMarkdown(),
202 + media(),
203 + attachment(),
204 + ],
205 + });
206 + ```
207 +
208 + この場合、
209 +
210 + ```text id="9w7l08"
211 + appRoot
212 + = workspace/site
213 +
214 + content.directory
215 + = ../vault
216 +
217 + contentRoot
218 + = workspace/vault
219 + ```
220 +
221 + となります。
222 +
223 + 絶対パスを指定することもできます。
224 +
225 + ```ts id="vmohm9"
226 + content: {
227 + directory: "C:/Users/example/Documents/vault",
228 + }
229 + ```
230 +
231 + ただし絶対パスは開発 PC や CI で場所が変わると使えなくなるため、通常は Site からの相対パスを推奨します。
232 +
233 +
234 + ## `process.cwd()` に依存しない
235 +
236 + Content directory を次のように組み立てることは避けてください。
237 +
238 + ```ts id="i3cfla"
239 + directory: path.resolve(
240 + process.cwd(),
241 + "../vault",
242 + )
243 + ```
244 +
245 + CLI をどこから実行したかによって結果が変化するためです。
246 +
247 + また、
248 +
249 + ```text id="p2j2rb"
250 + appRoot = Vault
251 + ```
252 +
253 + とする必要もありません。
254 +
255 + Vault は **source data**、`appRoot` は **Site Application** です。
256 +
257 + ```mermaid id="xzz84j"
258 + flowchart LR
259 + Vault["Vault<br/>Source Data"]
260 + Site["Site<br/>Application"]
261 + Build["Riebeckite"]
262 +
263 + Vault --> Build
264 + Site --> Build
265 +
266 + Build --> Output["Generated Site"]
267 + ```
268 +
269 + この境界を維持してください。
270 +
271 +
272 + ## Application から ContentManager を使う
273 +
274 + 通常、HonoX Integration が `contentRoot` を自動的に解決します。解決済みの値は Framework 所有の module として公開されるため、Site が `riebeckite.config.ts` を読み直す必要はありません。
275 +
276 + ```ts id="veou0j"
277 + import { config } from "virtual:riebeckite/config";
278 + import { content } from "virtual:riebeckite/content";
279 + ```
280 +
281 + `config.content.directory` は絶対パスで、`content` はそれに結びついた `ContentManager` です。そのため、別の基準からもう一度 `path.resolve()` しないでください。この module は `riebeckiteVite()` が解決します。Vite の外で動く script(`tsx` で起動する Node script など)は `@riebeckite/honox/runtime` の `resolveHonoxConfig` で同じ値を解決できます。
282 +
283 + ```ts id="9pr6g1"
284 + import { fileURLToPath } from "node:url";
285 + import { resolveConfigModule } from "@riebeckite/core";
286 + import { resolveHonoxConfig } from "@riebeckite/honox/runtime";
287 + import * as rawConfigModule from "../riebeckite.config";
288 +
289 + const appRoot = fileURLToPath(new URL("../", import.meta.url));
290 + export const config = resolveHonoxConfig(
291 + resolveConfigModule(rawConfigModule),
292 + appRoot,
293 + );
294 + ```
295 +
296 + ```mermaid id="54gq7n"
297 + flowchart LR
298 + Relative["../vault"]
299 + Resolve["appRoot から一度だけ resolve"]
300 + Absolute["C:/.../vault"]
301 + Manager["ContentManager"]
302 +
303 + Relative --> Resolve
304 + Resolve --> Absolute
305 + Absolute --> Manager
306 + ```
307 +
308 + ## Config を Site の外へ置く
309 +
310 + 通常、
311 +
312 + ```text id="4p7m8h"
313 + appRoot
314 + = configRoot
315 + ```
316 +
317 + ですが、意図的に `riebeckite.config.ts` を別の directory に置くこともできます。
318 +
319 + その場合は `riebeckiteVite()` に `configRoot` を指定します。
320 +
321 + ただし、
322 +
323 + ```text id="8y2qf9"
324 + appRoot
325 + → Site Application
326 +
327 + configRoot
328 + → Config
329 +
330 + contentRoot
331 + → Content / Vault
332 + ```
333 +
334 + という役割は変わりません。
335 +
336 + 特に `appRoot` を Vault 側へ変更しないでください。
337 +
338 + 相対 `content.directory` は、`configRoot` ではなく引き続き **`appRoot` を基準**に指定します。
339 +