clovie 0.1.16 → 0.1.17
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 +410 -344
- package/bin/cli.js +159 -8
- package/bin/kill-port.js +99 -0
- package/dist/{LiveReload-CqLIyMAq.js → LiveReload-DVEZWHf3.js} +12 -8
- package/dist/LiveReload-DVEZWHf3.js.map +1 -0
- package/dist/Server-D_nOQX0E.js +530 -0
- package/dist/Server-D_nOQX0E.js.map +1 -0
- package/dist/cjs/{LiveReload-CSmPQa1-.cjs → LiveReload-Be6N_lnM.cjs} +10 -9
- package/dist/cjs/LiveReload-Be6N_lnM.cjs.map +1 -0
- package/dist/cjs/Server-CN4bVO2j.cjs +503 -0
- package/dist/cjs/Server-CN4bVO2j.cjs.map +1 -0
- package/dist/cjs/{createClovie-Dm4WUXg4.cjs → createClovie-CWEt0g2r.cjs} +1336 -271
- package/dist/cjs/createClovie-CWEt0g2r.cjs.map +1 -0
- package/dist/cjs/index-DLefxiwH.cjs +332 -0
- package/dist/cjs/index-DLefxiwH.cjs.map +1 -0
- package/dist/cjs/index.cjs +3 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/{createClovie-PYUiW2YJ.js → createClovie-B0jNRKtG.js} +1329 -266
- package/dist/createClovie-B0jNRKtG.js.map +1 -0
- package/dist/index-CdqSf8xZ.js +355 -0
- package/dist/index-CdqSf8xZ.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
- package/templates/default/README.md +100 -12
- package/templates/default/clovie.config.js +20 -19
- package/templates/server/README.md +260 -66
- package/templates/server/clovie.config.js +75 -35
- package/templates/static/README.md +169 -38
- package/templates/static/clovie.config.js +50 -29
- package/dist/LiveReload-CqLIyMAq.js.map +0 -1
- package/dist/Server-BxIJW31q.js +0 -375
- package/dist/Server-BxIJW31q.js.map +0 -1
- package/dist/cjs/LiveReload-CSmPQa1-.cjs.map +0 -1
- package/dist/cjs/Server-D7RmLCVP.cjs +0 -351
- package/dist/cjs/Server-D7RmLCVP.cjs.map +0 -1
- package/dist/cjs/createClovie-Dm4WUXg4.cjs.map +0 -1
- package/dist/createClovie-PYUiW2YJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,32 +1,62 @@
|
|
|
1
|
-
# Clovie - Vintage Web Dev Tooling
|
|
1
|
+
# Clovie - Vintage Web Dev Tooling with Modern QoL
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> *"The Hollow Knight of Web Dev"* - Simple but deep, easy to start but room to grow.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A powerful Node.js-based **static site generator** and **full-stack web framework** that bridges the gap between simple static sites and complex web applications. Built on the **@brickworks/engine** service architecture for maximum flexibility and maintainability.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 🚀 Quick Start
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```bash
|
|
10
|
+
# Create a new project
|
|
11
|
+
npx clovie create my-site
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
# Start development
|
|
14
|
+
cd my-site
|
|
15
|
+
npm install
|
|
16
|
+
npm run dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## ✨ Key Features
|
|
20
|
+
|
|
21
|
+
- **🎯 Dual Mode**: Static site generation OR full Express server applications
|
|
22
|
+
- **🔄 Zero Config**: Smart auto-detection of project structure
|
|
23
|
+
- **⚡ Fast Builds**: Incremental builds with intelligent caching
|
|
24
|
+
- **🎨 Template Agnostic**: Handlebars, Nunjucks, Pug, Mustache, or custom engines
|
|
25
|
+
- **📦 Asset Pipeline**: SCSS compilation, JavaScript bundling with esbuild
|
|
26
|
+
- **🔄 Live Reload**: WebSocket-based live reload during development
|
|
27
|
+
- **🗄️ Database Ready**: SQLite integration for server mode applications
|
|
28
|
+
- **🛣️ Dynamic Routing**: Data-driven page generation and API endpoints
|
|
29
|
+
- **🔧 Service Architecture**: Modular, extensible service-oriented design
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
## 🏗️ Architecture Overview
|
|
20
32
|
|
|
21
|
-
**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- Traditional static site generator behavior
|
|
33
|
+
Clovie uses a **service-oriented architecture** built on `@brickworks/engine`. All functionality is provided by services that extend `ServiceProvider`, orchestrated through dependency injection with reactive state management.
|
|
34
|
+
|
|
35
|
+
### Core Services
|
|
25
36
|
|
|
26
|
-
**
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
37
|
+
- **🗂️ File** - File system operations with intelligent watching
|
|
38
|
+
- **⚙️ Compile** - Asset compilation with progress tracking
|
|
39
|
+
- **📝 Configurator** - Configuration management with hot-reloading
|
|
40
|
+
- **🏃 Run** - Build orchestration and task execution
|
|
41
|
+
- **🌐 Server** - Express server with kernel-based request handling
|
|
42
|
+
- **🔄 LiveReload** - Development live-reload with WebSocket
|
|
43
|
+
- **🛣️ Router** - Route processing for both static and dynamic content
|
|
44
|
+
- **💾 Cache** - Smart caching for incremental builds
|
|
45
|
+
|
|
46
|
+
### Operating Modes
|
|
47
|
+
|
|
48
|
+
**🗂️ Static Mode (`type: 'static'`)**:
|
|
49
|
+
- Generates optimized static HTML files
|
|
50
|
+
- Perfect for blogs, documentation, marketing sites
|
|
51
|
+
- Uses development server only for live reload
|
|
52
|
+
- Deployable to any static hosting (Netlify, Vercel, GitHub Pages)
|
|
53
|
+
|
|
54
|
+
**🌐 Server Mode (`type: 'server'`)**:
|
|
55
|
+
- Full Express.js web application
|
|
56
|
+
- API endpoints with state management
|
|
57
|
+
- Server-side rendering with dynamic routes
|
|
58
|
+
- Database integration and real-time features
|
|
59
|
+
- Perfect for web apps, dashboards, APIs
|
|
30
60
|
|
|
31
61
|
## Project Structure
|
|
32
62
|
|
|
@@ -101,289 +131,327 @@ actions(useContext) {
|
|
|
101
131
|
- **Incremental Builds**: Smart caching for faster rebuilds
|
|
102
132
|
- **Auto-Discovery**: Intelligent project structure detection
|
|
103
133
|
|
|
104
|
-
## Usage
|
|
134
|
+
## 📦 Installation & Usage
|
|
105
135
|
|
|
106
|
-
###
|
|
136
|
+
### Creating New Projects
|
|
107
137
|
|
|
108
|
-
####
|
|
138
|
+
#### Quick Start with Templates
|
|
109
139
|
```bash
|
|
110
|
-
#
|
|
111
|
-
|
|
140
|
+
# Static site (blogs, docs, marketing)
|
|
141
|
+
npx clovie create my-blog --template static
|
|
112
142
|
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
npm run dev
|
|
116
|
-
```
|
|
143
|
+
# Server application (APIs, web apps)
|
|
144
|
+
npx clovie create my-app --template server
|
|
117
145
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# Install globally
|
|
121
|
-
npm install -g clovie
|
|
146
|
+
# Default (auto-detected)
|
|
147
|
+
npx clovie create my-site
|
|
122
148
|
```
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
#### Using Clovie CLI (Recommended)
|
|
150
|
+
#### Manual Installation
|
|
127
151
|
```bash
|
|
128
|
-
#
|
|
129
|
-
|
|
152
|
+
# Install in existing project
|
|
153
|
+
npm install --save-dev clovie
|
|
130
154
|
|
|
131
|
-
# Or
|
|
132
|
-
|
|
155
|
+
# Or globally
|
|
156
|
+
npm install -g clovie
|
|
133
157
|
```
|
|
134
158
|
|
|
159
|
+
### Development Workflow
|
|
135
160
|
|
|
136
|
-
|
|
137
|
-
### Building and Development
|
|
138
|
-
|
|
139
|
-
#### Static Mode (Default)
|
|
161
|
+
#### 🗂️ Static Site Development
|
|
140
162
|
```bash
|
|
141
|
-
#
|
|
142
|
-
|
|
163
|
+
# Start development server with live reload
|
|
164
|
+
npm run dev
|
|
143
165
|
# or
|
|
144
|
-
|
|
166
|
+
clovie dev
|
|
145
167
|
|
|
146
|
-
#
|
|
147
|
-
|
|
168
|
+
# Build optimized static files
|
|
169
|
+
npm run build
|
|
148
170
|
# or
|
|
149
|
-
|
|
171
|
+
clovie build
|
|
172
|
+
|
|
173
|
+
# Preview production build
|
|
174
|
+
clovie serve --static
|
|
150
175
|
```
|
|
151
176
|
|
|
152
|
-
#### Server
|
|
177
|
+
#### 🌐 Server Application Development
|
|
153
178
|
```bash
|
|
154
|
-
#
|
|
155
|
-
|
|
156
|
-
# or
|
|
157
|
-
|
|
179
|
+
# Start development server with live reload
|
|
180
|
+
npm run dev
|
|
181
|
+
# or
|
|
182
|
+
clovie dev
|
|
183
|
+
|
|
184
|
+
# Start production server
|
|
185
|
+
npm start
|
|
186
|
+
# or
|
|
187
|
+
clovie serve
|
|
188
|
+
|
|
189
|
+
# Build assets only (server handles routing)
|
|
190
|
+
clovie build
|
|
158
191
|
```
|
|
159
192
|
|
|
160
|
-
## Configuration
|
|
193
|
+
## ⚙️ Configuration
|
|
161
194
|
|
|
162
|
-
###
|
|
195
|
+
### Zero Config Start
|
|
163
196
|
|
|
164
|
-
Clovie uses smart
|
|
197
|
+
Clovie uses **smart auto-detection** - just create your files and start:
|
|
165
198
|
|
|
166
199
|
```javascript
|
|
200
|
+
// clovie.config.js (minimal)
|
|
167
201
|
export default {
|
|
168
202
|
data: {
|
|
169
|
-
title: 'My Site'
|
|
203
|
+
title: 'My Site',
|
|
204
|
+
description: 'Built with Clovie'
|
|
170
205
|
}
|
|
171
206
|
};
|
|
172
207
|
```
|
|
173
208
|
|
|
174
|
-
|
|
175
|
-
- `views/`
|
|
176
|
-
- `scripts/main.js`
|
|
177
|
-
- `styles/main.scss`
|
|
178
|
-
- `assets/`
|
|
209
|
+
Automatically detects:
|
|
210
|
+
- `views/` → HTML templates
|
|
211
|
+
- `scripts/main.js` → JavaScript entry
|
|
212
|
+
- `styles/main.scss` → SCSS entry
|
|
213
|
+
- `assets/` → Static assets
|
|
214
|
+
- `partials/` → Reusable components
|
|
215
|
+
|
|
216
|
+
### 🗂️ Static Site Configuration
|
|
179
217
|
|
|
180
|
-
|
|
218
|
+
Perfect for blogs, documentation, and marketing sites:
|
|
181
219
|
|
|
182
220
|
```javascript
|
|
183
221
|
export default {
|
|
184
|
-
type: 'static', //
|
|
185
|
-
|
|
186
|
-
// Auto-detected paths (override if needed)
|
|
187
|
-
views: './src/views',
|
|
188
|
-
scripts: './src/js/app.js',
|
|
189
|
-
styles: './src/scss/main.scss',
|
|
190
|
-
assets: './public',
|
|
191
|
-
outputDir: './dist',
|
|
222
|
+
type: 'static', // Generate static HTML files
|
|
192
223
|
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
224
|
+
// Data available in all templates
|
|
225
|
+
data: {
|
|
226
|
+
site: {
|
|
227
|
+
title: 'My Blog',
|
|
228
|
+
url: 'https://myblog.com',
|
|
229
|
+
description: 'A fast static blog'
|
|
230
|
+
},
|
|
231
|
+
nav: [
|
|
232
|
+
{ title: 'Home', url: '/' },
|
|
233
|
+
{ title: 'About', url: '/about' },
|
|
234
|
+
{ title: 'Blog', url: '/blog' }
|
|
235
|
+
]
|
|
196
236
|
},
|
|
197
237
|
|
|
198
|
-
//
|
|
238
|
+
// Template engine (auto-detected from usage)
|
|
239
|
+
renderEngine: 'handlebars', // or nunjucks, pug, custom function
|
|
240
|
+
|
|
241
|
+
// Dynamic pages from data
|
|
199
242
|
routes: [{
|
|
200
243
|
name: 'Blog Posts',
|
|
201
244
|
path: '/posts/:slug',
|
|
202
245
|
template: 'post.html',
|
|
203
|
-
repeat: (
|
|
204
|
-
data: (
|
|
205
|
-
...
|
|
206
|
-
|
|
207
|
-
|
|
246
|
+
repeat: (data) => data.posts, // Generate page for each post
|
|
247
|
+
data: (globalData, post) => ({
|
|
248
|
+
...globalData,
|
|
249
|
+
post,
|
|
250
|
+
title: `${post.title} - ${globalData.site.title}`
|
|
208
251
|
})
|
|
209
|
-
}]
|
|
252
|
+
}],
|
|
253
|
+
|
|
254
|
+
// Build optimizations
|
|
255
|
+
minify: true,
|
|
256
|
+
generateSitemap: true
|
|
210
257
|
};
|
|
211
258
|
```
|
|
212
259
|
|
|
213
|
-
### Server Application Configuration
|
|
260
|
+
### 🌐 Server Application Configuration
|
|
261
|
+
|
|
262
|
+
Full-stack web applications with APIs and dynamic content:
|
|
214
263
|
|
|
215
264
|
```javascript
|
|
265
|
+
import express from 'express';
|
|
266
|
+
|
|
216
267
|
export default {
|
|
217
268
|
type: 'server', // Express application mode
|
|
218
|
-
|
|
219
269
|
port: 3000,
|
|
220
|
-
outputDir: './dist', // Serve static files from here
|
|
221
|
-
|
|
222
|
-
// Same view/asset processing as static mode
|
|
223
|
-
views: './src/views',
|
|
224
|
-
scripts: './src/js',
|
|
225
|
-
styles: './src/scss',
|
|
226
270
|
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
handler: async (req, res) => {
|
|
233
|
-
const posts = await getPosts();
|
|
234
|
-
res.json(posts);
|
|
235
|
-
}
|
|
236
|
-
}, {
|
|
237
|
-
name: 'Post Pages',
|
|
238
|
-
path: '/posts/:slug',
|
|
239
|
-
template: 'post.html',
|
|
240
|
-
data: async (state, params) => {
|
|
241
|
-
const post = await getPost(params.slug);
|
|
242
|
-
return { post };
|
|
271
|
+
// Shared data and configuration
|
|
272
|
+
data: {
|
|
273
|
+
app: {
|
|
274
|
+
name: 'My App',
|
|
275
|
+
version: '1.0.0'
|
|
243
276
|
}
|
|
244
|
-
}
|
|
277
|
+
},
|
|
245
278
|
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
path: '/api/users',
|
|
249
|
-
method: 'POST',
|
|
250
|
-
handler: async (req, res) => {
|
|
251
|
-
const user = await createUser(req.body);
|
|
252
|
-
res.json(user);
|
|
253
|
-
}
|
|
254
|
-
}],
|
|
279
|
+
// Database configuration (optional)
|
|
280
|
+
dbPath: './data/app.db',
|
|
255
281
|
|
|
256
282
|
// Express middleware
|
|
257
283
|
middleware: [
|
|
258
284
|
express.json(),
|
|
259
|
-
|
|
285
|
+
express.urlencoded({ extended: true }),
|
|
286
|
+
// Add CORS, authentication, etc.
|
|
287
|
+
],
|
|
288
|
+
|
|
289
|
+
// API endpoints
|
|
290
|
+
api: [
|
|
291
|
+
{
|
|
292
|
+
path: '/api/users',
|
|
293
|
+
method: 'GET',
|
|
294
|
+
action: async (state, event) => {
|
|
295
|
+
const users = await state.db.query('SELECT * FROM users');
|
|
296
|
+
return { users, total: users.length };
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
path: '/api/users',
|
|
301
|
+
method: 'POST',
|
|
302
|
+
action: async (state, event) => {
|
|
303
|
+
const { name, email } = event.body;
|
|
304
|
+
const user = await state.db.insert('users', { name, email });
|
|
305
|
+
return { success: true, user };
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
path: '/api/users/:id',
|
|
310
|
+
method: 'GET',
|
|
311
|
+
action: async (state, event) => {
|
|
312
|
+
const user = await state.db.findById('users', event.params.id);
|
|
313
|
+
return user ? { user } : { error: 'User not found', status: 404 };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
],
|
|
317
|
+
|
|
318
|
+
// Server-rendered routes
|
|
319
|
+
routes: [
|
|
320
|
+
{
|
|
321
|
+
name: 'User Dashboard',
|
|
322
|
+
path: '/dashboard/:userId',
|
|
323
|
+
template: 'dashboard.html',
|
|
324
|
+
data: async (state, params) => {
|
|
325
|
+
const user = await state.db.findById('users', params.userId);
|
|
326
|
+
const stats = await getUserStats(params.userId);
|
|
327
|
+
return { user, stats, title: `Dashboard - ${user.name}` };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
260
330
|
]
|
|
261
331
|
};
|
|
262
332
|
```
|
|
263
333
|
|
|
264
|
-
## Advanced Features
|
|
334
|
+
## 🚀 Advanced Features
|
|
265
335
|
|
|
266
|
-
###
|
|
336
|
+
### 📊 Database Integration (Server Mode)
|
|
267
337
|
|
|
268
|
-
Clovie
|
|
338
|
+
Clovie includes built-in SQLite database support for server applications:
|
|
269
339
|
|
|
270
340
|
```javascript
|
|
271
|
-
// clovie.config.js
|
|
272
341
|
export default {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
342
|
+
type: 'server',
|
|
343
|
+
dbPath: './data/app.db', // SQLite database path
|
|
344
|
+
|
|
345
|
+
// Database is available in API actions and routes
|
|
346
|
+
api: [{
|
|
347
|
+
path: '/api/posts',
|
|
348
|
+
method: 'GET',
|
|
349
|
+
action: async (state, event) => {
|
|
350
|
+
// Access database through state.db
|
|
351
|
+
const posts = await state.db.query('SELECT * FROM posts ORDER BY created_at DESC');
|
|
352
|
+
return { posts };
|
|
353
|
+
}
|
|
354
|
+
}]
|
|
285
355
|
};
|
|
286
356
|
```
|
|
287
357
|
|
|
288
|
-
###
|
|
358
|
+
### 🔄 Async Data Loading
|
|
289
359
|
|
|
290
|
-
|
|
360
|
+
Load data dynamically at build time or runtime:
|
|
291
361
|
|
|
292
362
|
```javascript
|
|
293
|
-
// clovie.config.js
|
|
294
363
|
export default {
|
|
295
|
-
//
|
|
296
|
-
data: {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
364
|
+
// Static: Load data at build time
|
|
365
|
+
data: async () => {
|
|
366
|
+
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
|
|
367
|
+
const authors = await loadAuthorsFromFile('./data/authors.json');
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
site: { title: 'My Blog' },
|
|
371
|
+
posts,
|
|
372
|
+
authors,
|
|
373
|
+
buildTime: new Date().toISOString()
|
|
374
|
+
};
|
|
303
375
|
},
|
|
376
|
+
|
|
377
|
+
// Server: Load data per request
|
|
304
378
|
routes: [{
|
|
305
|
-
name: 'Blog Posts',
|
|
306
379
|
path: '/posts/:slug',
|
|
307
380
|
template: 'post.html',
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
})
|
|
381
|
+
data: async (state, params) => {
|
|
382
|
+
const post = await fetchPostBySlug(params.slug);
|
|
383
|
+
const comments = await fetchComments(post.id);
|
|
384
|
+
return { post, comments };
|
|
385
|
+
}
|
|
314
386
|
}]
|
|
315
387
|
};
|
|
316
388
|
```
|
|
317
389
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
<html>
|
|
322
|
-
<head>
|
|
323
|
-
<title>{{title}} - {{../title}}</title>
|
|
324
|
-
</head>
|
|
325
|
-
<body>
|
|
326
|
-
<article>
|
|
327
|
-
<h1>{{title}}</h1>
|
|
328
|
-
<p>{{excerpt}}</p>
|
|
329
|
-
<div>{{content}}</div>
|
|
330
|
-
</article>
|
|
331
|
-
</body>
|
|
332
|
-
</html>
|
|
333
|
-
```
|
|
390
|
+
### 🎯 Dynamic Route Generation
|
|
391
|
+
|
|
392
|
+
Generate pages from data with powerful routing:
|
|
334
393
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
394
|
+
```javascript
|
|
395
|
+
export default {
|
|
396
|
+
data: {
|
|
397
|
+
posts: [
|
|
398
|
+
{ id: 1, title: 'Getting Started', slug: 'getting-started', category: 'tutorial' },
|
|
399
|
+
{ id: 2, title: 'Advanced Usage', slug: 'advanced-usage', category: 'guide' }
|
|
400
|
+
],
|
|
401
|
+
categories: ['tutorial', 'guide', 'news']
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
routes: [
|
|
405
|
+
// Individual post pages
|
|
406
|
+
{
|
|
407
|
+
name: 'Blog Posts',
|
|
408
|
+
path: '/posts/:slug',
|
|
409
|
+
template: 'post.html',
|
|
410
|
+
repeat: (data) => data.posts,
|
|
411
|
+
data: (globalData, post) => ({ ...globalData, post })
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
// Category pages
|
|
415
|
+
{
|
|
416
|
+
name: 'Category Pages',
|
|
417
|
+
path: '/category/:category',
|
|
418
|
+
template: 'category.html',
|
|
419
|
+
repeat: (data) => data.categories,
|
|
420
|
+
data: (globalData, category) => ({
|
|
421
|
+
...globalData,
|
|
422
|
+
category,
|
|
423
|
+
posts: globalData.posts.filter(p => p.category === category)
|
|
424
|
+
})
|
|
425
|
+
}
|
|
426
|
+
]
|
|
427
|
+
};
|
|
428
|
+
```
|
|
339
429
|
|
|
340
|
-
###
|
|
430
|
+
### 🎨 Template Engine Support
|
|
341
431
|
|
|
342
|
-
|
|
432
|
+
Use any template engine or create custom ones:
|
|
343
433
|
|
|
344
|
-
#### Handlebars
|
|
345
434
|
```javascript
|
|
435
|
+
// Handlebars
|
|
346
436
|
import Handlebars from 'handlebars';
|
|
347
|
-
|
|
348
437
|
export default {
|
|
349
|
-
|
|
350
|
-
compiler: (template, data) => {
|
|
438
|
+
renderEngine: (template, data) => {
|
|
351
439
|
const compiled = Handlebars.compile(template);
|
|
352
440
|
return compiled(data);
|
|
353
441
|
}
|
|
354
442
|
};
|
|
355
|
-
```
|
|
356
443
|
|
|
357
|
-
|
|
358
|
-
```javascript
|
|
444
|
+
// Nunjucks
|
|
359
445
|
import nunjucks from 'nunjucks';
|
|
360
|
-
|
|
361
446
|
export default {
|
|
362
|
-
|
|
363
|
-
compiler: (template, data) => {
|
|
447
|
+
renderEngine: (template, data) => {
|
|
364
448
|
return nunjucks.renderString(template, data);
|
|
365
449
|
}
|
|
366
450
|
};
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
#### Pug
|
|
370
|
-
```javascript
|
|
371
|
-
import pug from 'pug';
|
|
372
451
|
|
|
452
|
+
// Custom engine
|
|
373
453
|
export default {
|
|
374
|
-
|
|
375
|
-
compiler: (template, data) => {
|
|
376
|
-
return pug.render(template, { ...data, pretty: true });
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
#### Custom Engine
|
|
382
|
-
```javascript
|
|
383
|
-
export default {
|
|
384
|
-
// ... other config
|
|
385
|
-
compiler: (template, data) => {
|
|
386
|
-
// Simple variable replacement
|
|
454
|
+
renderEngine: (template, data) => {
|
|
387
455
|
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
388
456
|
return data[key] || match;
|
|
389
457
|
});
|
|
@@ -391,185 +459,183 @@ export default {
|
|
|
391
459
|
};
|
|
392
460
|
```
|
|
393
461
|
|
|
394
|
-
###
|
|
462
|
+
### 🛠️ CLI Commands
|
|
395
463
|
|
|
396
|
-
|
|
464
|
+
Clovie includes powerful CLI tools for development and deployment:
|
|
397
465
|
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
routes: [{
|
|
402
|
-
name: 'Blog Pagination',
|
|
403
|
-
path: '/blog/:page?',
|
|
404
|
-
template: 'blog.html',
|
|
405
|
-
paginate: 5, // 5 posts per page
|
|
406
|
-
repeat: (state) => state.get(['posts']),
|
|
407
|
-
data: (state, posts, pageInfo) => ({
|
|
408
|
-
posts,
|
|
409
|
-
pagination: pageInfo,
|
|
410
|
-
title: `Blog - Page ${pageInfo.current}`
|
|
411
|
-
})
|
|
412
|
-
}]
|
|
413
|
-
};
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**Output:**
|
|
417
|
-
- `blog.html` - First 5 posts (page 1)
|
|
418
|
-
- `blog/2.html` - Next 5 posts (page 2)
|
|
419
|
-
- `blog/3.html` - Remaining posts (page 3)
|
|
466
|
+
```bash
|
|
467
|
+
# Project creation
|
|
468
|
+
clovie create <name> [--template static|server|default]
|
|
420
469
|
|
|
421
|
-
|
|
470
|
+
# Development
|
|
471
|
+
clovie dev # Start development server with live reload
|
|
472
|
+
clovie watch # Alias for dev
|
|
422
473
|
|
|
423
|
-
|
|
474
|
+
# Building
|
|
475
|
+
clovie build # Build for production
|
|
476
|
+
clovie serve # Start production server
|
|
424
477
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
name: 'Products',
|
|
430
|
-
path: '/products/:slug',
|
|
431
|
-
template: 'product.html',
|
|
432
|
-
repeat: (state) => state.get(['products']),
|
|
433
|
-
data: (state, product) => ({
|
|
434
|
-
...product,
|
|
435
|
-
price: `$${product.price.toFixed(2)}`,
|
|
436
|
-
slug: product.name.toLowerCase().replace(/\s+/g, '-'),
|
|
437
|
-
inStock: product.quantity > 0,
|
|
438
|
-
relatedProducts: state.get(['products']).filter(p =>
|
|
439
|
-
p.category === product.category && p.id !== product.id
|
|
440
|
-
)
|
|
441
|
-
})
|
|
442
|
-
}]
|
|
443
|
-
};
|
|
478
|
+
# Utilities
|
|
479
|
+
clovie kill --port 3000 # Kill process on port 3000
|
|
480
|
+
clovie kill --common # Kill processes on common dev ports
|
|
481
|
+
clovie kill --check # Check which ports are in use
|
|
444
482
|
```
|
|
445
483
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
### Error Handling
|
|
449
|
-
|
|
450
|
-
Clovie includes robust error handling for common issues:
|
|
484
|
+
### 📁 Project Structure
|
|
451
485
|
|
|
452
|
-
|
|
453
|
-
- **File read errors**: Continues processing even if individual files fail
|
|
454
|
-
- **Template errors**: Provides clear error messages for compilation failures
|
|
455
|
-
- **Data validation**: Warns about invalid data structures
|
|
456
|
-
|
|
457
|
-
### Progress Indicators
|
|
458
|
-
|
|
459
|
-
Clovie provides clear feedback during builds:
|
|
486
|
+
When you create a new project, you get a clean, organized structure:
|
|
460
487
|
|
|
461
488
|
```
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
489
|
+
my-site/
|
|
490
|
+
├── clovie.config.js # Configuration file
|
|
491
|
+
├── package.json # Dependencies and scripts
|
|
492
|
+
├── views/ # HTML templates
|
|
493
|
+
│ ├── index.html # Homepage
|
|
494
|
+
│ └── about.html # Additional pages
|
|
495
|
+
├── partials/ # Reusable components (optional)
|
|
496
|
+
│ ├── header.html # Site header
|
|
497
|
+
│ └── footer.html # Site footer
|
|
498
|
+
├── scripts/ # JavaScript
|
|
499
|
+
│ └── main.js # Main JS entry point
|
|
500
|
+
├── styles/ # SCSS/CSS
|
|
501
|
+
│ └── main.scss # Main stylesheet
|
|
502
|
+
├── assets/ # Static files
|
|
503
|
+
│ └── images/ # Images, fonts, etc.
|
|
504
|
+
└── dist/ # Build output (generated)
|
|
478
505
|
```
|
|
479
506
|
|
|
480
|
-
###
|
|
507
|
+
### 🚀 Performance Features
|
|
481
508
|
|
|
482
|
-
|
|
509
|
+
- **⚡ Incremental Builds**: Only rebuilds changed files
|
|
510
|
+
- **📦 Smart Caching**: Content-based cache invalidation
|
|
511
|
+
- **🔄 Live Reload**: WebSocket-based for instant updates
|
|
512
|
+
- **📊 Progress Tracking**: Real-time build progress
|
|
513
|
+
- **🗜️ Asset Optimization**: Minification and optimization
|
|
514
|
+
- **🌐 Static + Server**: Best of both worlds
|
|
483
515
|
|
|
484
|
-
|
|
485
|
-
🔍 Auto-detected views directory: views
|
|
486
|
-
🔍 Auto-detected scripts entry: scripts/main.js
|
|
487
|
-
🔍 Auto-detected styles entry: styles/main.scss
|
|
488
|
-
🔍 Auto-detected assets directory: assets
|
|
489
|
-
```
|
|
516
|
+
## 💡 Best Practices & Tips
|
|
490
517
|
|
|
491
|
-
### Best Practices
|
|
518
|
+
### 🎯 Development Best Practices
|
|
492
519
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
6. **Separate static and dynamic routes** for better performance
|
|
520
|
+
**Static Sites:**
|
|
521
|
+
- Use `partials/` for reusable components (header, footer, nav)
|
|
522
|
+
- Organize data in the config file or external JSON files
|
|
523
|
+
- Use semantic HTML and meaningful route paths for SEO
|
|
524
|
+
- Test builds regularly with `npm run build`
|
|
499
525
|
|
|
500
|
-
|
|
526
|
+
**Server Applications:**
|
|
527
|
+
- Validate input data in API actions
|
|
528
|
+
- Use middleware for authentication and request parsing
|
|
529
|
+
- Handle errors gracefully in API endpoints
|
|
530
|
+
- Implement proper database migrations and seeding
|
|
501
531
|
|
|
502
|
-
|
|
532
|
+
### 🔧 Configuration Tips
|
|
503
533
|
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
534
|
+
```javascript
|
|
535
|
+
export default {
|
|
536
|
+
// Environment-specific config
|
|
537
|
+
...(process.env.NODE_ENV === 'production' && {
|
|
538
|
+
baseUrl: 'https://mysite.com',
|
|
539
|
+
minify: true
|
|
540
|
+
}),
|
|
541
|
+
|
|
542
|
+
// Async data with error handling
|
|
543
|
+
data: async () => {
|
|
544
|
+
try {
|
|
545
|
+
const posts = await fetchPosts();
|
|
546
|
+
return { posts, lastUpdated: Date.now() };
|
|
547
|
+
} catch (error) {
|
|
548
|
+
console.warn('Failed to fetch posts:', error);
|
|
549
|
+
return { posts: [], lastUpdated: Date.now() };
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
};
|
|
516
553
|
```
|
|
517
554
|
|
|
518
|
-
|
|
519
|
-
You can also create your own structure:
|
|
555
|
+
### 📊 Performance Optimization
|
|
520
556
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
└── data/ # Data files (optional)
|
|
536
|
-
└── posts.json
|
|
557
|
+
- **Use incremental builds**: Clovie's caching handles this automatically
|
|
558
|
+
- **Optimize images**: Place optimized images in `assets/`
|
|
559
|
+
- **Minimize JavaScript**: Use esbuild's built-in minification
|
|
560
|
+
- **Cache API responses**: Implement caching in server mode API actions
|
|
561
|
+
- **Static generation**: Use static mode for content that doesn't change often
|
|
562
|
+
|
|
563
|
+
### 🔄 Development Workflow
|
|
564
|
+
|
|
565
|
+
```bash
|
|
566
|
+
# Recommended development flow
|
|
567
|
+
npm run dev # Start with live reload
|
|
568
|
+
# Edit files and see changes instantly
|
|
569
|
+
npm run build # Test production build
|
|
570
|
+
npm run serve # Test production serving (server mode)
|
|
537
571
|
```
|
|
538
572
|
|
|
539
|
-
## Development
|
|
573
|
+
## 🛠️ Development & Contributing
|
|
540
574
|
|
|
541
575
|
```bash
|
|
576
|
+
# Clone repository
|
|
577
|
+
git clone https://github.com/adrianjonmiller/clovie.git
|
|
578
|
+
cd clovie
|
|
579
|
+
|
|
542
580
|
# Install dependencies
|
|
543
581
|
npm install
|
|
544
582
|
|
|
545
|
-
# Run tests
|
|
583
|
+
# Run tests
|
|
546
584
|
npm test
|
|
585
|
+
npm run test:watch # Watch mode
|
|
586
|
+
npm run test:coverage # Coverage report
|
|
547
587
|
|
|
548
|
-
#
|
|
549
|
-
npm run
|
|
588
|
+
# Build package
|
|
589
|
+
npm run build
|
|
590
|
+
|
|
591
|
+
# Test with example projects
|
|
592
|
+
npm run dev # Uses __dev__ example
|
|
550
593
|
```
|
|
551
594
|
|
|
552
|
-
## Troubleshooting
|
|
595
|
+
## 🐛 Troubleshooting
|
|
553
596
|
|
|
554
597
|
### Common Issues
|
|
555
598
|
|
|
556
|
-
**
|
|
557
|
-
|
|
558
|
-
|
|
599
|
+
**Port Already in Use**
|
|
600
|
+
```bash
|
|
601
|
+
clovie kill --port 3000 # Kill specific port
|
|
602
|
+
clovie kill --common # Kill common dev ports
|
|
603
|
+
clovie kill --check # Check port status
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
**Build Errors**
|
|
607
|
+
- Check that all file paths in config exist
|
|
608
|
+
- Verify template syntax matches your render engine
|
|
609
|
+
- Ensure async data functions handle errors properly
|
|
610
|
+
- Check console output for detailed error messages
|
|
611
|
+
|
|
612
|
+
**Template Not Found**
|
|
613
|
+
- Verify the `views` directory path in your config
|
|
614
|
+
- Check that template files have correct extensions
|
|
615
|
+
- Ensure partial files are in the `partials` directory
|
|
616
|
+
|
|
617
|
+
**Database Connection Issues (Server Mode)**
|
|
618
|
+
- Check that `dbPath` in config points to a writable directory
|
|
619
|
+
- Ensure SQLite is properly installed
|
|
620
|
+
- Verify database initialization in your API actions
|
|
621
|
+
|
|
622
|
+
**Live Reload Not Working**
|
|
623
|
+
- Check that you're in development mode (`npm run dev`)
|
|
624
|
+
- Verify WebSocket connection in browser dev tools
|
|
625
|
+
- Try refreshing the page manually
|
|
626
|
+
|
|
627
|
+
### Getting Help
|
|
628
|
+
|
|
629
|
+
- 📚 [Documentation](https://github.com/adrianjonmiller/clovie)
|
|
630
|
+
- 🐛 [Issue Tracker](https://github.com/adrianjonmiller/clovie/issues)
|
|
631
|
+
- 💬 [Discussions](https://github.com/adrianjonmiller/clovie/discussions)
|
|
559
632
|
|
|
560
|
-
|
|
561
|
-
- Check that your route's repeat function returns an array
|
|
562
|
-
- Ensure the data structure matches the route configuration
|
|
633
|
+
## 📄 License
|
|
563
634
|
|
|
564
|
-
|
|
565
|
-
- Check for circular symlinks or extremely deep directory structures
|
|
566
|
-
- The limit is 50 levels deep (configurable in code)
|
|
635
|
+
MIT - see [LICENSE](LICENSE) file for details.
|
|
567
636
|
|
|
568
|
-
|
|
569
|
-
- Check console output for specific error messages
|
|
570
|
-
- Verify all referenced files exist
|
|
571
|
-
- Ensure template syntax matches your compiler
|
|
637
|
+
---
|
|
572
638
|
|
|
573
|
-
|
|
639
|
+
**Built with ❤️ by [Adrian Miller](https://github.com/adrianjonmiller)**
|
|
574
640
|
|
|
575
|
-
|
|
641
|
+
*Clovie: Vintage web dev tooling with modern quality of life.*
|