create-gardener 2.1.3 → 2.1.5
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 +108 -302
- package/package.json +1 -1
- package/template/.env +3 -0
- package/template/README.md +181 -0
- package/template/buildHelper.js +5 -0
- package/template/src/backend/controllers/gardener/hotReload.ts +34 -0
- package/template/src/backend/controllers/gardener/imageOptimiser.ts +114 -25
- package/template/src/backend/controllers/gardener/index.ts +1 -0
- package/template/src/backend/routes/gardener.route.ts +2 -1
- package/template/src/backend/server.ts +19 -1
- package/template/src/frontend/assets/remote/betterway.jpg +0 -0
- package/template/src/frontend/static/components/gardener/hotReloadbtn.js +25 -78
- package/template/src/frontend/static/gardenerDev.js +2 -18
- package/template/src/frontend/static/style.css +0 -77
- package/template/src/frontend/views/_.ejs +101 -89
- package/template/build/backend/controllers/gardener/addComponent.d.ts +0 -8
- package/template/build/backend/controllers/gardener/addComponent.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/addComponent.js +0 -19
- package/template/build/backend/controllers/gardener/addComponent.js.map +0 -1
- package/template/build/backend/controllers/gardener/addPage.d.ts +0 -3
- package/template/build/backend/controllers/gardener/addPage.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/addPage.js +0 -86
- package/template/build/backend/controllers/gardener/addPage.js.map +0 -1
- package/template/build/backend/controllers/gardener/createStatic.d.ts +0 -3
- package/template/build/backend/controllers/gardener/createStatic.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/createStatic.js +0 -63
- package/template/build/backend/controllers/gardener/createStatic.js.map +0 -1
- package/template/build/backend/controllers/gardener/imageOptimiser.d.ts +0 -3
- package/template/build/backend/controllers/gardener/imageOptimiser.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/imageOptimiser.js +0 -54
- package/template/build/backend/controllers/gardener/imageOptimiser.js.map +0 -1
- package/template/build/backend/controllers/gardener/index.d.ts +0 -6
- package/template/build/backend/controllers/gardener/index.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/index.js +0 -6
- package/template/build/backend/controllers/gardener/index.js.map +0 -1
- package/template/build/backend/controllers/gardener/saveTemplate.d.ts +0 -3
- package/template/build/backend/controllers/gardener/saveTemplate.d.ts.map +0 -1
- package/template/build/backend/controllers/gardener/saveTemplate.js +0 -36
- package/template/build/backend/controllers/gardener/saveTemplate.js.map +0 -1
- package/template/build/backend/libs/generateWebp.d.ts +0 -2
- package/template/build/backend/libs/generateWebp.d.ts.map +0 -1
- package/template/build/backend/libs/generateWebp.js +0 -16
- package/template/build/backend/libs/generateWebp.js.map +0 -1
- package/template/build/backend/routes/gardener.route.d.ts +0 -4
- package/template/build/backend/routes/gardener.route.d.ts.map +0 -1
- package/template/build/backend/routes/gardener.route.js +0 -18
- package/template/build/backend/routes/gardener.route.js.map +0 -1
- package/template/build/backend/server.d.ts +0 -2
- package/template/build/backend/server.d.ts.map +0 -1
- package/template/build/backend/server.js +0 -20
- package/template/build/backend/server.js.map +0 -1
- package/template/build/frontend/assets/favicon.png +0 -0
- package/template/build/frontend/assets/gardener.jpg +0 -0
- package/template/build/frontend/static/bundle/bundle._.js +0 -1
- package/template/build/frontend/static/bundle/bundle._about.js +0 -1
- package/template/build/frontend/static/bundle/bundle._kartik.js +0 -1
- package/template/build/frontend/static/bundle/bundle._new.js +0 -1
- package/template/build/frontend/static/bundle/bundle._ritish.js +0 -1
- package/template/build/frontend/static/cache/favicon_500x500.webp +0 -0
- package/template/build/frontend/static/cache/favicon_50x50.webp +0 -0
- package/template/build/frontend/static/cache/gardener_100x100.webp +0 -0
- package/template/build/frontend/static/cache/gardener_500x500.webp +0 -0
- package/template/build/frontend/static/cache/gardener_50x50.webp +0 -0
- package/template/build/frontend/static/components/copybtn.js +0 -99
- package/template/build/frontend/static/components/footer.js +0 -33
- package/template/build/frontend/static/components/gardener/errorBox.js +0 -47
- package/template/build/frontend/static/components/gardener/hotReloadbtn.js +0 -82
- package/template/build/frontend/static/components/gardener/pageOverlayBtn.js +0 -138
- package/template/build/frontend/static/components/gardener/parserWindow.js +0 -159
- package/template/build/frontend/static/components/nonui/api.js +0 -52
- package/template/build/frontend/static/components/nonui/navigation.js +0 -59
- package/template/build/frontend/static/components/notification.js +0 -67
- package/template/build/frontend/static/gardener.js +0 -160
- package/template/build/frontend/static/gardenerConfig.js +0 -1
- package/template/build/frontend/static/gardenerDev.js +0 -165
- package/template/build/frontend/static/global.js +0 -4
- package/template/build/frontend/static/pages/pages._.js +0 -25
- package/template/build/frontend/static/pages/pages._about.js +0 -2
- package/template/build/frontend/static/pages/pages._kartik.js +0 -2
- package/template/build/frontend/static/pages/pages._new.js +0 -2
- package/template/build/frontend/static/pages/pages._ritish.js +0 -2
- package/template/build/frontend/static/style.css +0 -2
- package/template/build/frontend/static/style2.css +0 -26
- package/template/build/frontend/style.css +0 -1045
- package/template/build/frontend/tailwind.css +0 -1
- package/template/build/frontend/views/_.ejs +0 -125
- package/template/build/frontend/views/_about.ejs +0 -126
- package/template/build/frontend/views/_kartik.ejs +0 -126
- package/template/build/frontend/views/_new.ejs +0 -126
- package/template/build/frontend/views/_ritish.ejs +0 -126
- package/template/build/frontend/views/partials/icons/clipboard.ejs +0 -1
- package/template/build/frontend/views/partials/icons/clipboardok.ejs +0 -1
- package/template/src/frontend/static/cache/favicon_500x500.webp +0 -0
- package/template/src/frontend/static/cache/favicon_50x50.webp +0 -0
- package/template/src/frontend/static/cache/gardener_100x100.webp +0 -0
- package/template/src/frontend/static/cache/gardener_500x500.webp +0 -0
package/README.md
CHANGED
|
@@ -1,360 +1,165 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Gardener — DOM-First Mini Framework
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Gardener is a lightweight web framework built on top of Express and EJS. It enables building web applications without React or heavy frontend frameworks by using a DOM-first approach with reusable components.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Create a new Gardener app:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pnpm create gardener app
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Install dependencies and start development:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
pnpm install
|
|
17
|
-
pnpm dev
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Your app will be running with hot reload enabled!
|
|
21
|
-
|
|
22
|
-
## 🌟 Core Features
|
|
23
|
-
|
|
24
|
-
### Backend
|
|
25
|
-
- **Express.js**: Familiar Node.js backend with full Express capabilities
|
|
26
|
-
- **TypeScript Ready**: Built-in TypeScript support for type-safe development
|
|
27
|
-
- **Static Site Generation**: Export your dynamic app to static HTML with one API call
|
|
28
|
-
|
|
29
|
-
### Frontend
|
|
30
|
-
- **EJS Templating**: Server-side rendering with EJS views
|
|
31
|
-
- **Tailwind CSS**: Integrated with watch mode for rapid styling
|
|
32
|
-
- **Gardener Component System**: Unique DOM-to-JSON conversion for reusable components
|
|
33
|
-
- **Live Development Tools**: Browser-based route and component creation
|
|
34
|
-
|
|
35
|
-
### Developer Experience
|
|
36
|
-
- **Hot Reload**: Toggle with `Alt + H` for instant CSS updates
|
|
37
|
-
- **Visual Component Parser**: Convert DOM elements to JSON components in the browser
|
|
38
|
-
- **Browser-Based Routing**: Create new routes without touching your code
|
|
39
|
-
- **Image Optimization**: Automatic WebP conversion with smart sizing
|
|
40
|
-
|
|
41
|
-
## 📖 Complete Workflow
|
|
42
|
-
|
|
43
|
-
### 1. Backend Development
|
|
44
|
-
|
|
45
|
-
Write familiar Express.js code in TypeScript:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
// src/backend/server.ts
|
|
49
|
-
app.get('/api/posts', (req, res) => {
|
|
50
|
-
res.json({ posts: [] });
|
|
51
|
-
});
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2. Creating Pages & Routes
|
|
55
|
-
|
|
56
|
-
**Two ways to create routes:**
|
|
5
|
+
---
|
|
57
6
|
|
|
58
|
-
|
|
59
|
-
1. Click the "**New Page**" button that appears in development mode
|
|
60
|
-
2. Enter your route path (e.g., `/about`, `/blog/post`)
|
|
61
|
-
3. Press Enter - the route and EJS file are created automatically!
|
|
7
|
+
## What it does
|
|
62
8
|
|
|
63
|
-
|
|
64
|
-
Create an EJS file in `src/frontend/views/` and add the Express route manually.
|
|
9
|
+
Gardener lets you:
|
|
65
10
|
|
|
66
|
-
|
|
11
|
+
- Build UI using plain HTML, CSS, and JavaScript
|
|
12
|
+
- Convert DOM elements into reusable components
|
|
13
|
+
- Serve lightweight pages with minimal runtime overhead
|
|
67
14
|
|
|
68
|
-
|
|
15
|
+
---
|
|
69
16
|
|
|
70
|
-
|
|
71
|
-
Static components that render once:
|
|
72
|
-
```ejs
|
|
73
|
-
<%- include('partials/header') %>
|
|
74
|
-
```
|
|
17
|
+
## Why it exists
|
|
75
18
|
|
|
76
|
-
|
|
77
|
-
JSON-based components with the Gardener system:
|
|
78
|
-
|
|
79
|
-
**Creating a Component:**
|
|
80
|
-
1. Write your HTML structure in an EJS file or browser
|
|
81
|
-
2. In your JavaScript file, call:
|
|
82
|
-
```javascript
|
|
83
|
-
import { parser } from '/static/gardenerDev.js';
|
|
84
|
-
|
|
85
|
-
parser('.my-component-selector');
|
|
86
|
-
```
|
|
87
|
-
3. A window appears in the browser with the JSON representation
|
|
88
|
-
4. Name and save the component
|
|
89
|
-
5. The component is now reusable!
|
|
90
|
-
|
|
91
|
-
**Using a Component:**
|
|
92
|
-
```javascript
|
|
93
|
-
import { myComponent } from '/static/components/myComponent.js';
|
|
94
|
-
import { gardener, appendElement } from '/static/gardener.js';
|
|
95
|
-
|
|
96
|
-
// Render the component
|
|
97
|
-
const element = gardener(myComponent);
|
|
98
|
-
appendElement('#container', element);
|
|
99
|
-
```
|
|
19
|
+
Modern frameworks introduce significant abstraction and bundle size overhead.
|
|
100
20
|
|
|
101
|
-
|
|
102
|
-
```javascript
|
|
103
|
-
// Gardener components are JSON objects
|
|
104
|
-
export const button = {
|
|
105
|
-
t: 'button', // tag
|
|
106
|
-
cn: ['btn', 'primary'], // classNames
|
|
107
|
-
txt: 'Click me', // text content
|
|
108
|
-
attr: { id: 'submit' }, // attributes
|
|
109
|
-
events: { click: handleClick }, // event handlers
|
|
110
|
-
children: [...] // nested components
|
|
111
|
-
};
|
|
112
|
-
```
|
|
21
|
+
Gardener focuses on:
|
|
113
22
|
|
|
114
|
-
|
|
23
|
+
- Minimal runtime (~300 lines core)
|
|
24
|
+
- Direct DOM control
|
|
25
|
+
- Simplicity over abstraction
|
|
115
26
|
|
|
116
|
-
|
|
27
|
+
---
|
|
117
28
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
29
|
+
## Example
|
|
30
|
+
|
|
31
|
+
Define a component using JSON:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
{
|
|
35
|
+
"t": "div",
|
|
36
|
+
"cn": ["flex", "justify-center", "items-center", "target"],
|
|
37
|
+
"children": [
|
|
38
|
+
{
|
|
39
|
+
"t": "span",
|
|
40
|
+
"cn": ["text-xl", "font-bold"],
|
|
41
|
+
"txt": "Hello World"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"t": "button",
|
|
45
|
+
"txt": "click",
|
|
46
|
+
"events": {
|
|
47
|
+
"click": "() => console.log('button clicked')"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
126
50
|
]
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Use with parameters
|
|
130
|
-
const myCard = gardener(card, {
|
|
131
|
-
title: 'Hello',
|
|
132
|
-
description: 'World'
|
|
133
|
-
});
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### 5. Template System
|
|
137
|
-
|
|
138
|
-
**Save Current Page as Template:**
|
|
139
|
-
- Click "**Save Template**" button in the browser
|
|
140
|
-
- This saves the current page structure as a template
|
|
141
|
-
- Used automatically for deeper routes (e.g., `/blog/` template for `/blog/post-1`)
|
|
142
|
-
|
|
143
|
-
### 6. Dynamic Routes & Parameters
|
|
144
|
-
|
|
145
|
-
For parameterized routes like `/post/:id`:
|
|
146
|
-
|
|
147
|
-
**Backend:**
|
|
148
|
-
```javascript
|
|
149
|
-
app.get('/post/:id', (req, res) => {
|
|
150
|
-
res.render('post', {
|
|
151
|
-
id: req.params.id,
|
|
152
|
-
title: 'My Post'
|
|
153
|
-
});
|
|
154
|
-
});
|
|
51
|
+
}
|
|
155
52
|
```
|
|
156
53
|
|
|
157
|
-
|
|
158
|
-
```ejs
|
|
159
|
-
<h1>Post <%= id %></h1>
|
|
160
|
-
<p><%= title %></p>
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**Query Parameters:**
|
|
164
|
-
```javascript
|
|
165
|
-
// Backend
|
|
166
|
-
app.get('/search', (req, res) => {
|
|
167
|
-
const query = req.query.q;
|
|
168
|
-
res.render('search', { query });
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Frontend EJS
|
|
172
|
-
<p>Searching for: <%= query %></p>
|
|
173
|
-
```
|
|
54
|
+
You don’t need to write JSON manually.
|
|
174
55
|
|
|
175
|
-
|
|
56
|
+
Instead:
|
|
176
57
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
- Perfect for rapid styling iterations
|
|
181
|
-
|
|
182
|
-
### 8. Image Optimization
|
|
183
|
-
|
|
184
|
-
Use the built-in image optimizer:
|
|
185
|
-
|
|
186
|
-
```html
|
|
187
|
-
<img src="/static/image_800x600.webp" alt="Optimized">
|
|
188
|
-
```
|
|
58
|
+
1. Write standard HTML
|
|
59
|
+
2. Select an element (id/class)
|
|
60
|
+
3. Run the parser → generates reusable component
|
|
189
61
|
|
|
190
|
-
|
|
62
|
+
---
|
|
191
63
|
|
|
192
|
-
|
|
193
|
-
- Converts to WebP format
|
|
194
|
-
- Resizes to specified dimensions
|
|
195
|
-
- Caches for performance
|
|
64
|
+
## Key Features
|
|
196
65
|
|
|
197
|
-
|
|
66
|
+
- Lightweight (~300 lines core, bundled with esbuild)
|
|
67
|
+
- No frontend framework dependency
|
|
68
|
+
- Reusable components (DOM → JSON)
|
|
69
|
+
- Server-side rendering via EJS
|
|
70
|
+
- Hot reloading
|
|
71
|
+
- Image optimization (Sharp + caching)
|
|
72
|
+
- Static build support
|
|
73
|
+
- One-command page creation
|
|
198
74
|
|
|
199
|
-
|
|
75
|
+
---
|
|
200
76
|
|
|
201
|
-
|
|
202
|
-
// Make a GET request
|
|
203
|
-
fetch('/createStatic')
|
|
204
|
-
```
|
|
77
|
+
## Architecture
|
|
205
78
|
|
|
206
|
-
|
|
79
|
+
Gardener follows a simple request → render → enhance flow:
|
|
207
80
|
|
|
208
|
-
|
|
81
|
+
- Express handles routing and backend logic
|
|
82
|
+
- EJS renders templates into HTML
|
|
83
|
+
- Frontend library enhances DOM with:
|
|
84
|
+
- component system
|
|
85
|
+
- state handling
|
|
86
|
+
- dev tooling
|
|
209
87
|
|
|
210
|
-
|
|
88
|
+
---
|
|
211
89
|
|
|
212
|
-
|
|
90
|
+
## Components
|
|
213
91
|
|
|
214
|
-
|
|
215
|
-
import {
|
|
216
|
-
gardener, // Convert JSON to DOM elements
|
|
217
|
-
fetchElement, // Query selector wrapper
|
|
218
|
-
appendElement, // Append child with error handling
|
|
219
|
-
createElement, // Create element with classes
|
|
220
|
-
insertText, // Set text content
|
|
221
|
-
replaceElement // Replace element in DOM
|
|
222
|
-
} from '/static/gardener.js';
|
|
92
|
+
### Two types:
|
|
223
93
|
|
|
224
|
-
|
|
225
|
-
const el = gardener({
|
|
226
|
-
t: 'div',
|
|
227
|
-
cn: ['container'],
|
|
228
|
-
attr: { id: 'main' },
|
|
229
|
-
children: [...]
|
|
230
|
-
});
|
|
231
|
-
```
|
|
94
|
+
1. Static Components
|
|
232
95
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
```javascript
|
|
236
|
-
import {
|
|
237
|
-
parser, // Convert DOM to JSON
|
|
238
|
-
parserWindow, // Show parser UI
|
|
239
|
-
State, // Reactive state management
|
|
240
|
-
addEl // Add event listener helper
|
|
241
|
-
} from '/static/gardenerDev.js';
|
|
242
|
-
|
|
243
|
-
// Reactive State
|
|
244
|
-
const count = new State(0);
|
|
245
|
-
count.registerCb((value) => {
|
|
246
|
-
console.log('Count:', value);
|
|
247
|
-
});
|
|
248
|
-
count.setTo(1); // Triggers callback
|
|
249
|
-
```
|
|
96
|
+
- EJS partials
|
|
97
|
+
- Require full page reload
|
|
250
98
|
|
|
251
|
-
|
|
99
|
+
2. Dynamic Components
|
|
252
100
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
nextPage, // Navigate with animation
|
|
256
|
-
nextPagehandler, // Set up link handlers
|
|
257
|
-
pageloader // Handle page loader
|
|
258
|
-
} from '/static/components/nonui/navigation.js';
|
|
259
|
-
```
|
|
101
|
+
- Generated from DOM → JSON
|
|
102
|
+
- Reusable and parameterized
|
|
260
103
|
|
|
261
|
-
|
|
104
|
+
Example parameter:
|
|
262
105
|
|
|
263
|
-
|
|
264
|
-
import { Fetch } from '/static/components/nonui/api.js';
|
|
106
|
+
<span>?title?</span>
|
|
265
107
|
|
|
266
|
-
|
|
267
|
-
const response = await Fetch('/api/data', { key: 'value' }, 'POST');
|
|
268
|
-
const data = await response.json();
|
|
269
|
-
```
|
|
108
|
+
This creates a dynamic variable "title".
|
|
270
109
|
|
|
271
|
-
|
|
110
|
+
---
|
|
272
111
|
|
|
273
|
-
|
|
274
|
-
your-app/
|
|
275
|
-
├── src/
|
|
276
|
-
│ ├── backend/
|
|
277
|
-
│ │ ├── server.ts # Main server file
|
|
278
|
-
│ │ ├── routes/ # Express routes
|
|
279
|
-
│ │ └── controllers/ # Route controllers
|
|
280
|
-
│ └── frontend/
|
|
281
|
-
│ ├── views/ # EJS templates
|
|
282
|
-
│ │ └── partials/ # EJS partials
|
|
283
|
-
│ ├── static/ # Client-side JS
|
|
284
|
-
│ │ ├── gardener.js # Core framework
|
|
285
|
-
│ │ ├── gardenerDev.js # Dev tools
|
|
286
|
-
│ │ ├── components/ # Gardener components
|
|
287
|
-
│ │ └── pages/ # Page-specific JS
|
|
288
|
-
│ ├── template/ # Page templates
|
|
289
|
-
│ ├── style.css # Compiled Tailwind
|
|
290
|
-
│ └── tailwind.css # Tailwind source
|
|
291
|
-
├── build/ # Static site output
|
|
292
|
-
└── package.json
|
|
293
|
-
```
|
|
112
|
+
## Image Optimization
|
|
294
113
|
|
|
295
|
-
|
|
114
|
+
- Uses Sharp for processing
|
|
115
|
+
- Cached images served via:
|
|
296
116
|
|
|
297
|
-
|
|
298
|
-
The `parser()` function converts any DOM element into a JSON representation that can be saved as a reusable component. This allows you to:
|
|
299
|
-
- Build UI visually in the browser
|
|
300
|
-
- Extract components without manual coding
|
|
301
|
-
- Create a library of reusable elements
|
|
117
|
+
/static/[image_name]_[width]x[height].webp
|
|
302
118
|
|
|
303
|
-
|
|
304
|
-
Components are composable JSON objects. Build complex UIs by nesting components:
|
|
119
|
+
---
|
|
305
120
|
|
|
306
|
-
|
|
307
|
-
const page = {
|
|
308
|
-
t: 'div',
|
|
309
|
-
children: [
|
|
310
|
-
header,
|
|
311
|
-
mainContent,
|
|
312
|
-
footer
|
|
313
|
-
]
|
|
314
|
-
};
|
|
315
|
-
```
|
|
121
|
+
## Hot Reloading
|
|
316
122
|
|
|
317
|
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
123
|
+
- Backend watches file changes
|
|
124
|
+
- Generates hash updates
|
|
125
|
+
- Frontend polls reload endpoint
|
|
126
|
+
- Full page reload triggered on change
|
|
320
127
|
|
|
321
|
-
|
|
128
|
+
---
|
|
322
129
|
|
|
323
|
-
|
|
130
|
+
## Tech Stack
|
|
324
131
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
132
|
+
- TypeScript
|
|
133
|
+
- Express
|
|
134
|
+
- EJS
|
|
135
|
+
- esbuild
|
|
136
|
+
- Sharp
|
|
328
137
|
|
|
329
|
-
|
|
138
|
+
---
|
|
330
139
|
|
|
331
|
-
|
|
140
|
+
## Setup
|
|
332
141
|
|
|
333
|
-
|
|
142
|
+
npm create gardener <project-name>
|
|
334
143
|
|
|
335
|
-
|
|
144
|
+
---
|
|
336
145
|
|
|
337
|
-
|
|
338
|
-
// 1. Create HTML in your EJS file
|
|
339
|
-
<div class="post">
|
|
340
|
-
<h2 class="title">?title?</h2>
|
|
341
|
-
<p class="content">?content?</p>
|
|
342
|
-
</div>
|
|
146
|
+
## Positioning
|
|
343
147
|
|
|
344
|
-
|
|
345
|
-
</div>
|
|
148
|
+
Gardener is designed for:
|
|
346
149
|
|
|
347
|
-
|
|
348
|
-
|
|
150
|
+
- Developers who prefer control over abstraction
|
|
151
|
+
- Lightweight applications
|
|
152
|
+
- Learning how frameworks work internally
|
|
349
153
|
|
|
350
|
-
|
|
154
|
+
---
|
|
351
155
|
|
|
352
|
-
|
|
156
|
+
## Future Work
|
|
353
157
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
158
|
+
- Partial DOM updates (instead of full reload)
|
|
159
|
+
- Better state management primitives
|
|
160
|
+
- Devtools / debugging layer
|
|
357
161
|
|
|
162
|
+
---
|
|
358
163
|
## 🤝 Contributing
|
|
359
164
|
|
|
360
165
|
Contributions are welcome! Visit the [GitHub repository](https://github.com/ritishDas/gardener).
|
|
@@ -373,3 +178,4 @@ MIT License - See LICENSE file for details.
|
|
|
373
178
|
---
|
|
374
179
|
|
|
375
180
|
Built with ❤️ for developers who want to move fast without breaking things.
|
|
181
|
+
|
package/package.json
CHANGED
package/template/.env
CHANGED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Gardener — DOM-First Mini Framework
|
|
2
|
+
|
|
3
|
+
Gardener is a lightweight web framework built on top of Express and EJS. It enables building web applications without React or heavy frontend frameworks by using a DOM-first approach with reusable components.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Gardener lets you:
|
|
10
|
+
|
|
11
|
+
- Build UI using plain HTML, CSS, and JavaScript
|
|
12
|
+
- Convert DOM elements into reusable components
|
|
13
|
+
- Serve lightweight pages with minimal runtime overhead
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why it exists
|
|
18
|
+
|
|
19
|
+
Modern frameworks introduce significant abstraction and bundle size overhead.
|
|
20
|
+
|
|
21
|
+
Gardener focuses on:
|
|
22
|
+
|
|
23
|
+
- Minimal runtime (~300 lines core)
|
|
24
|
+
- Direct DOM control
|
|
25
|
+
- Simplicity over abstraction
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Example
|
|
30
|
+
|
|
31
|
+
Define a component using JSON:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
{
|
|
35
|
+
"t": "div",
|
|
36
|
+
"cn": ["flex", "justify-center", "items-center", "target"],
|
|
37
|
+
"children": [
|
|
38
|
+
{
|
|
39
|
+
"t": "span",
|
|
40
|
+
"cn": ["text-xl", "font-bold"],
|
|
41
|
+
"txt": "Hello World"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"t": "button",
|
|
45
|
+
"txt": "click",
|
|
46
|
+
"events": {
|
|
47
|
+
"click": "() => console.log('button clicked')"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You don’t need to write JSON manually.
|
|
55
|
+
|
|
56
|
+
Instead:
|
|
57
|
+
|
|
58
|
+
1. Write standard HTML
|
|
59
|
+
2. Select an element (id/class)
|
|
60
|
+
3. Run the parser → generates reusable component
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Key Features
|
|
65
|
+
|
|
66
|
+
- Lightweight (~300 lines core, bundled with esbuild)
|
|
67
|
+
- No frontend framework dependency
|
|
68
|
+
- Reusable components (DOM → JSON)
|
|
69
|
+
- Server-side rendering via EJS
|
|
70
|
+
- Hot reloading
|
|
71
|
+
- Image optimization (Sharp + caching)
|
|
72
|
+
- Static build support
|
|
73
|
+
- One-command page creation
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Architecture
|
|
78
|
+
|
|
79
|
+
Gardener follows a simple request → render → enhance flow:
|
|
80
|
+
|
|
81
|
+
- Express handles routing and backend logic
|
|
82
|
+
- EJS renders templates into HTML
|
|
83
|
+
- Frontend library enhances DOM with:
|
|
84
|
+
- component system
|
|
85
|
+
- state handling
|
|
86
|
+
- dev tooling
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Components
|
|
91
|
+
|
|
92
|
+
### Two types:
|
|
93
|
+
|
|
94
|
+
1. Static Components
|
|
95
|
+
|
|
96
|
+
- EJS partials
|
|
97
|
+
- Require full page reload
|
|
98
|
+
|
|
99
|
+
2. Dynamic Components
|
|
100
|
+
|
|
101
|
+
- Generated from DOM → JSON
|
|
102
|
+
- Reusable and parameterized
|
|
103
|
+
|
|
104
|
+
Example parameter:
|
|
105
|
+
|
|
106
|
+
<span>?title?</span>
|
|
107
|
+
|
|
108
|
+
This creates a dynamic variable "title".
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Image Optimization
|
|
113
|
+
|
|
114
|
+
- Uses Sharp for processing
|
|
115
|
+
- Cached images served via:
|
|
116
|
+
|
|
117
|
+
/static/[image_name]_[width]x[height].webp
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Hot Reloading
|
|
122
|
+
|
|
123
|
+
- Backend watches file changes
|
|
124
|
+
- Generates hash updates
|
|
125
|
+
- Frontend polls reload endpoint
|
|
126
|
+
- Full page reload triggered on change
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Tech Stack
|
|
131
|
+
|
|
132
|
+
- TypeScript
|
|
133
|
+
- Express
|
|
134
|
+
- EJS
|
|
135
|
+
- esbuild
|
|
136
|
+
- Sharp
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Setup
|
|
141
|
+
|
|
142
|
+
npm create gardener <project-name>
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Positioning
|
|
147
|
+
|
|
148
|
+
Gardener is designed for:
|
|
149
|
+
|
|
150
|
+
- Developers who prefer control over abstraction
|
|
151
|
+
- Lightweight applications
|
|
152
|
+
- Learning how frameworks work internally
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Future Work
|
|
157
|
+
|
|
158
|
+
- Partial DOM updates (instead of full reload)
|
|
159
|
+
- Better state management primitives
|
|
160
|
+
- Devtools / debugging layer
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
## 🤝 Contributing
|
|
164
|
+
|
|
165
|
+
Contributions are welcome! Visit the [GitHub repository](https://github.com/ritishDas/gardener).
|
|
166
|
+
|
|
167
|
+
## 📄 License
|
|
168
|
+
|
|
169
|
+
MIT License - See LICENSE file for details.
|
|
170
|
+
|
|
171
|
+
## 👤 Author
|
|
172
|
+
|
|
173
|
+
**ritishDas**
|
|
174
|
+
|
|
175
|
+
- GitHub: [@ritishDas](https://github.com/ritishDas)
|
|
176
|
+
- Website: [gardener.ritish.site](https://gardener.ritish.site)
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
Built with ❤️ for developers who want to move fast without breaking things.
|
|
181
|
+
|
package/template/buildHelper.js
CHANGED
|
@@ -6,6 +6,11 @@ export default async function buildHelper() {
|
|
|
6
6
|
const src = path.resolve('src', 'frontend');
|
|
7
7
|
const dest = path.resolve('build', 'frontend');
|
|
8
8
|
|
|
9
|
+
try {
|
|
10
|
+
await fs.rm(dest, { recursive: true, force: true });
|
|
11
|
+
} catch (err) {
|
|
12
|
+
console.log(err);
|
|
13
|
+
}
|
|
9
14
|
await fs.cp(src, dest, { recursive: true });
|
|
10
15
|
|
|
11
16
|
await fs.writeFile(
|