@uniweb/build 0.1.1 → 0.1.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/README.md +189 -11
- package/package.json +25 -5
- package/src/dev/index.js +9 -0
- package/src/dev/plugin.js +206 -0
- package/src/images.js +5 -3
- package/src/index.js +5 -0
- package/src/prerender.js +310 -0
- package/src/site/advanced-processors.js +393 -0
- package/src/site/asset-processor.js +281 -0
- package/src/site/assets.js +247 -0
- package/src/site/content-collector.js +344 -0
- package/src/site/index.js +32 -0
- package/src/site/plugin.js +497 -0
- package/src/vite-foundation-plugin.js +7 -3
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @uniweb/build
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build tooling for the Uniweb Component Web Platform.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
This package provides
|
|
7
|
+
This package provides Vite plugins and utilities for building both **Foundations** (component libraries) and **Sites** (content-driven websites).
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -14,17 +14,23 @@ npm install @uniweb/build --save-dev
|
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
|
+
**For Foundations:**
|
|
17
18
|
- **Component Discovery** - Automatically discovers components from `src/components/*/meta.js`
|
|
18
19
|
- **Entry Generation** - Generates the foundation entry point with all exports
|
|
19
20
|
- **Schema Building** - Creates `schema.json` with full component metadata for editors
|
|
20
|
-
- **Image Processing** - Converts preview images to WebP format
|
|
21
|
+
- **Image Processing** - Converts preview images to WebP format
|
|
21
22
|
- **Vite Plugin** - Integrates seamlessly with Vite builds
|
|
22
23
|
|
|
24
|
+
**For Sites:**
|
|
25
|
+
- **Content Collection** - Collects pages from `pages/` directory with YAML/Markdown
|
|
26
|
+
- **Dev Server Integration** - Watches for content changes with hot reload
|
|
27
|
+
- **Foundation Dev Server** - Serves a local foundation during development
|
|
28
|
+
|
|
23
29
|
## Usage
|
|
24
30
|
|
|
25
|
-
###
|
|
31
|
+
### Foundation Plugin
|
|
26
32
|
|
|
27
|
-
Add the foundation plugin to your `vite.config.js`:
|
|
33
|
+
Add the foundation plugin to your foundation's `vite.config.js`:
|
|
28
34
|
|
|
29
35
|
```js
|
|
30
36
|
import { defineConfig } from 'vite'
|
|
@@ -49,6 +55,165 @@ export default defineConfig({
|
|
|
49
55
|
})
|
|
50
56
|
```
|
|
51
57
|
|
|
58
|
+
### Site Plugins
|
|
59
|
+
|
|
60
|
+
For sites, use the content and dev plugins in your site's `vite.config.js`:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
import { defineConfig } from 'vite'
|
|
64
|
+
import react from '@vitejs/plugin-react'
|
|
65
|
+
import { siteContentPlugin } from '@uniweb/build/site'
|
|
66
|
+
import { foundationDevPlugin } from '@uniweb/build/dev'
|
|
67
|
+
|
|
68
|
+
export default defineConfig({
|
|
69
|
+
plugins: [
|
|
70
|
+
react(),
|
|
71
|
+
|
|
72
|
+
// Collect content from pages/ directory
|
|
73
|
+
siteContentPlugin({
|
|
74
|
+
sitePath: './',
|
|
75
|
+
inject: true, // Inject into HTML
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
// Serve local foundation during development
|
|
79
|
+
foundationDevPlugin({
|
|
80
|
+
path: '../foundation',
|
|
81
|
+
serve: '/foundation',
|
|
82
|
+
}),
|
|
83
|
+
]
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### Site Content Plugin Options
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
siteContentPlugin({
|
|
91
|
+
sitePath: './', // Path to site directory
|
|
92
|
+
pagesDir: 'pages', // Pages subdirectory name
|
|
93
|
+
inject: true, // Inject content into HTML
|
|
94
|
+
filename: 'site-content.json', // Output filename
|
|
95
|
+
watch: true, // Watch for changes (dev mode)
|
|
96
|
+
seo: { // SEO configuration (optional)
|
|
97
|
+
baseUrl: 'https://example.com',
|
|
98
|
+
defaultImage: '/og-image.png',
|
|
99
|
+
twitterHandle: '@example',
|
|
100
|
+
locales: [
|
|
101
|
+
{ code: 'en', default: true },
|
|
102
|
+
{ code: 'es' }
|
|
103
|
+
],
|
|
104
|
+
robots: {
|
|
105
|
+
disallow: ['/admin', '/api'],
|
|
106
|
+
crawlDelay: 1
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
assets: { // Asset processing (optional)
|
|
110
|
+
process: true, // Process assets in production (default: true)
|
|
111
|
+
convertToWebp: true, // Convert images to WebP (default: true)
|
|
112
|
+
quality: 80, // WebP quality 1-100 (default: 80)
|
|
113
|
+
outputDir: 'assets', // Output subdirectory (default: 'assets')
|
|
114
|
+
videoPosters: true, // Extract poster from videos (default: true, requires ffmpeg)
|
|
115
|
+
pdfThumbnails: true // Generate PDF thumbnails (default: true, requires pdf-lib)
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### SEO Features
|
|
121
|
+
|
|
122
|
+
When `seo.baseUrl` is provided, the plugin generates:
|
|
123
|
+
|
|
124
|
+
**sitemap.xml** - Auto-generated from collected pages with:
|
|
125
|
+
- Last modified dates from file timestamps
|
|
126
|
+
- Per-page `changefreq` and `priority` from page frontmatter
|
|
127
|
+
- Hreflang entries for multi-locale sites
|
|
128
|
+
|
|
129
|
+
**robots.txt** - Generated with sitemap reference and optional rules
|
|
130
|
+
|
|
131
|
+
**Meta Tags** - Injected into HTML `<head>`:
|
|
132
|
+
- Open Graph tags (`og:title`, `og:description`, `og:image`, etc.)
|
|
133
|
+
- Twitter Card tags (`twitter:card`, `twitter:site`, etc.)
|
|
134
|
+
- Canonical URL
|
|
135
|
+
- Hreflang links for multi-locale sites
|
|
136
|
+
|
|
137
|
+
**Page-level SEO** - Configure in `page.yml`:
|
|
138
|
+
```yaml
|
|
139
|
+
title: About Us
|
|
140
|
+
description: Learn about our company
|
|
141
|
+
seo:
|
|
142
|
+
noindex: false # Exclude from sitemap
|
|
143
|
+
image: /about-og.png # Page-specific OG image
|
|
144
|
+
changefreq: monthly # Sitemap changefreq
|
|
145
|
+
priority: 0.8 # Sitemap priority
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Asset Processing
|
|
149
|
+
|
|
150
|
+
The plugin automatically discovers and processes assets referenced in your content. In content-driven sites, markdown acts as "code" - local asset references are like implicit imports and get optimized during build.
|
|
151
|
+
|
|
152
|
+
**Supported path formats:**
|
|
153
|
+
- `./image.png` - Relative to the markdown file
|
|
154
|
+
- `../shared/logo.png` - Relative paths with parent traversal
|
|
155
|
+
- `/images/hero.png` - Absolute paths (resolved from `public/` or `assets/` folder)
|
|
156
|
+
|
|
157
|
+
**What gets processed:**
|
|
158
|
+
- Images in markdown content: ``
|
|
159
|
+
- Media in frontmatter fields: `background`, `image`, `thumbnail`, `poster`, `avatar`, `logo`, `icon`, `video`, `pdf`, etc.
|
|
160
|
+
|
|
161
|
+
**Image processing:**
|
|
162
|
+
- PNG, JPG, JPEG, GIF → Converted to WebP for smaller file sizes
|
|
163
|
+
- SVG, WebP, AVIF → Copied as-is (already optimized formats)
|
|
164
|
+
- All processed assets get content-hashed filenames for cache busting
|
|
165
|
+
|
|
166
|
+
**Video poster extraction** (requires `ffmpeg` on system):
|
|
167
|
+
- MP4, WebM, MOV, AVI, MKV → Poster frame extracted at 1 second
|
|
168
|
+
- Poster images converted to WebP and added to `_assetMeta.posters`
|
|
169
|
+
- Skipped if an explicit `poster` attribute is provided in markdown
|
|
170
|
+
|
|
171
|
+
**PDF thumbnail generation** (requires `pdf-lib` package):
|
|
172
|
+
- PDF files → Placeholder thumbnail with page count
|
|
173
|
+
- Thumbnails added to `_assetMeta.thumbnails`
|
|
174
|
+
- Skipped if an explicit `preview` attribute is provided in markdown
|
|
175
|
+
|
|
176
|
+
**Explicit poster/preview images:**
|
|
177
|
+
|
|
178
|
+
When you provide explicit `poster` or `preview` attributes in your markdown, those images are collected and optimized alongside other assets:
|
|
179
|
+
|
|
180
|
+
```markdown
|
|
181
|
+
{role=video poster=./custom-poster.jpg}
|
|
182
|
+
{role=pdf preview=./guide-preview.png}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- The explicit images (`./custom-poster.jpg`, `./guide-preview.png`) are processed and optimized
|
|
186
|
+
- Auto-generation via ffmpeg/pdf-lib is skipped for these files
|
|
187
|
+
- This gives you full control over preview images while still benefiting from optimization
|
|
188
|
+
|
|
189
|
+
**Build output:**
|
|
190
|
+
```
|
|
191
|
+
dist/
|
|
192
|
+
├── assets/
|
|
193
|
+
│ ├── hero-a1b2c3d4.webp # Converted from hero.jpg
|
|
194
|
+
│ ├── logo-e5f6g7h8.svg # Copied as-is
|
|
195
|
+
│ ├── intro-poster-9i0j1k2l.webp # Video poster frame
|
|
196
|
+
│ └── guide-thumb-3m4n5o6p.webp # PDF thumbnail
|
|
197
|
+
└── site-content.json # Paths rewritten, _assetMeta included
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Graceful degradation:**
|
|
201
|
+
- If `ffmpeg` is not installed, video posters are silently skipped
|
|
202
|
+
- If `pdf-lib` is not installed, PDF thumbnails are silently skipped
|
|
203
|
+
- Missing assets are logged as warnings but don't fail the build
|
|
204
|
+
|
|
205
|
+
#### Foundation Dev Plugin Options
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
foundationDevPlugin({
|
|
209
|
+
name: 'foundation', // Name for logging
|
|
210
|
+
path: '../foundation', // Path to foundation package
|
|
211
|
+
serve: '/foundation', // URL path to serve from
|
|
212
|
+
watch: true, // Watch for source changes
|
|
213
|
+
buildOnStart: true // Build when dev server starts
|
|
214
|
+
})
|
|
215
|
+
```
|
|
216
|
+
|
|
52
217
|
### Programmatic API
|
|
53
218
|
|
|
54
219
|
```js
|
|
@@ -161,10 +326,11 @@ After building, your foundation will contain:
|
|
|
161
326
|
dist/
|
|
162
327
|
├── foundation.js # Bundled components (~6KB typical)
|
|
163
328
|
├── foundation.js.map # Source map
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
└──
|
|
167
|
-
└──
|
|
329
|
+
└── meta/ # Editor metadata (not needed at runtime)
|
|
330
|
+
├── schema.json # Full component metadata for editors
|
|
331
|
+
└── previews/ # Preset preview images
|
|
332
|
+
└── Hero/
|
|
333
|
+
└── default.webp
|
|
168
334
|
```
|
|
169
335
|
|
|
170
336
|
## API Reference
|
|
@@ -194,16 +360,28 @@ dist/
|
|
|
194
360
|
|
|
195
361
|
### Vite Plugins
|
|
196
362
|
|
|
363
|
+
**Foundation plugins** (`@uniweb/build`):
|
|
364
|
+
|
|
197
365
|
| Plugin | Description |
|
|
198
366
|
|--------|-------------|
|
|
199
367
|
| `foundationPlugin(options)` | Combined dev + build plugin |
|
|
200
368
|
| `foundationBuildPlugin(options)` | Build-only plugin |
|
|
201
369
|
| `foundationDevPlugin(options)` | Dev-only plugin with HMR |
|
|
202
370
|
|
|
371
|
+
**Site plugins** (`@uniweb/build/site` and `@uniweb/build/dev`):
|
|
372
|
+
|
|
373
|
+
| Plugin | Description |
|
|
374
|
+
|--------|-------------|
|
|
375
|
+
| `siteContentPlugin(options)` | Collect and inject site content |
|
|
376
|
+
| `collectSiteContent(sitePath)` | Programmatic content collection |
|
|
377
|
+
| `foundationDevPlugin(options)` | Serve foundation during site dev |
|
|
378
|
+
|
|
203
379
|
## Related Packages
|
|
204
380
|
|
|
205
|
-
- [
|
|
206
|
-
- [`@uniweb/
|
|
381
|
+
- [`@uniweb/core`](https://github.com/uniweb/core) - Core classes (Uniweb, Website, Block)
|
|
382
|
+
- [`@uniweb/kit`](https://github.com/uniweb/kit) - Component library for foundations
|
|
383
|
+
- [`@uniweb/runtime`](https://github.com/uniweb/runtime) - Browser runtime for sites
|
|
384
|
+
- [`uniweb`](https://github.com/uniweb/cli) - CLI for creating projects
|
|
207
385
|
|
|
208
386
|
## License
|
|
209
387
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.js",
|
|
8
8
|
"./schema": "./src/schema.js",
|
|
9
9
|
"./images": "./src/images.js",
|
|
10
10
|
"./generate-entry": "./src/generate-entry.js",
|
|
11
|
-
"./vite-plugin": "./src/vite-foundation-plugin.js"
|
|
11
|
+
"./vite-plugin": "./src/vite-foundation-plugin.js",
|
|
12
|
+
"./site": "./src/site/index.js",
|
|
13
|
+
"./dev": "./src/dev/index.js",
|
|
14
|
+
"./prerender": "./src/prerender.js"
|
|
12
15
|
},
|
|
13
16
|
"files": [
|
|
14
17
|
"src"
|
|
@@ -16,6 +19,7 @@
|
|
|
16
19
|
"keywords": [
|
|
17
20
|
"uniweb",
|
|
18
21
|
"foundation",
|
|
22
|
+
"site",
|
|
19
23
|
"build",
|
|
20
24
|
"vite",
|
|
21
25
|
"components"
|
|
@@ -31,17 +35,33 @@
|
|
|
31
35
|
"url": "https://github.com/uniweb/build/issues"
|
|
32
36
|
},
|
|
33
37
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
38
|
+
"node": ">=20.19"
|
|
35
39
|
},
|
|
36
40
|
"dependencies": {
|
|
41
|
+
"js-yaml": "^4.1.0",
|
|
37
42
|
"sharp": "^0.33.2"
|
|
38
43
|
},
|
|
44
|
+
"optionalDependencies": {
|
|
45
|
+
"@uniweb/content-reader": "1.0.2"
|
|
46
|
+
},
|
|
39
47
|
"peerDependencies": {
|
|
40
|
-
"vite": "^5.0.0 || ^6.0.0"
|
|
48
|
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
49
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
50
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
51
|
+
"@uniweb/core": "0.1.2"
|
|
41
52
|
},
|
|
42
53
|
"peerDependenciesMeta": {
|
|
43
54
|
"vite": {
|
|
44
55
|
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"react": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"react-dom": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@uniweb/core": {
|
|
64
|
+
"optional": true
|
|
45
65
|
}
|
|
46
66
|
}
|
|
47
67
|
}
|
package/src/dev/index.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite Plugin: Foundation Dev Server
|
|
3
|
+
*
|
|
4
|
+
* Builds and serves a foundation within the site's dev server.
|
|
5
|
+
* This enables a single dev server for both site and foundation development.
|
|
6
|
+
*
|
|
7
|
+
* @module @uniweb/build/dev
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { foundationDevPlugin } from '@uniweb/build/dev'
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* plugins: [
|
|
14
|
+
* foundationDevPlugin({
|
|
15
|
+
* name: 'my-foundation',
|
|
16
|
+
* path: '../my-foundation', // Path to foundation package
|
|
17
|
+
* serve: '/foundation', // URL path to serve from
|
|
18
|
+
* })
|
|
19
|
+
* ]
|
|
20
|
+
* })
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { resolve, join } from 'node:path'
|
|
24
|
+
import { watch } from 'node:fs'
|
|
25
|
+
import { readFile } from 'node:fs/promises'
|
|
26
|
+
import { existsSync } from 'node:fs'
|
|
27
|
+
import { build } from 'vite'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create the foundation dev plugin
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} options
|
|
33
|
+
* @param {string} [options.name='foundation'] - Foundation name (for logging)
|
|
34
|
+
* @param {string} [options.path='../foundation'] - Path to foundation package
|
|
35
|
+
* @param {string} [options.serve='/foundation'] - URL path to serve from
|
|
36
|
+
* @param {boolean} [options.watch=true] - Watch for source changes
|
|
37
|
+
* @param {boolean} [options.buildOnStart=true] - Build on server start
|
|
38
|
+
*/
|
|
39
|
+
export function foundationDevPlugin(options = {}) {
|
|
40
|
+
const {
|
|
41
|
+
name = 'foundation',
|
|
42
|
+
path: foundationPath = '../foundation',
|
|
43
|
+
serve: servePath = '/foundation',
|
|
44
|
+
watch: shouldWatch = true,
|
|
45
|
+
buildOnStart = true
|
|
46
|
+
} = options
|
|
47
|
+
|
|
48
|
+
let resolvedFoundationPath = null
|
|
49
|
+
let resolvedDistPath = null
|
|
50
|
+
let server = null
|
|
51
|
+
let watcher = null
|
|
52
|
+
let isBuilding = false
|
|
53
|
+
let lastBuildTime = 0
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build the foundation using Vite
|
|
57
|
+
*/
|
|
58
|
+
async function buildFoundation() {
|
|
59
|
+
if (isBuilding) return
|
|
60
|
+
isBuilding = true
|
|
61
|
+
|
|
62
|
+
const startTime = Date.now()
|
|
63
|
+
console.log(`[foundation] Building ${name}...`)
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
// Use Vite's native config loading by specifying configFile
|
|
67
|
+
const configPath = join(resolvedFoundationPath, 'vite.config.js')
|
|
68
|
+
|
|
69
|
+
// Build using Vite with the foundation's own config file
|
|
70
|
+
await build({
|
|
71
|
+
root: resolvedFoundationPath,
|
|
72
|
+
configFile: existsSync(configPath) ? configPath : false,
|
|
73
|
+
logLevel: 'warn',
|
|
74
|
+
build: {
|
|
75
|
+
outDir: 'dist',
|
|
76
|
+
emptyOutDir: true,
|
|
77
|
+
watch: null // Don't use Vite's watch, we handle it ourselves
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
lastBuildTime = Date.now()
|
|
82
|
+
console.log(`[foundation] Built ${name} in ${lastBuildTime - startTime}ms`)
|
|
83
|
+
|
|
84
|
+
// Trigger HMR reload if server is running
|
|
85
|
+
if (server) {
|
|
86
|
+
server.ws.send({ type: 'full-reload' })
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error(`[foundation] Build failed:`, err.message)
|
|
90
|
+
} finally {
|
|
91
|
+
isBuilding = false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
name: 'uniweb:foundation-dev',
|
|
97
|
+
// Run before other plugins to intercept foundation requests
|
|
98
|
+
enforce: 'pre',
|
|
99
|
+
|
|
100
|
+
configResolved(config) {
|
|
101
|
+
resolvedFoundationPath = resolve(config.root, foundationPath)
|
|
102
|
+
resolvedDistPath = join(resolvedFoundationPath, 'dist')
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
async buildStart() {
|
|
106
|
+
if (buildOnStart) {
|
|
107
|
+
await buildFoundation()
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
configureServer(devServer) {
|
|
112
|
+
server = devServer
|
|
113
|
+
|
|
114
|
+
// Serve foundation files via middleware
|
|
115
|
+
// For JS files, use Vite's transform pipeline to properly resolve imports
|
|
116
|
+
devServer.middlewares.use(async (req, res, next) => {
|
|
117
|
+
const urlPath = req.url.split('?')[0]
|
|
118
|
+
|
|
119
|
+
if (!urlPath.startsWith(servePath)) {
|
|
120
|
+
return next()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const filePath = urlPath.slice(servePath.length) || '/foundation.js'
|
|
124
|
+
const fullPath = join(resolvedDistPath, filePath)
|
|
125
|
+
|
|
126
|
+
if (!existsSync(fullPath)) {
|
|
127
|
+
return next()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
let content = await readFile(fullPath, 'utf-8')
|
|
132
|
+
let contentType = 'application/octet-stream'
|
|
133
|
+
|
|
134
|
+
if (filePath.endsWith('.js')) {
|
|
135
|
+
contentType = 'application/javascript'
|
|
136
|
+
|
|
137
|
+
// Use Vite's transform pipeline to resolve bare imports
|
|
138
|
+
// This properly handles React ESM/CJS interop
|
|
139
|
+
const result = await devServer.transformRequest(`/@fs${fullPath}`, {
|
|
140
|
+
html: false
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (result) {
|
|
144
|
+
content = result.code
|
|
145
|
+
}
|
|
146
|
+
} else if (filePath.endsWith('.css')) {
|
|
147
|
+
contentType = 'text/css'
|
|
148
|
+
} else if (filePath.endsWith('.json')) {
|
|
149
|
+
contentType = 'application/json'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
res.setHeader('Content-Type', contentType)
|
|
153
|
+
res.setHeader('Cache-Control', 'no-cache')
|
|
154
|
+
res.setHeader('Access-Control-Allow-Origin', '*')
|
|
155
|
+
res.end(content)
|
|
156
|
+
} catch (err) {
|
|
157
|
+
next(err)
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
// Watch foundation source for changes
|
|
162
|
+
if (shouldWatch) {
|
|
163
|
+
const srcPath = join(resolvedFoundationPath, 'src')
|
|
164
|
+
|
|
165
|
+
// Debounce rebuilds
|
|
166
|
+
let rebuildTimeout = null
|
|
167
|
+
const scheduleRebuild = () => {
|
|
168
|
+
if (rebuildTimeout) clearTimeout(rebuildTimeout)
|
|
169
|
+
rebuildTimeout = setTimeout(() => {
|
|
170
|
+
buildFoundation()
|
|
171
|
+
}, 200)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
watcher = watch(srcPath, { recursive: true }, (eventType, filename) => {
|
|
176
|
+
// Ignore non-source files
|
|
177
|
+
if (
|
|
178
|
+
filename &&
|
|
179
|
+
(filename.endsWith('.js') ||
|
|
180
|
+
filename.endsWith('.jsx') ||
|
|
181
|
+
filename.endsWith('.ts') ||
|
|
182
|
+
filename.endsWith('.tsx') ||
|
|
183
|
+
filename.endsWith('.css') ||
|
|
184
|
+
filename.endsWith('.svg'))
|
|
185
|
+
) {
|
|
186
|
+
console.log(`[foundation] ${filename} changed`)
|
|
187
|
+
scheduleRebuild()
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
console.log(`[foundation] Watching ${srcPath}`)
|
|
191
|
+
} catch (err) {
|
|
192
|
+
console.warn(`[foundation] Could not watch source:`, err.message)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
closeBundle() {
|
|
198
|
+
if (watcher) {
|
|
199
|
+
watcher.close()
|
|
200
|
+
watcher = null
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export default foundationDevPlugin
|
package/src/images.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Image Processing Utilities
|
|
3
3
|
*
|
|
4
4
|
* Handles preview image discovery, conversion to webp, and metadata extraction.
|
|
5
|
+
* Preview images are editor metadata (for preset visualization) and are output
|
|
6
|
+
* to dist/meta/previews/ to keep them separate from runtime assets.
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
import { readdir, mkdir, copyFile } from 'node:fs/promises'
|
|
@@ -71,8 +73,8 @@ export async function processComponentPreviews(componentDir, componentName, outp
|
|
|
71
73
|
return previews
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
// Create output directory
|
|
75
|
-
const componentOutputDir = join(outputDir, '
|
|
76
|
+
// Create output directory for preview images (editor metadata)
|
|
77
|
+
const componentOutputDir = join(outputDir, 'meta', 'previews', componentName)
|
|
76
78
|
await mkdir(componentOutputDir, { recursive: true })
|
|
77
79
|
|
|
78
80
|
// Get all image files
|
|
@@ -115,7 +117,7 @@ export async function processComponentPreviews(componentDir, componentName, outp
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
previews[presetName] = {
|
|
118
|
-
path: `
|
|
120
|
+
path: `meta/previews/${componentName}/${outputFilename}`,
|
|
119
121
|
width: metadata.width,
|
|
120
122
|
height: metadata.height,
|
|
121
123
|
type: finalFormat,
|
package/src/index.js
CHANGED
|
@@ -35,5 +35,10 @@ export {
|
|
|
35
35
|
foundationDevPlugin,
|
|
36
36
|
} from './vite-foundation-plugin.js'
|
|
37
37
|
|
|
38
|
+
// SSG Prerendering
|
|
39
|
+
export {
|
|
40
|
+
prerenderSite,
|
|
41
|
+
} from './prerender.js'
|
|
42
|
+
|
|
38
43
|
// Default export is the combined Vite plugin
|
|
39
44
|
export { default } from './vite-foundation-plugin.js'
|