Color mode

プラグインの依存関係と Lifecycle

このページは プラグイン作成の詳細 の一部で、Plugin 同士の依存関係、Options の検証、Plugin Context、Lifecycle を扱います。

5. Plugin の依存関係

Plugin 同士に実際の依存関係がある場合は Capability Contract を使用します。

ts
definePlugin({
  name: "consumer",
 
  provides: [
    "example.output",
  ],
 
  requires: [
    "content.graph",
  ],
 
  optional: [
    "example.optional",
  ],
});

それぞれ、

Field 意味
provides この Plugin が提供する Capability
requires 必須の Capability
optional あれば利用する Capability

です。

Resolver は依存関係をもとに実行順を解決します。

Diagram source
text
flowchart LR
    Provider["Provider<br/>provides: content.graph"]
    Consumer["Consumer<br/>requires: content.graph"]
 
    Provider --> Consumer

次の状態は Configuration Error になります。

  • 必須 Capability がない
  • Provider が重複している
  • Dependency Cycle がある

order は依存解決前の基本順序です。

実際の依存関係を表現するために order を使わないでください。

6. Options を検証する

TypeScript の型だけでは Runtime Value を完全には保証できません。

必要な Plugin は validateOptions を実装します。

text
Options
   ↓
validateOptions
   ↓
Structured Issues
   ↓
riebeckite check

Validator は副作用を持たせません。

特に、

  • Filesystem Scan
  • Build
  • Cache Write
  • 外部状態の変更

を行わないでください。

問題は Structured Issue として返し、Config Validation からまとめて表示できるようにします。

7. Plugin Context

Plugin は Framework の Service を PluginContext から受け取ります。

基本的な Context は概念的に次のようになります。

ts
type PluginContext = {
  config?: ResolvedRiebeckiteConfig;
  contentIndex: Map<string, string>;
  diagnostics: Diagnostic[];
  cache: PluginCache;
  output: GeneratedOutputSink;
  logger: Logger;
  tracer: Tracer;
  contentSource?: ContentSource;
};

Hook によって、

text
slug
markdown
content
manifest
entries
location input

などが追加されます。

Plugin 内で Framework Service の Global Singleton を作るのではなく、Context から必要な Service を受け取ることを優先します。

8. Lifecycle

Framework Lifecycle には、

text
setup
buildStart
buildEnd
dispose

があります。

概念的には、

Diagram source
text
flowchart LR
    Setup["setup"]
    Start["buildStart"]
    Work["Build / Content Processing"]
    End["buildEnd"]
    Dispose["dispose"]
 
    Setup --> Start
    Start --> Work
    Work --> End
    End --> Dispose

という流れになります。

setup、buildStart、onConfigResolved、Content 処理、buildEnd は、1つの ContentManager につき一度だけ実行されます。buildEnd は Diagnostics の収集後に完成した Manifest を受け取る唯一の終端 Hook です。dispose は確保した Resource の解放に使用し、解決済み Plugin の逆順で実行されます。

Lifecycle の実行順は、解決済み Plugin Order に従います。

Hook で Error が発生した場合は、

  • Plugin 名
  • Hook 名
  • 元の Cause

が分かる形で上位へ伝播させてください。

9. Content Lifecycle

Content は複数の段階を通って処理されます。

Diagram source
text
flowchart TD
    Config["Config Resolved"]
    Loaded["Content Loaded"]
    Location["Public Location Resolved"]
    Parsed["Post Parsed"]
    Processed["Post Processed"]
    Graph["Content Graph"]
    Manifest["Manifest Created"]
 
    Config --> Location
    Location --> Loaded
    Loaded --> Parsed
    Parsed --> Processed
    Processed --> Graph
    Graph --> Manifest

全体の順序は setup → buildStart → onConfigResolved → Public Location 解決 → onContentLoaded → Markdown / HTML Pipeline → onPostParsed → onPostProcessed → extendContentGraph → onManifestCreated → Diagnostics → buildEnd です。

代表的な Hook は、

text
onConfigResolved
onContentLoaded
onPostParsed
onPostProcessed
onManifestCreated

です。

必要な段階の Hook だけを使用してください。

たとえば Manifest にすでに存在する情報を onContentLoaded で独自に再構築する、といった実装は避けます。

History

