underpost 2.90.0 → 2.90.4
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/.env.production +2 -0
- package/README.md +3 -2
- package/bin/build.js +4 -0
- package/bin/deploy.js +16 -0
- package/cli.md +56 -2
- package/examples/QUICK-REFERENCE.md +499 -0
- package/examples/README.md +447 -0
- package/examples/STATIC-GENERATOR-GUIDE.md +807 -0
- package/examples/ssr-components/CustomPage.js +579 -0
- package/examples/static-config-example.json +183 -0
- package/examples/static-config-simple.json +57 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -1
- package/src/api/document/document.model.js +7 -0
- package/src/api/document/document.service.js +4 -1
- package/src/cli/index.js +105 -1
- package/src/cli/run.js +1 -1
- package/src/cli/static.js +820 -0
- package/src/client/components/core/Input.js +6 -4
- package/src/client/components/core/Modal.js +13 -18
- package/src/client/components/core/Panel.js +26 -6
- package/src/client/components/core/PanelForm.js +67 -52
- package/src/index.js +10 -1
- package/src/server/client-build.js +9 -15
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
# Underpost Static Site Generator - Comprehensive Guide
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Overview](#overview)
|
|
6
|
+
2. [Quick Start](#quick-start)
|
|
7
|
+
3. [CLI Usage](#cli-usage)
|
|
8
|
+
4. [Configuration File](#configuration-file)
|
|
9
|
+
5. [Metadata Customization](#metadata-customization)
|
|
10
|
+
6. [Scripts and Styles](#scripts-and-styles)
|
|
11
|
+
7. [Icons and PWA](#icons-and-pwa)
|
|
12
|
+
8. [SSR Components](#ssr-components)
|
|
13
|
+
9. [Advanced Examples](#advanced-examples)
|
|
14
|
+
10. [Best Practices](#best-practices)
|
|
15
|
+
11. [API Reference](#api-reference)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
The Underpost Static Site Generator is a powerful tool for creating highly customizable static HTML pages with:
|
|
22
|
+
|
|
23
|
+
- **Comprehensive SEO metadata** (Open Graph, Twitter Cards, Schema.org)
|
|
24
|
+
- **Custom script and stylesheet injection**
|
|
25
|
+
- **Icon and PWA manifest support**
|
|
26
|
+
- **Server-side rendering (SSR) components**
|
|
27
|
+
- **Structured data (JSON-LD) support**
|
|
28
|
+
- **Production-ready minification**
|
|
29
|
+
- **Flexible configuration via CLI or JSON files**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
Generate a simple static page:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
underpost static \
|
|
41
|
+
--page ./src/client/ssr/body/DefaultSplashScreen.js \
|
|
42
|
+
--output-path ./dist/index.html \
|
|
43
|
+
--title "My App"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Using a Configuration File
|
|
47
|
+
|
|
48
|
+
1. Generate a template config:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
underpost static --generate-config ./my-config.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. Edit the generated `my-config.json` file
|
|
55
|
+
|
|
56
|
+
3. Build with the config:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
underpost static --config-file ./my-config.json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## CLI Usage
|
|
65
|
+
|
|
66
|
+
### Complete CLI Options
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
underpost static [options]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Page and Output Options
|
|
73
|
+
|
|
74
|
+
- `--page <path>` - SSR component path to render
|
|
75
|
+
- `--output-path <path>` - Where to save the generated HTML
|
|
76
|
+
- `--env <env>` - Environment: `development` or `production` (default: `production`)
|
|
77
|
+
- `--minify` / `--no-minify` - Control HTML minification
|
|
78
|
+
|
|
79
|
+
#### Metadata Options
|
|
80
|
+
|
|
81
|
+
- `--title <title>` - Page title
|
|
82
|
+
- `--description <desc>` - Page description for SEO
|
|
83
|
+
- `--keywords <keywords>` - Comma-separated keywords
|
|
84
|
+
- `--author <author>` - Page author
|
|
85
|
+
- `--theme-color <color>` - Theme color (hex format)
|
|
86
|
+
- `--canonical-url <url>` - Canonical URL
|
|
87
|
+
- `--thumbnail <url>` - Open Graph thumbnail URL
|
|
88
|
+
- `--locale <locale>` - Page locale (e.g., `en-US`)
|
|
89
|
+
- `--site-name <name>` - Site name for Open Graph
|
|
90
|
+
|
|
91
|
+
#### Script and Style Options
|
|
92
|
+
|
|
93
|
+
- `--head-scripts <paths>` - Comma-separated script URLs for `<head>`
|
|
94
|
+
- `--body-scripts <paths>` - Comma-separated script URLs for `<body>`
|
|
95
|
+
- `--styles <paths>` - Comma-separated stylesheet URLs
|
|
96
|
+
|
|
97
|
+
#### Icon Options
|
|
98
|
+
|
|
99
|
+
- `--favicon <path>` - Favicon path
|
|
100
|
+
- `--apple-touch-icon <path>` - Apple touch icon path
|
|
101
|
+
- `--manifest <path>` - Web manifest path
|
|
102
|
+
|
|
103
|
+
#### Component Options
|
|
104
|
+
|
|
105
|
+
- `--head-components <paths>` - Comma-separated SSR head component paths
|
|
106
|
+
- `--body-components <paths>` - Comma-separated SSR body component paths
|
|
107
|
+
|
|
108
|
+
#### Build Options
|
|
109
|
+
|
|
110
|
+
- `--deploy-id <id>` - Deployment identifier
|
|
111
|
+
- `--build` - Trigger build process
|
|
112
|
+
- `--build-host <host>` - Build host URL
|
|
113
|
+
- `--build-path <path>` - Build path (default: `/`)
|
|
114
|
+
|
|
115
|
+
#### Configuration Options
|
|
116
|
+
|
|
117
|
+
- `--config-file <path>` - Load configuration from JSON file
|
|
118
|
+
- `--generate-config [path]` - Generate template config file
|
|
119
|
+
- `--lang <lang>` - HTML lang attribute (default: `en`)
|
|
120
|
+
- `--dir <dir>` - HTML dir attribute (default: `ltr`)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Configuration File
|
|
125
|
+
|
|
126
|
+
### Structure
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"page": "./src/client/ssr/body/CustomPage.js",
|
|
131
|
+
"outputPath": "./dist/index.html",
|
|
132
|
+
"env": "production",
|
|
133
|
+
"minify": true,
|
|
134
|
+
"lang": "en",
|
|
135
|
+
"dir": "ltr",
|
|
136
|
+
|
|
137
|
+
"metadata": { /* ... */ },
|
|
138
|
+
"scripts": { /* ... */ },
|
|
139
|
+
"styles": [ /* ... */ ],
|
|
140
|
+
"icons": { /* ... */ },
|
|
141
|
+
"headComponents": [ /* ... */ ],
|
|
142
|
+
"bodyComponents": [ /* ... */ ],
|
|
143
|
+
"microdata": [ /* ... */ ],
|
|
144
|
+
"customPayload": { /* ... */ }
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Generate Template
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
underpost static --generate-config ./static-config.json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
This creates a fully documented template with all available options.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Metadata Customization
|
|
159
|
+
|
|
160
|
+
### Basic Metadata
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"metadata": {
|
|
165
|
+
"title": "My Application",
|
|
166
|
+
"description": "A comprehensive description of my application",
|
|
167
|
+
"keywords": ["web app", "progressive", "modern"],
|
|
168
|
+
"author": "Jane Developer",
|
|
169
|
+
"themeColor": "#4CAF50",
|
|
170
|
+
"canonicalURL": "https://example.com",
|
|
171
|
+
"thumbnail": "https://example.com/images/og-image.png",
|
|
172
|
+
"locale": "en-US",
|
|
173
|
+
"siteName": "My Site"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Advanced Open Graph
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"metadata": {
|
|
183
|
+
"title": "My App",
|
|
184
|
+
"description": "App description",
|
|
185
|
+
"openGraph": {
|
|
186
|
+
"type": "website",
|
|
187
|
+
"image:width": "1200",
|
|
188
|
+
"image:height": "630",
|
|
189
|
+
"image:alt": "App screenshot"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Twitter Cards
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"metadata": {
|
|
200
|
+
"title": "My App",
|
|
201
|
+
"twitter": {
|
|
202
|
+
"card": "summary_large_image",
|
|
203
|
+
"site": "@myhandle",
|
|
204
|
+
"creator": "@developerhandle"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### CLI Example
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
underpost static \
|
|
214
|
+
--page ./src/client/ssr/body/HomePage.js \
|
|
215
|
+
--output-path ./dist/index.html \
|
|
216
|
+
--title "My App" \
|
|
217
|
+
--description "A modern web application" \
|
|
218
|
+
--keywords "web,app,modern" \
|
|
219
|
+
--author "John Doe" \
|
|
220
|
+
--theme-color "#007bff" \
|
|
221
|
+
--canonical-url "https://myapp.com" \
|
|
222
|
+
--thumbnail "https://myapp.com/og-image.png"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Scripts and Styles
|
|
228
|
+
|
|
229
|
+
### External Scripts
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"scripts": {
|
|
234
|
+
"head": [
|
|
235
|
+
{
|
|
236
|
+
"src": "https://cdn.example.com/analytics.js",
|
|
237
|
+
"async": true
|
|
238
|
+
}
|
|
239
|
+
],
|
|
240
|
+
"body": [
|
|
241
|
+
{
|
|
242
|
+
"src": "/app.js",
|
|
243
|
+
"type": "module",
|
|
244
|
+
"defer": true
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Inline Scripts
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"scripts": {
|
|
256
|
+
"head": [
|
|
257
|
+
{
|
|
258
|
+
"content": "window.config = { apiUrl: 'https://api.example.com' };",
|
|
259
|
+
"type": "text/javascript"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Advanced Script Options
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"scripts": {
|
|
271
|
+
"head": [
|
|
272
|
+
{
|
|
273
|
+
"src": "https://cdn.example.com/lib.js",
|
|
274
|
+
"async": true,
|
|
275
|
+
"integrity": "sha384-...",
|
|
276
|
+
"crossorigin": "anonymous",
|
|
277
|
+
"attributes": {
|
|
278
|
+
"data-custom": "value"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Stylesheets
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"styles": [
|
|
291
|
+
{
|
|
292
|
+
"href": "/styles/main.css"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"href": "https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"content": "body { margin: 0; padding: 0; }",
|
|
299
|
+
"_comment": "Critical CSS inline"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"href": "/styles/print.css",
|
|
303
|
+
"media": "print"
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### CLI Example
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
underpost static \
|
|
313
|
+
--page ./src/client/ssr/body/App.js \
|
|
314
|
+
--output-path ./dist/index.html \
|
|
315
|
+
--head-scripts "https://cdn.example.com/analytics.js,/config.js" \
|
|
316
|
+
--body-scripts "/app.js" \
|
|
317
|
+
--styles "/main.css,/theme.css"
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Icons and PWA
|
|
323
|
+
|
|
324
|
+
### Basic Icons
|
|
325
|
+
|
|
326
|
+
```json
|
|
327
|
+
{
|
|
328
|
+
"icons": {
|
|
329
|
+
"favicon": "/favicon.ico",
|
|
330
|
+
"appleTouchIcon": "/apple-touch-icon.png",
|
|
331
|
+
"manifest": "/manifest.json"
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Advanced Icons
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"icons": {
|
|
341
|
+
"favicon": "/favicon.ico",
|
|
342
|
+
"appleTouchIcon": "/apple-touch-icon.png",
|
|
343
|
+
"manifest": "/manifest.json",
|
|
344
|
+
"additional": [
|
|
345
|
+
{
|
|
346
|
+
"rel": "icon",
|
|
347
|
+
"type": "image/png",
|
|
348
|
+
"sizes": "32x32",
|
|
349
|
+
"href": "/favicon-32x32.png"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"rel": "icon",
|
|
353
|
+
"type": "image/png",
|
|
354
|
+
"sizes": "16x16",
|
|
355
|
+
"href": "/favicon-16x16.png"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"rel": "mask-icon",
|
|
359
|
+
"href": "/safari-pinned-tab.svg",
|
|
360
|
+
"color": "#4CAF50"
|
|
361
|
+
}
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### CLI Example
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
underpost static \
|
|
371
|
+
--page ./src/client/ssr/body/App.js \
|
|
372
|
+
--output-path ./dist/index.html \
|
|
373
|
+
--favicon "/favicon.ico" \
|
|
374
|
+
--apple-touch-icon "/apple-touch-icon.png" \
|
|
375
|
+
--manifest "/manifest.json"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## SSR Components
|
|
381
|
+
|
|
382
|
+
### Head Components
|
|
383
|
+
|
|
384
|
+
Create custom SSR components for reusable head content:
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
// src/client/ssr/head/CustomMeta.js
|
|
388
|
+
SrrComponent = ({ title, author, themeColor }) => html`
|
|
389
|
+
<meta name="author" content="${author}" />
|
|
390
|
+
<meta name="theme-color" content="${themeColor}" />
|
|
391
|
+
<meta name="custom-meta" content="custom-value" />
|
|
392
|
+
`;
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Use in configuration:
|
|
396
|
+
|
|
397
|
+
```json
|
|
398
|
+
{
|
|
399
|
+
"headComponents": [
|
|
400
|
+
"./src/client/ssr/head/Seo.js",
|
|
401
|
+
"./src/client/ssr/head/Pwa.js",
|
|
402
|
+
"./src/client/ssr/head/CustomMeta.js"
|
|
403
|
+
]
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Body Components
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
// src/client/ssr/body/CustomSplash.js
|
|
411
|
+
SrrComponent = () => html`
|
|
412
|
+
<div class="splash-screen">
|
|
413
|
+
<div class="logo"></div>
|
|
414
|
+
<div class="loading">Loading...</div>
|
|
415
|
+
</div>
|
|
416
|
+
`;
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### CLI Example
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
underpost static \
|
|
423
|
+
--page ./src/client/ssr/body/MainPage.js \
|
|
424
|
+
--output-path ./dist/index.html \
|
|
425
|
+
--head-components "./src/client/ssr/head/Seo.js,./src/client/ssr/head/Pwa.js" \
|
|
426
|
+
--body-components "./src/client/ssr/body/Header.js,./src/client/ssr/body/Footer.js"
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Advanced Examples
|
|
432
|
+
|
|
433
|
+
### Example 1: Landing Page with Analytics
|
|
434
|
+
|
|
435
|
+
```json
|
|
436
|
+
{
|
|
437
|
+
"page": "./src/client/ssr/body/LandingPage.js",
|
|
438
|
+
"outputPath": "./dist/landing.html",
|
|
439
|
+
"env": "production",
|
|
440
|
+
"metadata": {
|
|
441
|
+
"title": "Welcome to Our Product",
|
|
442
|
+
"description": "The best product for your needs",
|
|
443
|
+
"keywords": ["product", "solution", "innovation"],
|
|
444
|
+
"themeColor": "#007bff",
|
|
445
|
+
"canonicalURL": "https://product.com/landing"
|
|
446
|
+
},
|
|
447
|
+
"scripts": {
|
|
448
|
+
"head": [
|
|
449
|
+
{
|
|
450
|
+
"src": "https://www.googletagmanager.com/gtag/js?id=GA_ID",
|
|
451
|
+
"async": true
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"content": "window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','GA_ID');"
|
|
455
|
+
}
|
|
456
|
+
],
|
|
457
|
+
"body": [
|
|
458
|
+
{
|
|
459
|
+
"src": "/landing.js",
|
|
460
|
+
"defer": true
|
|
461
|
+
}
|
|
462
|
+
]
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Example 2: Documentation Site
|
|
468
|
+
|
|
469
|
+
```json
|
|
470
|
+
{
|
|
471
|
+
"page": "./src/client/ssr/body/DocsPage.js",
|
|
472
|
+
"outputPath": "./dist/docs/index.html",
|
|
473
|
+
"metadata": {
|
|
474
|
+
"title": "Documentation - My API",
|
|
475
|
+
"description": "Complete API documentation",
|
|
476
|
+
"author": "API Team"
|
|
477
|
+
},
|
|
478
|
+
"headComponents": [
|
|
479
|
+
"./src/client/ssr/head/Seo.js",
|
|
480
|
+
"./src/client/ssr/head/DocsStyles.js"
|
|
481
|
+
],
|
|
482
|
+
"styles": [
|
|
483
|
+
{
|
|
484
|
+
"href": "/docs/prism.css"
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"href": "/docs/docs.css"
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
"scripts": {
|
|
491
|
+
"body": [
|
|
492
|
+
{
|
|
493
|
+
"src": "/docs/prism.js",
|
|
494
|
+
"defer": true
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Example 3: E-commerce Product Page
|
|
502
|
+
|
|
503
|
+
```json
|
|
504
|
+
{
|
|
505
|
+
"page": "./src/client/ssr/body/ProductPage.js",
|
|
506
|
+
"outputPath": "./dist/product.html",
|
|
507
|
+
"metadata": {
|
|
508
|
+
"title": "Premium Widget - Buy Now",
|
|
509
|
+
"description": "High-quality premium widget with free shipping",
|
|
510
|
+
"thumbnail": "https://shop.com/products/widget/image.jpg",
|
|
511
|
+
"openGraph": {
|
|
512
|
+
"type": "product",
|
|
513
|
+
"price:amount": "29.99",
|
|
514
|
+
"price:currency": "USD"
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
"microdata": [
|
|
518
|
+
{
|
|
519
|
+
"@context": "https://schema.org",
|
|
520
|
+
"@type": "Product",
|
|
521
|
+
"name": "Premium Widget",
|
|
522
|
+
"image": "https://shop.com/products/widget/image.jpg",
|
|
523
|
+
"description": "High-quality premium widget",
|
|
524
|
+
"offers": {
|
|
525
|
+
"@type": "Offer",
|
|
526
|
+
"price": "29.99",
|
|
527
|
+
"priceCurrency": "USD",
|
|
528
|
+
"availability": "https://schema.org/InStock"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Example 4: Multi-language Site
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
# Generate English version
|
|
539
|
+
underpost static \
|
|
540
|
+
--config-file ./config-en.json \
|
|
541
|
+
--output-path ./dist/en/index.html \
|
|
542
|
+
--lang en \
|
|
543
|
+
--dir ltr
|
|
544
|
+
|
|
545
|
+
# Generate Arabic version
|
|
546
|
+
underpost static \
|
|
547
|
+
--config-file ./config-ar.json \
|
|
548
|
+
--output-path ./dist/ar/index.html \
|
|
549
|
+
--lang ar \
|
|
550
|
+
--dir rtl
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Best Practices
|
|
556
|
+
|
|
557
|
+
### 1. SEO Optimization
|
|
558
|
+
|
|
559
|
+
- Always include `title`, `description`, and `keywords`
|
|
560
|
+
- Use canonical URLs to avoid duplicate content
|
|
561
|
+
- Add structured data (JSON-LD) for rich snippets
|
|
562
|
+
- Include Open Graph and Twitter Card metadata
|
|
563
|
+
|
|
564
|
+
```json
|
|
565
|
+
{
|
|
566
|
+
"metadata": {
|
|
567
|
+
"title": "Unique, descriptive title",
|
|
568
|
+
"description": "150-160 character description",
|
|
569
|
+
"keywords": ["relevant", "keywords"],
|
|
570
|
+
"canonicalURL": "https://example.com/page"
|
|
571
|
+
},
|
|
572
|
+
"microdata": [
|
|
573
|
+
{
|
|
574
|
+
"@context": "https://schema.org",
|
|
575
|
+
"@type": "WebPage",
|
|
576
|
+
"name": "Page Name"
|
|
577
|
+
}
|
|
578
|
+
]
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### 2. Performance
|
|
583
|
+
|
|
584
|
+
- Minify HTML in production (`minify: true`)
|
|
585
|
+
- Use `async` or `defer` for scripts
|
|
586
|
+
- Inline critical CSS
|
|
587
|
+
- Optimize images referenced in metadata
|
|
588
|
+
|
|
589
|
+
```json
|
|
590
|
+
{
|
|
591
|
+
"env": "production",
|
|
592
|
+
"minify": true,
|
|
593
|
+
"scripts": {
|
|
594
|
+
"head": [
|
|
595
|
+
{ "src": "/analytics.js", "async": true }
|
|
596
|
+
],
|
|
597
|
+
"body": [
|
|
598
|
+
{ "src": "/app.js", "defer": true }
|
|
599
|
+
]
|
|
600
|
+
},
|
|
601
|
+
"styles": [
|
|
602
|
+
{ "content": "/* Critical CSS */" },
|
|
603
|
+
{ "href": "/main.css" }
|
|
604
|
+
]
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 3. Progressive Web Apps
|
|
609
|
+
|
|
610
|
+
- Include web manifest
|
|
611
|
+
- Add various icon sizes
|
|
612
|
+
- Set theme color
|
|
613
|
+
- Register service worker
|
|
614
|
+
|
|
615
|
+
```json
|
|
616
|
+
{
|
|
617
|
+
"icons": {
|
|
618
|
+
"favicon": "/favicon.ico",
|
|
619
|
+
"manifest": "/manifest.json"
|
|
620
|
+
},
|
|
621
|
+
"metadata": {
|
|
622
|
+
"themeColor": "#007bff"
|
|
623
|
+
},
|
|
624
|
+
"scripts": {
|
|
625
|
+
"body": [
|
|
626
|
+
{
|
|
627
|
+
"content": "if('serviceWorker' in navigator){navigator.serviceWorker.register('/sw.js');}"
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### 4. Security
|
|
635
|
+
|
|
636
|
+
- Use Subresource Integrity (SRI) for external resources
|
|
637
|
+
- Set appropriate CORS headers
|
|
638
|
+
- Validate all user inputs in custom payloads
|
|
639
|
+
|
|
640
|
+
```json
|
|
641
|
+
{
|
|
642
|
+
"scripts": {
|
|
643
|
+
"head": [
|
|
644
|
+
{
|
|
645
|
+
"src": "https://cdn.example.com/lib.js",
|
|
646
|
+
"integrity": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC",
|
|
647
|
+
"crossorigin": "anonymous"
|
|
648
|
+
}
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### 5. Configuration Management
|
|
655
|
+
|
|
656
|
+
- Use config files for complex setups
|
|
657
|
+
- Version control your config files
|
|
658
|
+
- Create environment-specific configs
|
|
659
|
+
- Document custom configurations
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
# Development
|
|
663
|
+
underpost static --config-file ./config.dev.json
|
|
664
|
+
|
|
665
|
+
# Production
|
|
666
|
+
underpost static --config-file ./config.prod.json
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### 6. Component Reusability
|
|
670
|
+
|
|
671
|
+
Create reusable SSR components for common patterns:
|
|
672
|
+
|
|
673
|
+
```javascript
|
|
674
|
+
// src/client/ssr/head/Analytics.js
|
|
675
|
+
SrrComponent = ({ gaId }) => html`
|
|
676
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=${gaId}"></script>
|
|
677
|
+
<script>
|
|
678
|
+
window.dataLayer = window.dataLayer || [];
|
|
679
|
+
function gtag(){dataLayer.push(arguments);}
|
|
680
|
+
gtag('js', new Date());
|
|
681
|
+
gtag('config', '${gaId}');
|
|
682
|
+
</script>
|
|
683
|
+
`;
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
## API Reference
|
|
689
|
+
|
|
690
|
+
### JavaScript API
|
|
691
|
+
|
|
692
|
+
```javascript
|
|
693
|
+
import UnderpostStatic from './src/cli/static.js';
|
|
694
|
+
|
|
695
|
+
// Generate static page programmatically
|
|
696
|
+
await UnderpostStatic.API.callback({
|
|
697
|
+
page: './src/client/ssr/body/Page.js',
|
|
698
|
+
outputPath: './dist/index.html',
|
|
699
|
+
metadata: { /* ... */ },
|
|
700
|
+
// ... other options
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// Generate config template
|
|
704
|
+
UnderpostStatic.API.generateConfigTemplate('./my-config.json');
|
|
705
|
+
|
|
706
|
+
// Use helper functions
|
|
707
|
+
import { TemplateHelpers } from './src/cli/static.js';
|
|
708
|
+
|
|
709
|
+
const scriptTag = TemplateHelpers.createScriptTag({
|
|
710
|
+
src: '/app.js',
|
|
711
|
+
defer: true
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
const metaTags = TemplateHelpers.createMetaTags({
|
|
715
|
+
title: 'My Page',
|
|
716
|
+
description: 'Description'
|
|
717
|
+
});
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Template Helpers
|
|
721
|
+
|
|
722
|
+
- `TemplateHelpers.createScriptTag(options)` - Generate script tags
|
|
723
|
+
- `TemplateHelpers.createStyleTag(options)` - Generate style/link tags
|
|
724
|
+
- `TemplateHelpers.createIconTags(icons)` - Generate icon link tags
|
|
725
|
+
- `TemplateHelpers.createMetaTags(metadata)` - Generate meta tags
|
|
726
|
+
- `TemplateHelpers.createMicrodataTags(microdata)` - Generate JSON-LD tags
|
|
727
|
+
|
|
728
|
+
### Config Validator
|
|
729
|
+
|
|
730
|
+
```javascript
|
|
731
|
+
import { ConfigValidator } from './src/cli/static.js';
|
|
732
|
+
|
|
733
|
+
const result = ConfigValidator.validate(options);
|
|
734
|
+
if (!result.isValid) {
|
|
735
|
+
console.error('Validation errors:', result.errors);
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
### Config Loader
|
|
740
|
+
|
|
741
|
+
```javascript
|
|
742
|
+
import { ConfigLoader } from './src/cli/static.js';
|
|
743
|
+
|
|
744
|
+
// Load config
|
|
745
|
+
const config = ConfigLoader.load('./config.json');
|
|
746
|
+
|
|
747
|
+
// Save config
|
|
748
|
+
ConfigLoader.save('./config.json', configObject);
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
## Troubleshooting
|
|
754
|
+
|
|
755
|
+
### Common Issues
|
|
756
|
+
|
|
757
|
+
**Issue: Component not found**
|
|
758
|
+
```
|
|
759
|
+
Error: Page component does not exist: ./src/client/ssr/body/Missing.js
|
|
760
|
+
```
|
|
761
|
+
**Solution:** Verify the path to your SSR component file.
|
|
762
|
+
|
|
763
|
+
**Issue: Output directory doesn't exist**
|
|
764
|
+
```
|
|
765
|
+
Error: Output directory does not exist: ./dist/pages
|
|
766
|
+
```
|
|
767
|
+
**Solution:** Create the directory first or use a different output path.
|
|
768
|
+
|
|
769
|
+
**Issue: Invalid JSON in config file**
|
|
770
|
+
```
|
|
771
|
+
Error: Error loading config file: Unexpected token
|
|
772
|
+
```
|
|
773
|
+
**Solution:** Validate your JSON syntax using a linter.
|
|
774
|
+
|
|
775
|
+
### Debug Mode
|
|
776
|
+
|
|
777
|
+
Use `--dev` flag for development mode with additional logging:
|
|
778
|
+
|
|
779
|
+
```bash
|
|
780
|
+
underpost static --config-file ./config.json --dev
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
## Examples Repository
|
|
786
|
+
|
|
787
|
+
See the `examples/` directory for complete working examples:
|
|
788
|
+
|
|
789
|
+
- `static-config-example.json` - Comprehensive configuration example
|
|
790
|
+
- Additional examples coming soon
|
|
791
|
+
|
|
792
|
+
---
|
|
793
|
+
|
|
794
|
+
## Contributing
|
|
795
|
+
|
|
796
|
+
To contribute improvements to the static generator:
|
|
797
|
+
|
|
798
|
+
1. Add new features to `src/cli/static.js`
|
|
799
|
+
2. Update this documentation
|
|
800
|
+
3. Add examples to the `examples/` directory
|
|
801
|
+
4. Include JSDoc comments for all new functions
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## License
|
|
806
|
+
|
|
807
|
+
This is part of the Underpost framework. See main project license.
|