@terrymooreii/sia 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/README.md +46 -0
- package/docs/creating-plugins.md +509 -0
- package/docs/plugins.md +320 -0
- package/lib/build.js +69 -4
- package/lib/collections.js +9 -3
- package/lib/config.js +7 -0
- package/lib/content.js +49 -23
- package/lib/hooks.js +188 -0
- package/lib/index.js +19 -0
- package/lib/plugins.js +308 -0
- package/lib/templates.js +7 -1
- package/package.json +1 -1
package/docs/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Welcome to the Sia documentation. Sia is a simple, powerful static site generato
|
|
|
10
10
|
| [Markdown Guide](markdown-guide.md) | Markdown syntax and all supported plugins |
|
|
11
11
|
| [Front Matter Reference](front-matter.md) | YAML front matter options for posts, pages, and notes |
|
|
12
12
|
| [Creating Themes](creating-themes.md) | How to create and customize themes |
|
|
13
|
+
| [Plugin System](plugins.md) | Extend Sia with plugins - hooks, API, and configuration |
|
|
14
|
+
| [Creating Plugins](creating-plugins.md) | Guide to creating local and npm package plugins |
|
|
13
15
|
|
|
14
16
|
## Quick Links
|
|
15
17
|
|
|
@@ -58,6 +60,7 @@ npm run build
|
|
|
58
60
|
- **Live Reload** - Development server with hot reloading
|
|
59
61
|
- **Multiple Themes** - Built-in themes (main, minimal, developer, magazine) with light/dark mode
|
|
60
62
|
- **Custom Theme Packages** - Create and share themes as npm packages (`sia-theme-*`)
|
|
63
|
+
- **Plugin System** - Extend functionality with local or npm plugins (`sia-plugin-*`)
|
|
61
64
|
- **RSS Feed** - Automatic RSS feed generation
|
|
62
65
|
- **SEO Ready** - Open Graph and Twitter Card meta tags included
|
|
63
66
|
|
|
@@ -86,6 +89,8 @@ my-site/
|
|
|
86
89
|
├── favicon.ico # Site favicon (optional)
|
|
87
90
|
├── _layouts/ # Custom layouts (optional)
|
|
88
91
|
├── _includes/ # Custom includes (optional)
|
|
92
|
+
├── _plugins/ # Local plugins (optional)
|
|
93
|
+
│ └── my-plugin.js
|
|
89
94
|
├── styles/ # Custom CSS (optional)
|
|
90
95
|
└── dist/ # Generated output
|
|
91
96
|
```
|
|
@@ -136,6 +141,12 @@ server:
|
|
|
136
141
|
assets:
|
|
137
142
|
css: [] # Custom CSS files (paths relative to root)
|
|
138
143
|
js: [] # Custom JavaScript files (paths relative to root)
|
|
144
|
+
|
|
145
|
+
plugins:
|
|
146
|
+
enabled: true # Master switch for plugins
|
|
147
|
+
strictMode: false # Fail build on plugin errors
|
|
148
|
+
order: [] # Explicit plugin execution order (optional)
|
|
149
|
+
config: {} # Plugin-specific configuration
|
|
139
150
|
```
|
|
140
151
|
|
|
141
152
|
## Custom CSS and JavaScript
|
|
@@ -173,6 +184,40 @@ This will:
|
|
|
173
184
|
|
|
174
185
|
And inject them into all pages automatically.
|
|
175
186
|
|
|
187
|
+
## Plugin System
|
|
188
|
+
|
|
189
|
+
Sia includes a powerful plugin system that allows you to extend functionality at key points in the build lifecycle. Plugins can:
|
|
190
|
+
|
|
191
|
+
- Transform content during parsing
|
|
192
|
+
- Generate additional files (search indexes, sitemaps, etc.)
|
|
193
|
+
- Add custom Marked extensions for markdown processing
|
|
194
|
+
- Register custom Nunjucks template filters and functions
|
|
195
|
+
- Modify site data before rendering
|
|
196
|
+
- Perform post-build tasks
|
|
197
|
+
|
|
198
|
+
### Using Plugins
|
|
199
|
+
|
|
200
|
+
Plugins can be local (in `_plugins/` directory) or npm packages (with `sia-plugin-*` naming):
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Install an npm plugin
|
|
204
|
+
npm install sia-plugin-search
|
|
205
|
+
|
|
206
|
+
# Or create a local plugin in _plugins/my-plugin.js
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Configure plugins in `_config.yml`:
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
plugins:
|
|
213
|
+
enabled: true
|
|
214
|
+
config:
|
|
215
|
+
sia-plugin-search:
|
|
216
|
+
outputPath: search-index.json
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
See the [Plugin System documentation](plugins.md) for complete details and the [Creating Plugins guide](creating-plugins.md) for examples.
|
|
220
|
+
|
|
176
221
|
## Static Assets
|
|
177
222
|
|
|
178
223
|
Sia automatically copies static assets during the build process. You can place static files in any of these locations:
|
|
@@ -236,6 +281,7 @@ dist/
|
|
|
236
281
|
| `sia new page "Title"` | Create a new page |
|
|
237
282
|
| `sia new note "Content"` | Create a new note |
|
|
238
283
|
| `sia theme <name>` | Create a new theme package |
|
|
284
|
+
| `sia migrate` | Migrate standalone .md files to folder structure |
|
|
239
285
|
|
|
240
286
|
## License
|
|
241
287
|
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# Creating Plugins
|
|
2
|
+
|
|
3
|
+
This guide explains how to create plugins for Sia, both as local plugins in your project and as npm packages that can be shared with others.
|
|
4
|
+
|
|
5
|
+
## Plugin Types
|
|
6
|
+
|
|
7
|
+
Sia supports two types of plugins:
|
|
8
|
+
|
|
9
|
+
1. **Local plugins**: JavaScript files in your project's `_plugins/` directory
|
|
10
|
+
2. **NPM package plugins**: Published npm packages with the `sia-plugin-*` naming convention
|
|
11
|
+
|
|
12
|
+
## Local Plugins
|
|
13
|
+
|
|
14
|
+
Local plugins are perfect for project-specific functionality that you don't need to share.
|
|
15
|
+
|
|
16
|
+
### Creating a Local Plugin
|
|
17
|
+
|
|
18
|
+
1. Create a `_plugins/` directory in your project root (if it doesn't exist)
|
|
19
|
+
2. Create a JavaScript file (`.js` or `.mjs`) in that directory
|
|
20
|
+
3. Export a plugin object
|
|
21
|
+
|
|
22
|
+
**Example: `_plugins/search-index.js`**
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
export default {
|
|
26
|
+
name: 'search-index',
|
|
27
|
+
version: '1.0.0',
|
|
28
|
+
hooks: {
|
|
29
|
+
afterBuild: async (siteData, config, api) => {
|
|
30
|
+
// Generate search index
|
|
31
|
+
const searchData = {
|
|
32
|
+
pages: siteData.collections.pages.map(item => ({
|
|
33
|
+
title: item.title,
|
|
34
|
+
url: item.url,
|
|
35
|
+
excerpt: item.excerpt,
|
|
36
|
+
tags: item.tags
|
|
37
|
+
})),
|
|
38
|
+
posts: siteData.collections.posts.map(item => ({
|
|
39
|
+
title: item.title,
|
|
40
|
+
url: item.url,
|
|
41
|
+
date: item.date.toISOString(),
|
|
42
|
+
excerpt: item.excerpt,
|
|
43
|
+
tags: item.tags
|
|
44
|
+
})),
|
|
45
|
+
notes: siteData.collections.notes.map(item => ({
|
|
46
|
+
title: item.title,
|
|
47
|
+
url: item.url,
|
|
48
|
+
date: item.date.toISOString(),
|
|
49
|
+
excerpt: item.excerpt
|
|
50
|
+
}))
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Write search index file
|
|
54
|
+
const outputPath = api.joinPath(config.outputDir, 'search-index.json');
|
|
55
|
+
api.writeFile(outputPath, JSON.stringify(searchData, null, 2));
|
|
56
|
+
api.log('Generated search index', 'info');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Local Plugin with Configuration
|
|
63
|
+
|
|
64
|
+
You can access plugin-specific configuration from `config.plugins.config`:
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
export default {
|
|
68
|
+
name: 'search-index',
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
configSchema: {
|
|
71
|
+
outputPath: { type: 'string', default: 'search-index.json' },
|
|
72
|
+
includeContent: { type: 'boolean', default: false }
|
|
73
|
+
},
|
|
74
|
+
hooks: {
|
|
75
|
+
afterBuild: async (siteData, config, api) => {
|
|
76
|
+
const pluginConfig = config.plugins?.config?.['search-index'] || {};
|
|
77
|
+
const outputPath = pluginConfig.outputPath || 'search-index.json';
|
|
78
|
+
const includeContent = pluginConfig.includeContent || false;
|
|
79
|
+
|
|
80
|
+
const searchData = {
|
|
81
|
+
pages: siteData.collections.pages.map(item => ({
|
|
82
|
+
title: item.title,
|
|
83
|
+
url: item.url,
|
|
84
|
+
excerpt: item.excerpt,
|
|
85
|
+
...(includeContent && { content: item.content })
|
|
86
|
+
})),
|
|
87
|
+
// ... posts, notes
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
api.writeFile(
|
|
91
|
+
api.joinPath(config.outputDir, outputPath),
|
|
92
|
+
JSON.stringify(searchData, null, 2)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Configure in `_config.yml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
plugins:
|
|
103
|
+
config:
|
|
104
|
+
search-index:
|
|
105
|
+
outputPath: search-index.json
|
|
106
|
+
includeContent: false
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## NPM Package Plugins
|
|
110
|
+
|
|
111
|
+
NPM package plugins can be shared with the community and installed via npm.
|
|
112
|
+
|
|
113
|
+
### Creating an NPM Package Plugin
|
|
114
|
+
|
|
115
|
+
1. Create a new npm package with name starting with `sia-plugin-`
|
|
116
|
+
2. Set up the package structure
|
|
117
|
+
3. Export the plugin object
|
|
118
|
+
|
|
119
|
+
### Package Structure
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
sia-plugin-example/
|
|
123
|
+
├── package.json
|
|
124
|
+
├── index.js
|
|
125
|
+
├── README.md
|
|
126
|
+
└── LICENSE
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### package.json
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"name": "sia-plugin-example",
|
|
134
|
+
"version": "1.0.0",
|
|
135
|
+
"description": "Example Sia plugin",
|
|
136
|
+
"main": "index.js",
|
|
137
|
+
"type": "module",
|
|
138
|
+
"keywords": [
|
|
139
|
+
"sia",
|
|
140
|
+
"sia-plugin",
|
|
141
|
+
"static-site-generator"
|
|
142
|
+
],
|
|
143
|
+
"author": "Your Name",
|
|
144
|
+
"license": "MIT",
|
|
145
|
+
"engines": {
|
|
146
|
+
"node": ">=18.0.0"
|
|
147
|
+
},
|
|
148
|
+
"peerDependencies": {
|
|
149
|
+
"@terrymooreii/sia": "^2.0.0"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### index.js
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
export default {
|
|
158
|
+
name: 'sia-plugin-example',
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
configSchema: {
|
|
161
|
+
enabled: { type: 'boolean', default: true },
|
|
162
|
+
outputFile: { type: 'string', default: 'example-output.json' }
|
|
163
|
+
},
|
|
164
|
+
hooks: {
|
|
165
|
+
afterBuild: async (siteData, config, api) => {
|
|
166
|
+
const pluginConfig = config.plugins?.config?.['sia-plugin-example'] || {};
|
|
167
|
+
|
|
168
|
+
if (pluginConfig.enabled === false) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const output = {
|
|
173
|
+
buildDate: new Date().toISOString(),
|
|
174
|
+
totalPages: siteData.collections.pages.length,
|
|
175
|
+
totalPosts: siteData.collections.posts.length,
|
|
176
|
+
totalNotes: siteData.collections.notes.length,
|
|
177
|
+
totalTags: siteData.allTags.length
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
api.writeFile(
|
|
181
|
+
api.joinPath(config.outputDir, pluginConfig.outputFile || 'example-output.json'),
|
|
182
|
+
JSON.stringify(output, null, 2)
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
api.log(`Generated ${pluginConfig.outputFile}`, 'info');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Installing and Using
|
|
192
|
+
|
|
193
|
+
Users install your plugin:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm install sia-plugin-example
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Then configure it in `_config.yml`:
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
plugins:
|
|
203
|
+
config:
|
|
204
|
+
sia-plugin-example:
|
|
205
|
+
enabled: true
|
|
206
|
+
outputFile: stats.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Advanced Examples
|
|
210
|
+
|
|
211
|
+
### Content Transformation Plugin
|
|
212
|
+
|
|
213
|
+
Transform content during parsing:
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
export default {
|
|
217
|
+
name: 'content-transformer',
|
|
218
|
+
version: '1.0.0',
|
|
219
|
+
hooks: {
|
|
220
|
+
beforeMarkdown: (markdown, context) => {
|
|
221
|
+
// Replace custom syntax
|
|
222
|
+
return markdown.replace(/\[TOC\]/g, '<!-- Table of Contents -->');
|
|
223
|
+
},
|
|
224
|
+
afterMarkdown: (html, context) => {
|
|
225
|
+
// Inject custom HTML
|
|
226
|
+
return html.replace(
|
|
227
|
+
'<!-- Table of Contents -->',
|
|
228
|
+
'<nav class="toc">...</nav>'
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Custom Template Filter Plugin
|
|
236
|
+
|
|
237
|
+
Add custom Nunjucks filters:
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
export default {
|
|
241
|
+
name: 'custom-filters',
|
|
242
|
+
version: '1.0.0',
|
|
243
|
+
hooks: {
|
|
244
|
+
addTemplateFilter: (env, config) => {
|
|
245
|
+
// Add a filter to format numbers
|
|
246
|
+
env.addFilter('formatNumber', (num) => {
|
|
247
|
+
return new Intl.NumberFormat().format(num);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Add a filter to truncate text
|
|
251
|
+
env.addFilter('truncate', (str, length = 50) => {
|
|
252
|
+
if (str.length <= length) return str;
|
|
253
|
+
return str.substring(0, length) + '...';
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Use in templates:
|
|
261
|
+
|
|
262
|
+
```nunjucks
|
|
263
|
+
{{ post.wordCount | formatNumber }}
|
|
264
|
+
{{ post.excerpt | truncate(100) }}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Custom Marked Extension Plugin
|
|
268
|
+
|
|
269
|
+
Add custom markdown syntax:
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
import { addMarkedExtension } from '@terrymooreii/sia';
|
|
273
|
+
|
|
274
|
+
export default {
|
|
275
|
+
name: 'custom-markdown',
|
|
276
|
+
version: '1.0.0',
|
|
277
|
+
hooks: {
|
|
278
|
+
beforeBuild: (config, api) => {
|
|
279
|
+
addMarkedExtension({
|
|
280
|
+
renderer: {
|
|
281
|
+
// Custom blockquote renderer
|
|
282
|
+
blockquote(quote) {
|
|
283
|
+
return `<blockquote class="custom-quote">${quote}</blockquote>`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Sitemap Generator Plugin
|
|
293
|
+
|
|
294
|
+
Generate a sitemap.xml:
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
export default {
|
|
298
|
+
name: 'sitemap-generator',
|
|
299
|
+
version: '1.0.0',
|
|
300
|
+
hooks: {
|
|
301
|
+
afterBuild: async (siteData, config, api) => {
|
|
302
|
+
const siteUrl = config.site.url.replace(/\/$/, '');
|
|
303
|
+
const basePath = config.site.basePath || '';
|
|
304
|
+
|
|
305
|
+
const urls = [];
|
|
306
|
+
|
|
307
|
+
// Add homepage
|
|
308
|
+
urls.push({
|
|
309
|
+
loc: `${siteUrl}${basePath}/`,
|
|
310
|
+
lastmod: new Date().toISOString().split('T')[0],
|
|
311
|
+
changefreq: 'daily',
|
|
312
|
+
priority: '1.0'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Add all content items
|
|
316
|
+
for (const [collectionName, items] of Object.entries(siteData.collections)) {
|
|
317
|
+
for (const item of items) {
|
|
318
|
+
urls.push({
|
|
319
|
+
loc: `${siteUrl}${item.url}`,
|
|
320
|
+
lastmod: item.date.toISOString().split('T')[0],
|
|
321
|
+
changefreq: 'monthly',
|
|
322
|
+
priority: collectionName === 'pages' ? '0.8' : '0.6'
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Generate XML
|
|
328
|
+
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
329
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
330
|
+
${urls.map(url => ` <url>
|
|
331
|
+
<loc>${url.loc}</loc>
|
|
332
|
+
<lastmod>${url.lastmod}</lastmod>
|
|
333
|
+
<changefreq>${url.changefreq}</changefreq>
|
|
334
|
+
<priority>${url.priority}</priority>
|
|
335
|
+
</url>`).join('\n')}
|
|
336
|
+
</urlset>`;
|
|
337
|
+
|
|
338
|
+
api.writeFile(
|
|
339
|
+
api.joinPath(config.outputDir, 'sitemap.xml'),
|
|
340
|
+
sitemap
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
api.log('Generated sitemap.xml', 'info');
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Plugin with Dependencies
|
|
350
|
+
|
|
351
|
+
Plugins can depend on other plugins:
|
|
352
|
+
|
|
353
|
+
```javascript
|
|
354
|
+
export default {
|
|
355
|
+
name: 'enhanced-search',
|
|
356
|
+
version: '1.0.0',
|
|
357
|
+
dependencies: ['search-index'], // Requires search-index plugin
|
|
358
|
+
hooks: {
|
|
359
|
+
afterBuild: async (siteData, config, api) => {
|
|
360
|
+
// This plugin enhances the search index created by search-index plugin
|
|
361
|
+
// It runs after search-index because of the dependency
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Best Practices
|
|
368
|
+
|
|
369
|
+
### 1. Error Handling
|
|
370
|
+
|
|
371
|
+
Always handle errors gracefully:
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
hooks: {
|
|
375
|
+
afterBuild: async (siteData, config, api) => {
|
|
376
|
+
try {
|
|
377
|
+
// Plugin logic
|
|
378
|
+
} catch (err) {
|
|
379
|
+
api.log(`Plugin error: ${err.message}`, 'error');
|
|
380
|
+
// Don't throw - let the build continue
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 2. Configuration Validation
|
|
387
|
+
|
|
388
|
+
Validate plugin configuration:
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
hooks: {
|
|
392
|
+
beforeBuild: (config, api) => {
|
|
393
|
+
const pluginConfig = config.plugins?.config?.['my-plugin'] || {};
|
|
394
|
+
|
|
395
|
+
if (pluginConfig.requiredOption === undefined) {
|
|
396
|
+
throw new Error('my-plugin: requiredOption is required');
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 3. Async Operations
|
|
403
|
+
|
|
404
|
+
Use async/await for asynchronous operations:
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
hooks: {
|
|
408
|
+
afterBuild: async (siteData, config, api) => {
|
|
409
|
+
const data = await fetchExternalData();
|
|
410
|
+
// Process data
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### 4. Logging
|
|
416
|
+
|
|
417
|
+
Use the API's logging function:
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
api.log('Processing complete', 'info');
|
|
421
|
+
api.log('Warning: something unusual', 'warn');
|
|
422
|
+
api.log('Error occurred', 'error');
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### 5. Documentation
|
|
426
|
+
|
|
427
|
+
Document your plugin:
|
|
428
|
+
|
|
429
|
+
- Explain what it does
|
|
430
|
+
- List configuration options
|
|
431
|
+
- Provide usage examples
|
|
432
|
+
- Include version compatibility
|
|
433
|
+
|
|
434
|
+
### 6. Testing
|
|
435
|
+
|
|
436
|
+
Test your plugin:
|
|
437
|
+
|
|
438
|
+
1. Create a test Sia site
|
|
439
|
+
2. Add your plugin
|
|
440
|
+
3. Run `sia build`
|
|
441
|
+
4. Verify the output
|
|
442
|
+
|
|
443
|
+
### 7. Version Compatibility
|
|
444
|
+
|
|
445
|
+
Specify Sia version requirements in your plugin's README:
|
|
446
|
+
|
|
447
|
+
```markdown
|
|
448
|
+
## Requirements
|
|
449
|
+
|
|
450
|
+
- Sia >= 2.0.0
|
|
451
|
+
- Node.js >= 18.0.0
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Publishing NPM Plugins
|
|
455
|
+
|
|
456
|
+
1. **Prepare your package:**
|
|
457
|
+
- Write a clear README
|
|
458
|
+
- Add a LICENSE file
|
|
459
|
+
- Test thoroughly
|
|
460
|
+
|
|
461
|
+
2. **Publish to npm:**
|
|
462
|
+
```bash
|
|
463
|
+
npm login
|
|
464
|
+
npm publish
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
3. **Tag your releases:**
|
|
468
|
+
```bash
|
|
469
|
+
git tag v1.0.0
|
|
470
|
+
git push --tags
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
4. **Update documentation:**
|
|
474
|
+
- Add to Sia's plugin list (if applicable)
|
|
475
|
+
- Share on social media/forums
|
|
476
|
+
|
|
477
|
+
## Troubleshooting
|
|
478
|
+
|
|
479
|
+
### Plugin Not Loading
|
|
480
|
+
|
|
481
|
+
- Check that the plugin file is in `_plugins/` or installed via npm
|
|
482
|
+
- Verify the plugin exports a default object with `name` and `version`
|
|
483
|
+
- Check console output for error messages
|
|
484
|
+
|
|
485
|
+
### Hook Not Executing
|
|
486
|
+
|
|
487
|
+
- Verify the hook name is correct
|
|
488
|
+
- Check that the hook function is properly defined
|
|
489
|
+
- Ensure the plugin is enabled (`plugins.enabled: true`)
|
|
490
|
+
|
|
491
|
+
### Configuration Not Working
|
|
492
|
+
|
|
493
|
+
- Verify configuration is in `config.plugins.config[pluginName]`
|
|
494
|
+
- Check that plugin name matches exactly (case-sensitive)
|
|
495
|
+
- Validate configuration structure matches `configSchema`
|
|
496
|
+
|
|
497
|
+
### Build Failing
|
|
498
|
+
|
|
499
|
+
- Set `plugins.strictMode: false` to see detailed error messages
|
|
500
|
+
- Check plugin dependencies are installed
|
|
501
|
+
- Verify Node.js version compatibility
|
|
502
|
+
|
|
503
|
+
## Resources
|
|
504
|
+
|
|
505
|
+
- [Plugin System Documentation](./plugins.md) - Complete hook reference
|
|
506
|
+
- [Sia GitHub Repository](https://github.com/terrymooreii/sia) - Source code and issues
|
|
507
|
+
- [Marked Documentation](https://marked.js.org/) - For custom markdown extensions
|
|
508
|
+
- [Nunjucks Documentation](https://mozilla.github.io/nunjucks/) - For custom template filters/functions
|
|
509
|
+
|