1 changesCollapseExpand
1 + ---
2 + title: プラグインの依存関係と Lifecycle
3 + sidebar:
4 + label: 依存関係と Lifecycle
5 + order: 10
6 + ---
7 + # プラグインの依存関係と Lifecycle
8 +
9 + このページは [プラグイン作成の詳細](../plugin-system.ja.md) の一部で、Plugin 同士の依存関係、Options の検証、Plugin Context、Lifecycle を扱います。
10 +
11 + ## 5. Plugin の依存関係
12 +
13 + Plugin 同士に実際の依存関係がある場合は Capability Contract を使用します。
14 +
15 + ```ts id="mdj2qn"
16 + definePlugin({
17 + name: "consumer",
18 +
19 + provides: [
20 + "example.output",
21 + ],
22 +
23 + requires: [
24 + "content.graph",
25 + ],
26 +
27 + optional: [
28 + "example.optional",
29 + ],
30 + });
31 + ```
32 +
33 + それぞれ、
34 +
35 + | Field | 意味 |
36 + | --- | --- |
37 + | `provides` | この Plugin が提供する Capability |
38 + | `requires` | 必須の Capability |
39 + | `optional` | あれば利用する Capability |
40 +
41 + です。
42 +
43 + Resolver は依存関係をもとに実行順を解決します。
44 +
45 + ```mermaid id="ahm3ow"
46 + flowchart LR
47 + Provider["Provider<br/>provides: content.graph"]
48 + Consumer["Consumer<br/>requires: content.graph"]
49 +
50 + Provider --> Consumer
51 + ```
52 +
53 + 次の状態は Configuration Error になります。
54 +
55 + - 必須 Capability がない
56 + - Provider が重複している
57 + - Dependency Cycle がある
58 +
59 + `order` は依存解決前の基本順序です。
60 +
61 + 実際の依存関係を表現するために `order` を使わないでください。
62 +
63 +
64 + ## 6. Options を検証する
65 +
66 + TypeScript の型だけでは Runtime Value を完全には保証できません。
67 +
68 + 必要な Plugin は `validateOptions` を実装します。
69 +
70 + ```text id="09xj48"
71 + Options
72 + ↓
73 + validateOptions
74 + ↓
75 + Structured Issues
76 + ↓
77 + riebeckite check
78 + ```
79 +
80 + Validator は副作用を持たせません。
81 +
82 + 特に、
83 +
84 + - Filesystem Scan
85 + - Build
86 + - Cache Write
87 + - 外部状態の変更
88 +
89 + を行わないでください。
90 +
91 + 問題は Structured Issue として返し、Config Validation からまとめて表示できるようにします。
92 +
93 +
94 + ## 7. Plugin Context
95 +
96 + Plugin は Framework の Service を `PluginContext` から受け取ります。
97 +
98 + 基本的な Context は概念的に次のようになります。
99 +
100 + ```ts id="jrp2vo"
101 + type PluginContext = {
102 + config?: ResolvedRiebeckiteConfig;
103 + contentIndex: Map<string, string>;
104 + diagnostics: Diagnostic[];
105 + cache: PluginCache;
106 + output: GeneratedOutputSink;
107 + logger: Logger;
108 + tracer: Tracer;
109 + contentSource?: ContentSource;
110 + };
111 + ```
112 +
113 + Hook によって、
114 +
115 + ```text id="2t18qa"
116 + slug
117 + markdown
118 + content
119 + manifest
120 + entries
121 + location input
122 + ```
123 +
124 + などが追加されます。
125 +
126 + Plugin 内で Framework Service の Global Singleton を作るのではなく、Context から必要な Service を受け取ることを優先します。
127 +
128 +
129 + ## 8. Lifecycle
130 +
131 + Framework Lifecycle には、
132 +
133 + ```text id="oy9iqs"
134 + setup
135 + buildStart
136 + buildEnd
137 + dispose
138 + ```
139 +
140 + があります。
141 +
142 + 概念的には、
143 +
144 + ```mermaid id="6hsbmh"
145 + flowchart LR
146 + Setup["setup"]
147 + Start["buildStart"]
148 + Work["Build / Content Processing"]
149 + End["buildEnd"]
150 + Dispose["dispose"]
151 +
152 + Setup --> Start
153 + Start --> Work
154 + Work --> End
155 + End --> Dispose
156 + ```
157 +
158 + という流れになります。
159 +
160 + `setup`、`buildStart`、`onConfigResolved`、Content 処理、`buildEnd` は、1つの `ContentManager` につき一度だけ実行されます。`buildEnd` は Diagnostics の収集後に完成した Manifest を受け取る唯一の終端 Hook です。`dispose` は確保した Resource の解放に使用し、解決済み Plugin の逆順で実行されます。
161 +
162 + Lifecycle の実行順は、解決済み Plugin Order に従います。
163 +
164 + Hook で Error が発生した場合は、
165 +
166 + - Plugin 名
167 + - Hook 名
168 + - 元の Cause
169 +
170 + が分かる形で上位へ伝播させてください。
171 +
172 +
173 + ## 9. Content Lifecycle
174 +
175 + Content は複数の段階を通って処理されます。
176 +
177 + ```mermaid id="47k3qg"
178 + flowchart TD
179 + Config["Config Resolved"]
180 + Loaded["Content Loaded"]
181 + Location["Public Location Resolved"]
182 + Parsed["Post Parsed"]
183 + Processed["Post Processed"]
184 + Graph["Content Graph"]
185 + Manifest["Manifest Created"]
186 +
187 + Config --> Location
188 + Location --> Loaded
189 + Loaded --> Parsed
190 + Parsed --> Processed
191 + Processed --> Graph
192 + Graph --> Manifest
193 + ```
194 +
195 + 全体の順序は `setup` → `buildStart` → `onConfigResolved` → Public Location 解決 → `onContentLoaded` → Markdown / HTML Pipeline → `onPostParsed` → `onPostProcessed` → `extendContentGraph` → `onManifestCreated` → Diagnostics → `buildEnd` です。
196 +
197 + 代表的な Hook は、
198 +
199 + ```text id="6idgbj"
200 + onConfigResolved
201 + onContentLoaded
202 + onPostParsed
203 + onPostProcessed
204 + onManifestCreated
205 + ```
206 +
207 + です。
208 +
209 + 必要な段階の Hook だけを使用してください。
210 +
211 + たとえば Manifest にすでに存在する情報を `onContentLoaded` で独自に再構築する、といった実装は避けます。
212 +