vite-plugin-html-elements 0.0.9 β 0.1.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/README.md +224 -26
- package/dist/index.d.ts +34 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +77 -15
- package/package.json +34 -15
package/README.md
CHANGED
|
@@ -8,9 +8,11 @@ A lightweight Vite plugin for composing reusable HTML elements in static sites.
|
|
|
8
8
|
|
|
9
9
|
- **Zero JavaScript** - Pure static HTML output
|
|
10
10
|
- **Hot Reload** - Instant updates during development
|
|
11
|
-
- **Intuitive Syntax** - Natural self-closing `<element />` tags
|
|
12
|
-
- **
|
|
11
|
+
- **Intuitive Syntax** - Natural self-closing `<element />` tags with props and slots
|
|
12
|
+
- **Route Manifests** - Explicit control over URL structure
|
|
13
|
+
- **Deployment Ready** - Built-in base path support for subdirectory hosting
|
|
13
14
|
- **TypeScript** - Full type safety
|
|
15
|
+
- **Flexible** - Opinionated defaults or complete control
|
|
14
16
|
- **Tiny** - Minimal footprint, maximum impact
|
|
15
17
|
|
|
16
18
|
## π¦ Installation
|
|
@@ -91,7 +93,7 @@ npm run build # Production build
|
|
|
91
93
|
|
|
92
94
|
The output is pure static HTML with all elements inlined - no `<element>` tags remain.
|
|
93
95
|
|
|
94
|
-
## π Syntax
|
|
96
|
+
## π Basic Syntax
|
|
95
97
|
|
|
96
98
|
### Shorthand (Recommended)
|
|
97
99
|
|
|
@@ -107,8 +109,55 @@ Automatically resolves to `elements/header.html`
|
|
|
107
109
|
<element src="elements/nav/mobile.html" />
|
|
108
110
|
```
|
|
109
111
|
|
|
112
|
+
### With Slots
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<element src="card.html">
|
|
116
|
+
<h2>Card Title</h2>
|
|
117
|
+
<p>Card content goes here</p>
|
|
118
|
+
</element>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**src/elements/card.html:**
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<div class="card">
|
|
125
|
+
<slot />
|
|
126
|
+
</div>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### With Props
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<element src="hero.html" title="Welcome" subtitle="Build fast static sites">
|
|
133
|
+
<button>Get Started</button>
|
|
134
|
+
</element>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**src/elements/hero.html:**
|
|
138
|
+
|
|
139
|
+
```html
|
|
140
|
+
<section class="hero">
|
|
141
|
+
<h1>{{title}}</h1>
|
|
142
|
+
<p>{{subtitle}}</p>
|
|
143
|
+
<slot />
|
|
144
|
+
</section>
|
|
145
|
+
```
|
|
146
|
+
|
|
110
147
|
## βοΈ Configuration
|
|
111
148
|
|
|
149
|
+
### Basic Options
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface HtmlElementsOptions {
|
|
153
|
+
debug?: boolean; // Enable verbose logging (default: false)
|
|
154
|
+
basePath?: string; // Base path for deployment (default: '/')
|
|
155
|
+
srcDir?: string; // Source directory for HTML files (default: 'src')
|
|
156
|
+
defaults?: boolean; // Use opinionated structure (default: true)
|
|
157
|
+
routes?: RouteConfig[]; // Route manifest (optional)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
112
161
|
### Debug Mode
|
|
113
162
|
|
|
114
163
|
Enable verbose logging to see which elements are being included:
|
|
@@ -121,23 +170,115 @@ Output:
|
|
|
121
170
|
|
|
122
171
|
```
|
|
123
172
|
π§ Element included: elements/header.html
|
|
124
|
-
π§ Element included: elements/footer.html
|
|
173
|
+
π§ Element included: elements/footer.html (with slot)
|
|
174
|
+
πΊοΈ Route: /blog -> blog.html (output: blog/index.html)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Base Path
|
|
178
|
+
|
|
179
|
+
Deploy to a subdirectory (e.g., GitHub Pages):
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
htmlElements({
|
|
183
|
+
basePath: '/my-site',
|
|
184
|
+
});
|
|
125
185
|
```
|
|
126
186
|
|
|
187
|
+
All asset paths will be automatically prefixed with `/my-site`.
|
|
188
|
+
|
|
189
|
+
### Custom Source Directory
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
htmlElements({
|
|
193
|
+
srcDir: 'pages', // Look for HTML files in src/pages/
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Non-Opinionated Mode
|
|
198
|
+
|
|
199
|
+
Take full control over your Vite configuration:
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
export default defineConfig({
|
|
203
|
+
root: './',
|
|
204
|
+
publicDir: 'static',
|
|
205
|
+
build: { outDir: 'build' },
|
|
206
|
+
plugins: [
|
|
207
|
+
htmlElements({
|
|
208
|
+
defaults: false, // Disable opinionated defaults
|
|
209
|
+
srcDir: 'pages',
|
|
210
|
+
}),
|
|
211
|
+
],
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## πΊοΈ Route Manifests
|
|
216
|
+
|
|
217
|
+
Define explicit URL structures with route manifests:
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
htmlElements({
|
|
221
|
+
basePath: '/my-site',
|
|
222
|
+
routes: [
|
|
223
|
+
{ path: '/', source: 'index.html' },
|
|
224
|
+
{ path: '/blog', source: 'blog.html' },
|
|
225
|
+
{ path: '/blog/getting-started', source: 'blog/getting-started.html' },
|
|
226
|
+
{ path: '/blog/advanced-tips', source: 'blog/advanced-tips.html' },
|
|
227
|
+
],
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Output structure:**
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
dist/
|
|
235
|
+
βββ index.html
|
|
236
|
+
βββ blog/
|
|
237
|
+
βββ index.html
|
|
238
|
+
βββ getting-started/
|
|
239
|
+
β βββ index.html
|
|
240
|
+
βββ advanced-tips/
|
|
241
|
+
βββ index.html
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Benefits:**
|
|
245
|
+
|
|
246
|
+
- Clean URLs (`/blog/getting-started` instead of `/blog-getting-started.html`)
|
|
247
|
+
- Explicit path control
|
|
248
|
+
- Perfect for blogs, documentation, and content sites
|
|
249
|
+
- Works seamlessly with static hosting (Netlify, Vercel, GitHub Pages)
|
|
250
|
+
|
|
127
251
|
## π Project Structure
|
|
128
252
|
|
|
129
|
-
|
|
253
|
+
### Default Structure (Opinionated)
|
|
130
254
|
|
|
131
|
-
|
|
255
|
+
When using `defaults: true` (the default):
|
|
132
256
|
|
|
133
257
|
```
|
|
134
258
|
project/
|
|
135
|
-
βββ
|
|
136
|
-
β
|
|
259
|
+
βββ public/ # Static assets
|
|
260
|
+
β βββ favicon.ico
|
|
261
|
+
βββ src/ # Source files (becomes root)
|
|
262
|
+
β βββ elements/ # Reusable elements
|
|
137
263
|
β β βββ header.html
|
|
138
264
|
β β βββ footer.html
|
|
139
265
|
β βββ index.html
|
|
140
266
|
β βββ about.html
|
|
267
|
+
βββ dist/ # Build output
|
|
268
|
+
βββ vite.config.js
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Custom Structure
|
|
272
|
+
|
|
273
|
+
When using `defaults: false`:
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
project/
|
|
277
|
+
βββ pages/ # You control everything
|
|
278
|
+
β βββ components/
|
|
279
|
+
β βββ index.html
|
|
280
|
+
β βββ about.html
|
|
281
|
+
βββ build/
|
|
141
282
|
βββ vite.config.js
|
|
142
283
|
```
|
|
143
284
|
|
|
@@ -153,11 +294,11 @@ project/
|
|
|
153
294
|
β β βββ nav/
|
|
154
295
|
β β βββ mobile.html
|
|
155
296
|
β β βββ desktop.html
|
|
297
|
+
β βββ blog/
|
|
298
|
+
β β βββ index.html
|
|
299
|
+
β β βββ post-1.html
|
|
156
300
|
β βββ index.html
|
|
157
|
-
β βββ about.html
|
|
158
301
|
β βββ styles.css
|
|
159
|
-
βββ public/
|
|
160
|
-
β βββ favicon.ico
|
|
161
302
|
βββ vite.config.js
|
|
162
303
|
```
|
|
163
304
|
|
|
@@ -167,18 +308,21 @@ Perfect for:
|
|
|
167
308
|
|
|
168
309
|
- π Landing pages
|
|
169
310
|
- π Documentation sites
|
|
170
|
-
- π° Blogs
|
|
311
|
+
- π° Blogs with clean URLs
|
|
171
312
|
- π¨ Marketing sites
|
|
172
313
|
- π’ Company websites
|
|
173
314
|
- π Any multi-page static site
|
|
315
|
+
- π± Progressive web apps (start with HTML)
|
|
174
316
|
|
|
175
317
|
Ideal when you want:
|
|
176
318
|
|
|
177
|
-
- Reusable HTML components
|
|
319
|
+
- Reusable HTML components with props and slots
|
|
178
320
|
- No build complexity
|
|
321
|
+
- Clean URL structures
|
|
179
322
|
- Progressive enhancement
|
|
180
323
|
- Fast, accessible sites
|
|
181
324
|
- SEO-friendly output
|
|
325
|
+
- Easy deployment to static hosts
|
|
182
326
|
|
|
183
327
|
## π‘ Philosophy
|
|
184
328
|
|
|
@@ -190,7 +334,7 @@ Start with solid HTML, add CSS for style, and layer JavaScript only where it add
|
|
|
190
334
|
|
|
191
335
|
## π Examples
|
|
192
336
|
|
|
193
|
-
### Shared Head Element
|
|
337
|
+
### Shared Head Element with Props
|
|
194
338
|
|
|
195
339
|
**src/elements/head.html:**
|
|
196
340
|
|
|
@@ -199,7 +343,7 @@ Start with solid HTML, add CSS for style, and layer JavaScript only where it add
|
|
|
199
343
|
<meta charset="UTF-8" />
|
|
200
344
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
201
345
|
<link rel="stylesheet" href="/styles.css" />
|
|
202
|
-
<
|
|
346
|
+
<title>{{pageTitle}}</title>
|
|
203
347
|
</head>
|
|
204
348
|
```
|
|
205
349
|
|
|
@@ -208,13 +352,55 @@ Start with solid HTML, add CSS for style, and layer JavaScript only where it add
|
|
|
208
352
|
```html
|
|
209
353
|
<!doctype html>
|
|
210
354
|
<html lang="en">
|
|
211
|
-
<element src="head.html" />
|
|
355
|
+
<element src="head.html" pageTitle="Home | My Site" />
|
|
212
356
|
<body>
|
|
213
357
|
<!-- content -->
|
|
214
358
|
</body>
|
|
215
359
|
</html>
|
|
216
360
|
```
|
|
217
361
|
|
|
362
|
+
### Feature Cards with Slots
|
|
363
|
+
|
|
364
|
+
**src/elements/feature-card.html:**
|
|
365
|
+
|
|
366
|
+
```html
|
|
367
|
+
<div class="feature-card">
|
|
368
|
+
<div class="icon">{{icon}}</div>
|
|
369
|
+
<h3>{{title}}</h3>
|
|
370
|
+
<slot />
|
|
371
|
+
</div>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Usage:**
|
|
375
|
+
|
|
376
|
+
```html
|
|
377
|
+
<element src="feature-card.html" icon="β‘" title="Fast Builds">
|
|
378
|
+
<p>Lightning-fast hot reloading with Vite.</p>
|
|
379
|
+
</element>
|
|
380
|
+
|
|
381
|
+
<element src="feature-card.html" icon="π¨" title="Zero JS">
|
|
382
|
+
<p>Pure static HTML output.</p>
|
|
383
|
+
</element>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Blog with Route Manifest
|
|
387
|
+
|
|
388
|
+
```javascript
|
|
389
|
+
// vite.config.js
|
|
390
|
+
export default defineConfig({
|
|
391
|
+
plugins: [
|
|
392
|
+
htmlElements({
|
|
393
|
+
routes: [
|
|
394
|
+
{ path: '/', source: 'index.html' },
|
|
395
|
+
{ path: '/blog', source: 'blog/index.html' },
|
|
396
|
+
{ path: '/blog/post-1', source: 'blog/post-1.html' },
|
|
397
|
+
{ path: '/blog/post-2', source: 'blog/post-2.html' },
|
|
398
|
+
],
|
|
399
|
+
}),
|
|
400
|
+
],
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
218
404
|
### Component Library
|
|
219
405
|
|
|
220
406
|
```
|
|
@@ -231,29 +417,41 @@ elements/
|
|
|
231
417
|
```
|
|
232
418
|
|
|
233
419
|
```html
|
|
234
|
-
<element src="buttons/primary.html"
|
|
420
|
+
<element src="buttons/primary.html">Buy Now</element>
|
|
421
|
+
<element src="cards/product.html" title="Product" price="$99">
|
|
422
|
+
<p>Product description here</p>
|
|
423
|
+
</element>
|
|
235
424
|
```
|
|
236
425
|
|
|
237
426
|
## β FAQ
|
|
238
427
|
|
|
239
|
-
**Can I use
|
|
240
|
-
Yes!
|
|
428
|
+
**Can I use props and slots together?**
|
|
429
|
+
Yes! Props replace `{{propName}}` placeholders, while slots inject content into `<slot />` tags.
|
|
430
|
+
|
|
431
|
+
**Does it work with Tailwind CSS?**
|
|
432
|
+
Yes! Fully compatible with Tailwind and other CSS frameworks.
|
|
241
433
|
|
|
242
|
-
**
|
|
243
|
-
Yes!
|
|
434
|
+
**Can I deploy to GitHub Pages?**
|
|
435
|
+
Yes! Use `basePath: '/repo-name'` to match your repository name.
|
|
436
|
+
|
|
437
|
+
**What's the difference between `defaults: true` and `defaults: false`?**
|
|
438
|
+
`defaults: true` applies opinionated structure (`src/` as root, `public/`, `dist/`). Set to `false` to fully control your Vite config.
|
|
244
439
|
|
|
245
440
|
**Can elements include JavaScript?**
|
|
246
|
-
Elements are just HTML.
|
|
441
|
+
Yes! Elements are just HTML. Include `<script>` tags as needed.
|
|
247
442
|
|
|
248
443
|
**What about dynamic content?**
|
|
249
|
-
This plugin is for static composition at build time.
|
|
444
|
+
This plugin is for static composition at build time. Layer on JavaScript for dynamic behavior.
|
|
250
445
|
|
|
251
446
|
**Do I need Node.js at runtime?**
|
|
252
|
-
No! The plugin runs at build time.
|
|
447
|
+
No! The plugin runs at build time. Output is pure static HTML that works anywhere.
|
|
448
|
+
|
|
449
|
+
**How do route manifests work with static hosting?**
|
|
450
|
+
Routes like `/blog/post-1` output to `blog/post-1/index.html`, which static hosts serve automatically at the clean URL.
|
|
253
451
|
|
|
254
452
|
## π€ Contributing
|
|
255
453
|
|
|
256
|
-
Contributions welcome! Please open an issue or PR on
|
|
454
|
+
Contributions welcome! Please open an issue or PR on Codeberg.
|
|
257
455
|
|
|
258
456
|
## π License
|
|
259
457
|
|
|
@@ -262,6 +460,6 @@ MIT
|
|
|
262
460
|
## π Links
|
|
263
461
|
|
|
264
462
|
- [Documentation](https://htmlelements.dev)
|
|
265
|
-
- [
|
|
463
|
+
- [Codeberg](https://codeberg.org/nexusocean/vite-plugin-html-elements)
|
|
266
464
|
- [npm](https://www.npmjs.com/package/vite-plugin-html-elements)
|
|
267
465
|
- [Issues](https://codeberg.org/nexusocean/vite-plugin-html-elements/issues)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,43 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
+
export interface RouteConfig {
|
|
3
|
+
/**
|
|
4
|
+
* URL path for the route (e.g., '/', '/blog', '/blog/today-is-nice')
|
|
5
|
+
*/
|
|
6
|
+
path: string;
|
|
7
|
+
/**
|
|
8
|
+
* Source HTML file relative to srcDir
|
|
9
|
+
*/
|
|
10
|
+
source: string;
|
|
11
|
+
}
|
|
2
12
|
export interface HtmlElementsOptions {
|
|
3
13
|
/**
|
|
4
14
|
* Enable debug logging
|
|
5
15
|
* @default false
|
|
6
16
|
*/
|
|
7
|
-
debug
|
|
17
|
+
debug?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Base path for deployment (e.g., '/my-site' for GitHub Pages)
|
|
20
|
+
* @default '/'
|
|
21
|
+
*/
|
|
22
|
+
basePath?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Route manifest for explicit path configuration
|
|
25
|
+
* If provided, automatic HTML discovery is disabled
|
|
26
|
+
*/
|
|
27
|
+
routes?: RouteConfig[];
|
|
28
|
+
/**
|
|
29
|
+
* Source directory for HTML files (relative to Vite's root)
|
|
30
|
+
* @default 'src'
|
|
31
|
+
*/
|
|
32
|
+
srcDir?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Apply default project structure conventions
|
|
35
|
+
* When true: sets root to 'src', publicDir to '../public', outDir to '../dist'
|
|
36
|
+
* When false: respects user's Vite config completely
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
defaults?: boolean;
|
|
8
40
|
}
|
|
9
41
|
export declare function htmlElements(options?: HtmlElementsOptions): Plugin;
|
|
10
|
-
export declare function getHtmlEntries(srcDir: string): Record<string, string>;
|
|
42
|
+
export declare function getHtmlEntries(srcDir: string, debug?: boolean): Record<string, string>;
|
|
11
43
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAyC,MAAM,MAAM,CAAC;AAI1E,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAiEtE;AAyHD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,OAAe,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BxB"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,47 @@
|
|
|
1
1
|
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
export function htmlElements(options = {
|
|
4
|
-
const { debug } = options;
|
|
3
|
+
export function htmlElements(options = {}) {
|
|
4
|
+
const { debug = false, basePath = '/', routes, srcDir = 'src', defaults = false, } = options;
|
|
5
5
|
return {
|
|
6
6
|
name: 'vite-plugin-html-elements',
|
|
7
|
-
config() {
|
|
8
|
-
const
|
|
9
|
-
const resolvedSrcDir =
|
|
7
|
+
config(userConfig) {
|
|
8
|
+
const root = defaults ? srcDir : userConfig.root || process.cwd();
|
|
9
|
+
const resolvedSrcDir = defaults
|
|
10
|
+
? resolve(process.cwd(), srcDir)
|
|
11
|
+
: resolve(root, srcDir);
|
|
12
|
+
if (debug) {
|
|
13
|
+
console.log(`π§ html-elements config:`);
|
|
14
|
+
console.log(` Defaults mode: ${defaults}`);
|
|
15
|
+
console.log(` Root: ${root}`);
|
|
16
|
+
console.log(` Source dir: ${resolvedSrcDir}`);
|
|
17
|
+
console.log(` Base path: ${basePath}`);
|
|
18
|
+
if (routes) {
|
|
19
|
+
console.log(` Routes: ${routes.length} defined`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (defaults) {
|
|
23
|
+
return {
|
|
24
|
+
root: srcDir,
|
|
25
|
+
publicDir: '../public',
|
|
26
|
+
base: basePath,
|
|
27
|
+
build: {
|
|
28
|
+
outDir: '../dist',
|
|
29
|
+
emptyOutDir: true,
|
|
30
|
+
rollupOptions: {
|
|
31
|
+
input: routes
|
|
32
|
+
? getRoutesEntries(routes, resolvedSrcDir, debug)
|
|
33
|
+
: getHtmlEntries(resolvedSrcDir, debug),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
10
38
|
return {
|
|
11
|
-
|
|
12
|
-
publicDir: '../public',
|
|
39
|
+
base: basePath,
|
|
13
40
|
build: {
|
|
14
|
-
outDir: '../dist',
|
|
15
|
-
emptyOutDir: true,
|
|
16
41
|
rollupOptions: {
|
|
17
|
-
input:
|
|
42
|
+
input: routes
|
|
43
|
+
? getRoutesEntries(routes, resolvedSrcDir, debug)
|
|
44
|
+
: getHtmlEntries(resolvedSrcDir, debug),
|
|
18
45
|
},
|
|
19
46
|
},
|
|
20
47
|
};
|
|
@@ -22,20 +49,48 @@ export function htmlElements(options = { debug: false }) {
|
|
|
22
49
|
transformIndexHtml: {
|
|
23
50
|
order: 'pre',
|
|
24
51
|
handler(html, _ctx) {
|
|
25
|
-
return processElements(html, debug);
|
|
52
|
+
return processElements(html, debug, srcDir);
|
|
26
53
|
},
|
|
27
54
|
},
|
|
28
55
|
};
|
|
29
56
|
}
|
|
30
|
-
function
|
|
57
|
+
function getRoutesEntries(routes, srcDir, debug) {
|
|
58
|
+
const entries = {};
|
|
59
|
+
routes.forEach((route) => {
|
|
60
|
+
const sourcePath = resolve(srcDir, route.source);
|
|
61
|
+
if (!existsSync(sourcePath)) {
|
|
62
|
+
console.error(`β Route source not found: ${route.source} for path ${route.path}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Convert route path to entry name
|
|
66
|
+
// '/' -> 'index'
|
|
67
|
+
// '/blog' -> 'blog/index'
|
|
68
|
+
// '/blog/today-is-nice' -> 'blog/today-is-nice/index'
|
|
69
|
+
let entryName;
|
|
70
|
+
if (route.path === '/') {
|
|
71
|
+
entryName = 'index';
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Remove leading slash and add /index for directory structure
|
|
75
|
+
const cleanPath = route.path.replace(/^\//, '');
|
|
76
|
+
entryName = `${cleanPath}/index`;
|
|
77
|
+
}
|
|
78
|
+
entries[entryName] = sourcePath;
|
|
79
|
+
if (debug) {
|
|
80
|
+
console.log(`πΊοΈ Route: ${route.path} -> ${route.source} (output: ${entryName}.html)`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return entries;
|
|
84
|
+
}
|
|
85
|
+
function processElements(html, debug, srcDir) {
|
|
31
86
|
const pattern = /<element\s+src=["']([^"']+)["']([^>]*?)(?:\/>|>([\s\S]*?)<\/element>)/g;
|
|
32
87
|
return html.replace(pattern, (_match, filepath, attributes, slotContent = '') => {
|
|
33
88
|
let resolvedPath = filepath;
|
|
34
89
|
if (!filepath.includes('elements/') && filepath.includes('.html')) {
|
|
35
90
|
resolvedPath = `elements/${filepath}`;
|
|
36
91
|
}
|
|
37
|
-
const
|
|
38
|
-
const fullPath = resolve(
|
|
92
|
+
const resolvedSrcDir = resolve(process.cwd(), srcDir);
|
|
93
|
+
const fullPath = resolve(resolvedSrcDir, resolvedPath);
|
|
39
94
|
if (!existsSync(fullPath)) {
|
|
40
95
|
console.error(`β Element not found: ${filepath}`);
|
|
41
96
|
if (debug) {
|
|
@@ -80,7 +135,7 @@ function parseAttributes(attrString) {
|
|
|
80
135
|
}
|
|
81
136
|
return attrs;
|
|
82
137
|
}
|
|
83
|
-
export function getHtmlEntries(srcDir) {
|
|
138
|
+
export function getHtmlEntries(srcDir, debug = false) {
|
|
84
139
|
try {
|
|
85
140
|
const htmlFiles = readdirSync(srcDir).filter((file) => file.endsWith('.html'));
|
|
86
141
|
const entries = {};
|
|
@@ -88,10 +143,17 @@ export function getHtmlEntries(srcDir) {
|
|
|
88
143
|
const name = file.replace('.html', '');
|
|
89
144
|
entries[name] = resolve(srcDir, file);
|
|
90
145
|
});
|
|
146
|
+
if (debug) {
|
|
147
|
+
console.log(`π Auto-discovered HTML files: ${Object.keys(entries).join(', ')}`);
|
|
148
|
+
}
|
|
91
149
|
return entries;
|
|
92
150
|
}
|
|
93
151
|
catch (error) {
|
|
152
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
94
153
|
console.warn(`β οΈ Could not read directory: ${srcDir}`);
|
|
154
|
+
if (debug) {
|
|
155
|
+
console.error(` ${errorMessage}`);
|
|
156
|
+
}
|
|
95
157
|
return {};
|
|
96
158
|
}
|
|
97
159
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-html-elements",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Modular HTML without the JavaScript",
|
|
5
5
|
"author": "Vincent Medina",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,24 +22,43 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"lint": "eslint src --ext .ts",
|
|
28
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
29
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
30
|
+
"prepublishOnly": "npm run build",
|
|
31
|
+
"prepare": "npx simple-git-hooks"
|
|
32
|
+
},
|
|
25
33
|
"peerDependencies": {
|
|
26
34
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
27
35
|
},
|
|
28
36
|
"devDependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"@
|
|
31
|
-
"@typescript-eslint/
|
|
32
|
-
"eslint": "^8.
|
|
33
|
-
"eslint
|
|
34
|
-
"prettier": "^
|
|
37
|
+
"@eslint/js": "^9.39.2",
|
|
38
|
+
"@types/node": "^24.0.0",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
41
|
+
"eslint": "^9.39.2",
|
|
42
|
+
"eslint-config-prettier": "^10.1.8",
|
|
43
|
+
"globals": "^17.3.0",
|
|
44
|
+
"lint-staged": "^16.2.7",
|
|
45
|
+
"prettier": "^3.8.1",
|
|
46
|
+
"simple-git-hooks": "^2.13.1",
|
|
47
|
+
"tseslint": "^0.0.2",
|
|
48
|
+
"tsparser": "^1.0.2",
|
|
35
49
|
"typescript": "^5.9.3",
|
|
36
|
-
"vite": "^7.
|
|
50
|
+
"vite": "^7.3.1"
|
|
37
51
|
},
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
52
|
+
"simple-git-hooks": {
|
|
53
|
+
"pre-commit": "npx lint-staged"
|
|
54
|
+
},
|
|
55
|
+
"lint-staged": {
|
|
56
|
+
"*.{mjs,js,ts,tsx}": [
|
|
57
|
+
"prettier --write",
|
|
58
|
+
"eslint"
|
|
59
|
+
],
|
|
60
|
+
"*.{css,less,scss,json,graphql}": [
|
|
61
|
+
"prettier --write"
|
|
62
|
+
]
|
|
44
63
|
}
|
|
45
|
-
}
|
|
64
|
+
}
|