vite-plugin-html-elements 0.0.9

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vincent Medina
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # 💧 vite-plugin-html-elements
2
+
3
+ > Modular HTML without the JavaScript
4
+
5
+ A lightweight Vite plugin for composing reusable HTML elements in static sites. Keep your HTML DRY and maintainable without adding runtime JavaScript.
6
+
7
+ ## ✨ Features
8
+
9
+ - **Zero JavaScript** - Pure static HTML output
10
+ - **Hot Reload** - Instant updates during development
11
+ - **Intuitive Syntax** - Natural self-closing `<element />` tags
12
+ - **Shorthand Support** - `<element src="header.html" />`
13
+ - **TypeScript** - Full type safety
14
+ - **Tiny** - Minimal footprint, maximum impact
15
+
16
+ ## 📦 Installation
17
+
18
+ ```bash
19
+ npm install -D vite-plugin-html-elements
20
+ ```
21
+
22
+ ## 🚀 Quick Start
23
+
24
+ ### 1. Add to your Vite config
25
+
26
+ ```javascript
27
+ // vite.config.js
28
+ import { defineConfig } from 'vite';
29
+ import { htmlElements } from 'vite-plugin-html-elements';
30
+
31
+ export default defineConfig({
32
+ plugins: [htmlElements()],
33
+ });
34
+ ```
35
+
36
+ ### 2. Create your project structure
37
+
38
+ ```
39
+ project/
40
+ ├── src/
41
+ │ ├── elements/
42
+ │ │ ├── header.html
43
+ │ │ └── footer.html
44
+ │ └── index.html
45
+ └── vite.config.js
46
+ ```
47
+
48
+ ### 3. Create reusable elements
49
+
50
+ **src/elements/header.html:**
51
+
52
+ ```html
53
+ <header>
54
+ <nav>
55
+ <a href="/">Home</a>
56
+ <a href="/about">About</a>
57
+ <a href="/contact">Contact</a>
58
+ </nav>
59
+ </header>
60
+ ```
61
+
62
+ ### 4. Use elements in your pages
63
+
64
+ **src/index.html:**
65
+
66
+ ```html
67
+ <!doctype html>
68
+ <html lang="en">
69
+ <head>
70
+ <title>My Site</title>
71
+ <link rel="stylesheet" href="/styles.css" />
72
+ </head>
73
+ <body>
74
+ <element src="header.html" />
75
+
76
+ <main>
77
+ <h1>Welcome to my site!</h1>
78
+ </main>
79
+
80
+ <element src="footer.html" />
81
+ </body>
82
+ </html>
83
+ ```
84
+
85
+ ### 5. Build
86
+
87
+ ```bash
88
+ npm run dev # Development with hot reload
89
+ npm run build # Production build
90
+ ```
91
+
92
+ The output is pure static HTML with all elements inlined - no `<element>` tags remain.
93
+
94
+ ## 📝 Syntax
95
+
96
+ ### Shorthand (Recommended)
97
+
98
+ ```html
99
+ <element src="header.html" />
100
+ ```
101
+
102
+ Automatically resolves to `elements/header.html`
103
+
104
+ ### Explicit Paths
105
+
106
+ ```html
107
+ <element src="elements/nav/mobile.html" />
108
+ ```
109
+
110
+ ## ⚙️ Configuration
111
+
112
+ ### Debug Mode
113
+
114
+ Enable verbose logging to see which elements are being included:
115
+
116
+ ```javascript
117
+ htmlElements({ debug: true });
118
+ ```
119
+
120
+ Output:
121
+
122
+ ```
123
+ 💧 Element included: elements/header.html
124
+ 💧 Element included: elements/footer.html
125
+ ```
126
+
127
+ ## 📁 Project Structure
128
+
129
+ Organize your project however you prefer. Here are some common patterns:
130
+
131
+ ### Simple Structure
132
+
133
+ ```
134
+ project/
135
+ ├── src/
136
+ │ ├── elements/
137
+ │ │ ├── header.html
138
+ │ │ └── footer.html
139
+ │ ├── index.html
140
+ │ └── about.html
141
+ └── vite.config.js
142
+ ```
143
+
144
+ ### Organized Structure
145
+
146
+ ```
147
+ project/
148
+ ├── src/
149
+ │ ├── elements/
150
+ │ │ ├── head.html
151
+ │ │ ├── header.html
152
+ │ │ ├── footer.html
153
+ │ │ └── nav/
154
+ │ │ ├── mobile.html
155
+ │ │ └── desktop.html
156
+ │ ├── index.html
157
+ │ ├── about.html
158
+ │ └── styles.css
159
+ ├── public/
160
+ │ └── favicon.ico
161
+ └── vite.config.js
162
+ ```
163
+
164
+ ## 🎯 Use Cases
165
+
166
+ Perfect for:
167
+
168
+ - 📄 Landing pages
169
+ - 📝 Documentation sites
170
+ - 📰 Blogs
171
+ - 🎨 Marketing sites
172
+ - 🏢 Company websites
173
+ - 🚀 Any multi-page static site
174
+
175
+ Ideal when you want:
176
+
177
+ - Reusable HTML components
178
+ - No build complexity
179
+ - Progressive enhancement
180
+ - Fast, accessible sites
181
+ - SEO-friendly output
182
+
183
+ ## 💡 Philosophy
184
+
185
+ HTML and CSS are powerful. JavaScript is optional.
186
+
187
+ This plugin embraces the web platform by making static HTML modular and maintainable without introducing runtime dependencies or complex tooling.
188
+
189
+ Start with solid HTML, add CSS for style, and layer JavaScript only where it adds value.
190
+
191
+ ## 📚 Examples
192
+
193
+ ### Shared Head Element
194
+
195
+ **src/elements/head.html:**
196
+
197
+ ```html
198
+ <head>
199
+ <meta charset="UTF-8" />
200
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
201
+ <link rel="stylesheet" href="/styles.css" />
202
+ <link rel="icon" href="/favicon.ico" />
203
+ </head>
204
+ ```
205
+
206
+ **src/index.html:**
207
+
208
+ ```html
209
+ <!doctype html>
210
+ <html lang="en">
211
+ <element src="head.html" />
212
+ <body>
213
+ <!-- content -->
214
+ </body>
215
+ </html>
216
+ ```
217
+
218
+ ### Component Library
219
+
220
+ ```
221
+ elements/
222
+ ├── buttons/
223
+ │ ├── primary.html
224
+ │ └── secondary.html
225
+ ├── cards/
226
+ │ ├── product.html
227
+ │ └── blog.html
228
+ └── layouts/
229
+ ├── header.html
230
+ └── footer.html
231
+ ```
232
+
233
+ ```html
234
+ <element src="buttons/primary.html" /> <element src="cards/product.html" />
235
+ ```
236
+
237
+ ## ❓ FAQ
238
+
239
+ **Can I use relative paths?**
240
+ Yes! Paths are resolved relative to the HTML file containing the `<element />` tag.
241
+
242
+ **Does it work with other Vite plugins?**
243
+ Yes! Fully compatible with Tailwind CSS and other Vite plugins.
244
+
245
+ **Can elements include JavaScript?**
246
+ Elements are just HTML. You can include `<script>` tags in your elements if needed.
247
+
248
+ **What about dynamic content?**
249
+ This plugin is for static composition at build time. For dynamic content, layer on JavaScript after your HTML is built.
250
+
251
+ **Do I need Node.js at runtime?**
252
+ No! The plugin runs at build time. The output is pure static HTML that works anywhere.
253
+
254
+ ## 🤝 Contributing
255
+
256
+ Contributions welcome! Please open an issue or PR on GitHub.
257
+
258
+ ## 📄 License
259
+
260
+ MIT
261
+
262
+ ## 🔗 Links
263
+
264
+ - [Documentation](https://htmlelements.dev)
265
+ - [GitHub](https://codeberg.org/nexusocean/vite-plugin-html-elements)
266
+ - [npm](https://www.npmjs.com/package/vite-plugin-html-elements)
267
+ - [Issues](https://codeberg.org/nexusocean/vite-plugin-html-elements/issues)
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from 'vite';
2
+ export interface HtmlElementsOptions {
3
+ /**
4
+ * Enable debug logging
5
+ * @default false
6
+ */
7
+ debug: boolean;
8
+ }
9
+ export declare function htmlElements(options?: HtmlElementsOptions): Plugin;
10
+ export declare function getHtmlEntries(srcDir: string): Record<string, string>;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAA6B,MAAM,MAAM,CAAC;AAI9D,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAsC,GAC9C,MAAM,CA8BR;AAgED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBrE"}
package/dist/index.js ADDED
@@ -0,0 +1,97 @@
1
+ import { readdirSync, readFileSync, existsSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ export function htmlElements(options = { debug: false }) {
4
+ const { debug } = options;
5
+ return {
6
+ name: 'vite-plugin-html-elements',
7
+ config() {
8
+ const srcDir = 'src';
9
+ const resolvedSrcDir = resolve(process.cwd(), srcDir);
10
+ return {
11
+ root: srcDir,
12
+ publicDir: '../public',
13
+ build: {
14
+ outDir: '../dist',
15
+ emptyOutDir: true,
16
+ rollupOptions: {
17
+ input: getHtmlEntries(resolvedSrcDir),
18
+ },
19
+ },
20
+ };
21
+ },
22
+ transformIndexHtml: {
23
+ order: 'pre',
24
+ handler(html, _ctx) {
25
+ return processElements(html, debug);
26
+ },
27
+ },
28
+ };
29
+ }
30
+ function processElements(html, debug) {
31
+ const pattern = /<element\s+src=["']([^"']+)["']([^>]*?)(?:\/>|>([\s\S]*?)<\/element>)/g;
32
+ return html.replace(pattern, (_match, filepath, attributes, slotContent = '') => {
33
+ let resolvedPath = filepath;
34
+ if (!filepath.includes('elements/') && filepath.includes('.html')) {
35
+ resolvedPath = `elements/${filepath}`;
36
+ }
37
+ const srcDir = resolve(process.cwd(), 'src');
38
+ const fullPath = resolve(srcDir, resolvedPath);
39
+ if (!existsSync(fullPath)) {
40
+ console.error(`❌ Element not found: ${filepath}`);
41
+ if (debug) {
42
+ console.error(` Tried path: ${fullPath}`);
43
+ }
44
+ return `<!-- Element error: Could not load ${filepath} -->`;
45
+ }
46
+ try {
47
+ let content = readFileSync(fullPath, 'utf-8');
48
+ // Parse props from attributes
49
+ const props = parseAttributes(attributes);
50
+ // Replace props: {{propName}}
51
+ content = content.replace(/\{\{(\w+)\}\}/g, (_, key) => props[key] || '');
52
+ // Replace slot
53
+ if (slotContent.trim()) {
54
+ content = content.replace(/<slot\s*\/>/g, slotContent);
55
+ }
56
+ else {
57
+ content = content.replace(/<slot\s*\/>/g, '');
58
+ }
59
+ if (debug) {
60
+ console.log(`💧 Element included: ${resolvedPath}${slotContent.trim() ? ' (with slot)' : ''}${Object.keys(props).length ? ` (props: ${Object.keys(props).join(', ')})` : ''}`);
61
+ }
62
+ return content;
63
+ }
64
+ catch (error) {
65
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
66
+ console.error(`❌ Error reading element: ${filepath}`);
67
+ if (debug) {
68
+ console.error(` ${errorMessage}`);
69
+ }
70
+ return `<!-- Element error: Could not load ${filepath} -->`;
71
+ }
72
+ });
73
+ }
74
+ function parseAttributes(attrString) {
75
+ const attrs = {};
76
+ const attrPattern = /(\w+)=["']([^"']*)["']/g;
77
+ let match;
78
+ while ((match = attrPattern.exec(attrString)) !== null) {
79
+ attrs[match[1]] = match[2];
80
+ }
81
+ return attrs;
82
+ }
83
+ export function getHtmlEntries(srcDir) {
84
+ try {
85
+ const htmlFiles = readdirSync(srcDir).filter((file) => file.endsWith('.html'));
86
+ const entries = {};
87
+ htmlFiles.forEach((file) => {
88
+ const name = file.replace('.html', '');
89
+ entries[name] = resolve(srcDir, file);
90
+ });
91
+ return entries;
92
+ }
93
+ catch (error) {
94
+ console.warn(`⚠️ Could not read directory: ${srcDir}`);
95
+ return {};
96
+ }
97
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "vite-plugin-html-elements",
3
+ "version": "0.0.9",
4
+ "description": "Modular HTML without the JavaScript",
5
+ "author": "Vincent Medina",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://codeberg.org/nexusocean/vite-plugin-html-elements"
10
+ },
11
+ "keywords": [
12
+ "vite",
13
+ "vite-plugin",
14
+ "html",
15
+ "elements",
16
+ "static"
17
+ ],
18
+ "homepage": "https://htmlelements.dev",
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "peerDependencies": {
26
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.0.0",
30
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
31
+ "@typescript-eslint/parser": "^6.0.0",
32
+ "eslint": "^8.0.0",
33
+ "eslint-config-prettier": "^9.0.0",
34
+ "prettier": "^3.6.2",
35
+ "typescript": "^5.9.3",
36
+ "vite": "^7.2.2"
37
+ },
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "lint": "eslint src --ext .ts",
41
+ "format": "prettier --write \"src/**/*.ts\"",
42
+ "format:check": "prettier --check \"src/**/*.ts\"",
43
+ "prepublis`hO`nly": "npm run build"
44
+ }
45
+ }