html-component-engine 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 +247 -0
- package/bin/cli.js +529 -0
- package/package.json +37 -0
- package/src/engine/compiler.js +312 -0
- package/src/engine/utils.js +74 -0
- package/src/index.js +279 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import readline from 'readline';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
// ANSI colors
|
|
11
|
+
const colors = {
|
|
12
|
+
reset: '\x1b[0m',
|
|
13
|
+
bright: '\x1b[1m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
cyan: '\x1b[36m',
|
|
16
|
+
yellow: '\x1b[33m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
dim: '\x1b[2m',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function log(message, color = 'reset') {
|
|
22
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createReadlineInterface() {
|
|
26
|
+
return readline.createInterface({
|
|
27
|
+
input: process.stdin,
|
|
28
|
+
output: process.stdout,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function question(rl, prompt) {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
rl.question(prompt, resolve);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Template files
|
|
39
|
+
const templates = {
|
|
40
|
+
'package.json': (projectName) => `{
|
|
41
|
+
"name": "${projectName}",
|
|
42
|
+
"version": "0.1.0",
|
|
43
|
+
"type": "module",
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "vite",
|
|
46
|
+
"build": "vite build",
|
|
47
|
+
"preview": "vite preview"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"vite": "^7.0.0",
|
|
51
|
+
"html-component-engine": "^0.1.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
`,
|
|
55
|
+
|
|
56
|
+
'vite.config.js': () => `import htmlComponentEngine from 'html-component-engine';
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
plugins: [
|
|
60
|
+
htmlComponentEngine({
|
|
61
|
+
srcDir: 'src',
|
|
62
|
+
componentsDir: 'components',
|
|
63
|
+
assetsDir: 'assets',
|
|
64
|
+
})
|
|
65
|
+
],
|
|
66
|
+
publicDir: 'src/assets',
|
|
67
|
+
build: {
|
|
68
|
+
outDir: 'dist',
|
|
69
|
+
emptyOutDir: true,
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
`,
|
|
73
|
+
|
|
74
|
+
'src/index.html': () => `<!DOCTYPE html>
|
|
75
|
+
<html lang="en">
|
|
76
|
+
<head>
|
|
77
|
+
<meta charset="UTF-8">
|
|
78
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
79
|
+
<title>Home | My Website</title>
|
|
80
|
+
<link rel="stylesheet" href="/styles/main.css">
|
|
81
|
+
</head>
|
|
82
|
+
<body>
|
|
83
|
+
<Component src="Header" title="My Website" />
|
|
84
|
+
|
|
85
|
+
<main class="container">
|
|
86
|
+
<h2>Welcome to My Website</h2>
|
|
87
|
+
<p>This is a sample page using HTML Component Engine.</p>
|
|
88
|
+
|
|
89
|
+
<section class="cards">
|
|
90
|
+
<Component name="Card" title="Getting Started">
|
|
91
|
+
<p>Edit <code>src/index.html</code> to modify this page.</p>
|
|
92
|
+
<p>Components are in <code>src/components/</code>.</p>
|
|
93
|
+
</Component>
|
|
94
|
+
|
|
95
|
+
<Component name="Card" title="Features">
|
|
96
|
+
<ul>
|
|
97
|
+
<li>Reusable HTML components</li>
|
|
98
|
+
<li>Props and variants support</li>
|
|
99
|
+
<li>Slot-based children</li>
|
|
100
|
+
<li>CSS/JS inlining for production</li>
|
|
101
|
+
</ul>
|
|
102
|
+
</Component>
|
|
103
|
+
</section>
|
|
104
|
+
|
|
105
|
+
<Component src="Button" text="Learn More" variant="primary" />
|
|
106
|
+
</main>
|
|
107
|
+
|
|
108
|
+
<Component src="Footer" year="2025" />
|
|
109
|
+
</body>
|
|
110
|
+
</html>
|
|
111
|
+
`,
|
|
112
|
+
|
|
113
|
+
'src/about.html': () => `<!DOCTYPE html>
|
|
114
|
+
<html lang="en">
|
|
115
|
+
<head>
|
|
116
|
+
<meta charset="UTF-8">
|
|
117
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
118
|
+
<title>About | My Website</title>
|
|
119
|
+
<link rel="stylesheet" href="/styles/main.css">
|
|
120
|
+
</head>
|
|
121
|
+
<body>
|
|
122
|
+
<Component src="Header" title="My Website" />
|
|
123
|
+
|
|
124
|
+
<main class="container">
|
|
125
|
+
<h2>About Us</h2>
|
|
126
|
+
<p>This is the about page.</p>
|
|
127
|
+
|
|
128
|
+
<Component name="Card" title="Our Mission">
|
|
129
|
+
<p>Building great websites with simple, reusable HTML components.</p>
|
|
130
|
+
</Component>
|
|
131
|
+
|
|
132
|
+
<Component src="Button" text="Go Home" variant="secondary" href="/" />
|
|
133
|
+
</main>
|
|
134
|
+
|
|
135
|
+
<Component src="Footer" year="2025" />
|
|
136
|
+
</body>
|
|
137
|
+
</html>
|
|
138
|
+
`,
|
|
139
|
+
|
|
140
|
+
'src/components/Header.html': () => `<header class="header">
|
|
141
|
+
<div class="header-content">
|
|
142
|
+
<h1 class="logo">{{ title }}</h1>
|
|
143
|
+
<nav class="nav">
|
|
144
|
+
<a href="/">Home</a>
|
|
145
|
+
<a href="/about">About</a>
|
|
146
|
+
</nav>
|
|
147
|
+
</div>
|
|
148
|
+
</header>
|
|
149
|
+
`,
|
|
150
|
+
|
|
151
|
+
'src/components/Footer.html': () => `<footer class="footer">
|
|
152
|
+
<div class="footer-content">
|
|
153
|
+
<p>© {{ year }} My Website. All rights reserved.</p>
|
|
154
|
+
</div>
|
|
155
|
+
</footer>
|
|
156
|
+
`,
|
|
157
|
+
|
|
158
|
+
'src/components/Card.html': () => `<div class="card">
|
|
159
|
+
<div class="card-header">
|
|
160
|
+
<h3>{{ title }}</h3>
|
|
161
|
+
</div>
|
|
162
|
+
<div class="card-body">
|
|
163
|
+
{{ children }}
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
`,
|
|
167
|
+
|
|
168
|
+
'src/components/Button.html': () => `<!-- variants: primary=btn-primary, secondary=btn-secondary, outline=btn-outline -->
|
|
169
|
+
<a class="btn {{ variantClasses }}" href="{{ href }}">{{ text }}</a>
|
|
170
|
+
`,
|
|
171
|
+
|
|
172
|
+
'src/assets/styles/main.css': () => `/* Reset */
|
|
173
|
+
*, *::before, *::after {
|
|
174
|
+
box-sizing: border-box;
|
|
175
|
+
margin: 0;
|
|
176
|
+
padding: 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Base */
|
|
180
|
+
:root {
|
|
181
|
+
--primary-color: #3b82f6;
|
|
182
|
+
--secondary-color: #64748b;
|
|
183
|
+
--text-color: #1e293b;
|
|
184
|
+
--bg-color: #f8fafc;
|
|
185
|
+
--card-bg: #ffffff;
|
|
186
|
+
--border-color: #e2e8f0;
|
|
187
|
+
--radius: 8px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
body {
|
|
191
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
192
|
+
line-height: 1.6;
|
|
193
|
+
color: var(--text-color);
|
|
194
|
+
background-color: var(--bg-color);
|
|
195
|
+
min-height: 100vh;
|
|
196
|
+
display: flex;
|
|
197
|
+
flex-direction: column;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Container */
|
|
201
|
+
.container {
|
|
202
|
+
max-width: 1200px;
|
|
203
|
+
margin: 0 auto;
|
|
204
|
+
padding: 2rem;
|
|
205
|
+
flex: 1;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Header */
|
|
209
|
+
.header {
|
|
210
|
+
background: var(--card-bg);
|
|
211
|
+
border-bottom: 1px solid var(--border-color);
|
|
212
|
+
padding: 1rem 2rem;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.header-content {
|
|
216
|
+
max-width: 1200px;
|
|
217
|
+
margin: 0 auto;
|
|
218
|
+
display: flex;
|
|
219
|
+
justify-content: space-between;
|
|
220
|
+
align-items: center;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.logo {
|
|
224
|
+
font-size: 1.5rem;
|
|
225
|
+
color: var(--primary-color);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.nav {
|
|
229
|
+
display: flex;
|
|
230
|
+
gap: 1.5rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.nav a {
|
|
234
|
+
color: var(--text-color);
|
|
235
|
+
text-decoration: none;
|
|
236
|
+
font-weight: 500;
|
|
237
|
+
transition: color 0.2s;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.nav a:hover {
|
|
241
|
+
color: var(--primary-color);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Footer */
|
|
245
|
+
.footer {
|
|
246
|
+
background: var(--text-color);
|
|
247
|
+
color: var(--bg-color);
|
|
248
|
+
padding: 1.5rem 2rem;
|
|
249
|
+
margin-top: auto;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.footer-content {
|
|
253
|
+
max-width: 1200px;
|
|
254
|
+
margin: 0 auto;
|
|
255
|
+
text-align: center;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Cards */
|
|
259
|
+
.cards {
|
|
260
|
+
display: grid;
|
|
261
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
262
|
+
gap: 1.5rem;
|
|
263
|
+
margin: 2rem 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.card {
|
|
267
|
+
background: var(--card-bg);
|
|
268
|
+
border: 1px solid var(--border-color);
|
|
269
|
+
border-radius: var(--radius);
|
|
270
|
+
overflow: hidden;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.card-header {
|
|
274
|
+
padding: 1rem 1.5rem;
|
|
275
|
+
border-bottom: 1px solid var(--border-color);
|
|
276
|
+
background: var(--bg-color);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.card-header h3 {
|
|
280
|
+
font-size: 1.125rem;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.card-body {
|
|
284
|
+
padding: 1.5rem;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.card-body ul {
|
|
288
|
+
padding-left: 1.5rem;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.card-body li {
|
|
292
|
+
margin-bottom: 0.5rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.card-body code {
|
|
296
|
+
background: var(--bg-color);
|
|
297
|
+
padding: 0.2em 0.4em;
|
|
298
|
+
border-radius: 4px;
|
|
299
|
+
font-size: 0.9em;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Buttons */
|
|
303
|
+
.btn {
|
|
304
|
+
display: inline-block;
|
|
305
|
+
padding: 0.75rem 1.5rem;
|
|
306
|
+
border-radius: var(--radius);
|
|
307
|
+
text-decoration: none;
|
|
308
|
+
font-weight: 500;
|
|
309
|
+
transition: all 0.2s;
|
|
310
|
+
cursor: pointer;
|
|
311
|
+
border: 2px solid transparent;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.btn-primary {
|
|
315
|
+
background: var(--primary-color);
|
|
316
|
+
color: white;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.btn-primary:hover {
|
|
320
|
+
background: #2563eb;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.btn-secondary {
|
|
324
|
+
background: var(--secondary-color);
|
|
325
|
+
color: white;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.btn-secondary:hover {
|
|
329
|
+
background: #475569;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.btn-outline {
|
|
333
|
+
background: transparent;
|
|
334
|
+
border-color: var(--primary-color);
|
|
335
|
+
color: var(--primary-color);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.btn-outline:hover {
|
|
339
|
+
background: var(--primary-color);
|
|
340
|
+
color: white;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/* Typography */
|
|
344
|
+
h2 {
|
|
345
|
+
margin-bottom: 1rem;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
p {
|
|
349
|
+
margin-bottom: 1rem;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
section {
|
|
353
|
+
margin-bottom: 2rem;
|
|
354
|
+
}
|
|
355
|
+
`,
|
|
356
|
+
|
|
357
|
+
'.gitignore': () => `node_modules
|
|
358
|
+
dist
|
|
359
|
+
.vite
|
|
360
|
+
*.log
|
|
361
|
+
.DS_Store
|
|
362
|
+
`,
|
|
363
|
+
|
|
364
|
+
'README.md': (projectName) => `# ${projectName}
|
|
365
|
+
|
|
366
|
+
A website built with [HTML Component Engine](https://github.com/taymakz/html-component-engine).
|
|
367
|
+
|
|
368
|
+
## Getting Started
|
|
369
|
+
|
|
370
|
+
\`\`\`bash
|
|
371
|
+
# Install dependencies
|
|
372
|
+
npm install
|
|
373
|
+
|
|
374
|
+
# Start development server
|
|
375
|
+
npm run dev
|
|
376
|
+
|
|
377
|
+
# Build for production
|
|
378
|
+
npm run build
|
|
379
|
+
|
|
380
|
+
# Preview production build
|
|
381
|
+
npm run preview
|
|
382
|
+
\`\`\`
|
|
383
|
+
|
|
384
|
+
## Project Structure
|
|
385
|
+
|
|
386
|
+
\`\`\`
|
|
387
|
+
${projectName}/
|
|
388
|
+
├── src/
|
|
389
|
+
│ ├── index.html # Home page
|
|
390
|
+
│ ├── about.html # About page
|
|
391
|
+
│ ├── components/ # Reusable components
|
|
392
|
+
│ │ ├── Header.html
|
|
393
|
+
│ │ ├── Footer.html
|
|
394
|
+
│ │ ├── Card.html
|
|
395
|
+
│ │ └── Button.html
|
|
396
|
+
│ └── assets/
|
|
397
|
+
│ └── styles/
|
|
398
|
+
│ └── main.css
|
|
399
|
+
├── vite.config.js
|
|
400
|
+
└── package.json
|
|
401
|
+
\`\`\`
|
|
402
|
+
|
|
403
|
+
## Component Syntax
|
|
404
|
+
|
|
405
|
+
### Self-closing components (no children)
|
|
406
|
+
\`\`\`html
|
|
407
|
+
<Component src="Button" text="Click Me" variant="primary" />
|
|
408
|
+
\`\`\`
|
|
409
|
+
|
|
410
|
+
### Components with children (slots)
|
|
411
|
+
\`\`\`html
|
|
412
|
+
<Component name="Card" title="My Card">
|
|
413
|
+
<p>This content goes into {{ children }}</p>
|
|
414
|
+
</Component>
|
|
415
|
+
\`\`\`
|
|
416
|
+
|
|
417
|
+
### Defining variants
|
|
418
|
+
\`\`\`html
|
|
419
|
+
<!-- variants: primary=btn-primary, secondary=btn-secondary -->
|
|
420
|
+
<button class="{{ variantClasses }}">{{ text }}</button>
|
|
421
|
+
\`\`\`
|
|
422
|
+
`,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
async function init() {
|
|
426
|
+
console.log();
|
|
427
|
+
log('🚀 HTML Component Engine - Project Initializer', 'cyan');
|
|
428
|
+
log('━'.repeat(50), 'dim');
|
|
429
|
+
console.log();
|
|
430
|
+
|
|
431
|
+
const rl = createReadlineInterface();
|
|
432
|
+
|
|
433
|
+
try {
|
|
434
|
+
// Ask for project name
|
|
435
|
+
const projectName = await question(
|
|
436
|
+
rl,
|
|
437
|
+
`${colors.cyan}? ${colors.reset}Project name ${colors.dim}(. for current directory)${colors.reset}: `
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
if (!projectName) {
|
|
441
|
+
log('✖ Project name is required', 'red');
|
|
442
|
+
process.exit(1);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const targetDir = projectName === '.' ? process.cwd() : path.resolve(process.cwd(), projectName);
|
|
446
|
+
const displayName = projectName === '.' ? path.basename(process.cwd()) : projectName;
|
|
447
|
+
|
|
448
|
+
// Check if directory exists and is not empty
|
|
449
|
+
if (projectName !== '.' && fs.existsSync(targetDir)) {
|
|
450
|
+
const files = fs.readdirSync(targetDir);
|
|
451
|
+
if (files.length > 0) {
|
|
452
|
+
const overwrite = await question(
|
|
453
|
+
rl,
|
|
454
|
+
`${colors.yellow}⚠ Directory "${projectName}" is not empty. Continue? (y/N): ${colors.reset}`
|
|
455
|
+
);
|
|
456
|
+
if (overwrite.toLowerCase() !== 'y') {
|
|
457
|
+
log('✖ Cancelled', 'red');
|
|
458
|
+
process.exit(1);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
rl.close();
|
|
464
|
+
|
|
465
|
+
console.log();
|
|
466
|
+
log(`Creating project in ${targetDir}...`, 'dim');
|
|
467
|
+
console.log();
|
|
468
|
+
|
|
469
|
+
// Create directories
|
|
470
|
+
const dirs = [
|
|
471
|
+
'',
|
|
472
|
+
'src',
|
|
473
|
+
'src/components',
|
|
474
|
+
'src/assets',
|
|
475
|
+
'src/assets/styles',
|
|
476
|
+
];
|
|
477
|
+
|
|
478
|
+
for (const dir of dirs) {
|
|
479
|
+
const dirPath = path.join(targetDir, dir);
|
|
480
|
+
if (!fs.existsSync(dirPath)) {
|
|
481
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Create files
|
|
486
|
+
for (const [filePath, getContent] of Object.entries(templates)) {
|
|
487
|
+
const fullPath = path.join(targetDir, filePath);
|
|
488
|
+
const content = typeof getContent === 'function' ? getContent(displayName) : getContent;
|
|
489
|
+
fs.writeFileSync(fullPath, content);
|
|
490
|
+
log(` ✓ ${filePath}`, 'green');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
console.log();
|
|
494
|
+
log('━'.repeat(50), 'dim');
|
|
495
|
+
log('✅ Project created successfully!', 'green');
|
|
496
|
+
console.log();
|
|
497
|
+
log('Next steps:', 'bright');
|
|
498
|
+
console.log();
|
|
499
|
+
|
|
500
|
+
if (projectName !== '.') {
|
|
501
|
+
log(` cd ${projectName}`, 'cyan');
|
|
502
|
+
}
|
|
503
|
+
log(' npm install', 'cyan');
|
|
504
|
+
log(' npm run dev', 'cyan');
|
|
505
|
+
console.log();
|
|
506
|
+
log('Happy coding! 🎉', 'yellow');
|
|
507
|
+
console.log();
|
|
508
|
+
|
|
509
|
+
} catch (error) {
|
|
510
|
+
rl.close();
|
|
511
|
+
log(`✖ Error: ${error.message}`, 'red');
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Parse command line arguments
|
|
517
|
+
const args = process.argv.slice(2);
|
|
518
|
+
const command = args[0];
|
|
519
|
+
|
|
520
|
+
if (command === 'init' || !command) {
|
|
521
|
+
init();
|
|
522
|
+
} else {
|
|
523
|
+
log(`Unknown command: ${command}`, 'red');
|
|
524
|
+
console.log();
|
|
525
|
+
log('Available commands:', 'bright');
|
|
526
|
+
log(' init Create a new HTML Component Engine project', 'dim');
|
|
527
|
+
console.log();
|
|
528
|
+
process.exit(1);
|
|
529
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "html-component-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Vite plugin for HTML component components with a lightweight static site compiler",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"html-component": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"bin",
|
|
13
|
+
"templates"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"test:coverage": "vitest run --coverage"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"vite",
|
|
22
|
+
"plugin",
|
|
23
|
+
"html",
|
|
24
|
+
"components",
|
|
25
|
+
"static-site",
|
|
26
|
+
"template-engine"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"vite": "^7.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"vitest": "^3.0.0",
|
|
35
|
+
"vite": "^7.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|