create-elit 3.0.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 +115 -0
- package/dist/index.js +664 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# create-elit
|
|
2
|
+
|
|
3
|
+
Scaffolding tool for creating new Elit projects.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
With npm:
|
|
8
|
+
```bash
|
|
9
|
+
npm create elit@latest my-app
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
With yarn:
|
|
13
|
+
```bash
|
|
14
|
+
yarn create elit my-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
With pnpm:
|
|
18
|
+
```bash
|
|
19
|
+
pnpm create elit my-app
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
With bun:
|
|
23
|
+
```bash
|
|
24
|
+
bun create elit my-app
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
With deno:
|
|
28
|
+
```bash
|
|
29
|
+
deno run -A npm:create-elit my-app
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Templates
|
|
33
|
+
|
|
34
|
+
Choose a template with the `--template` flag:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm create elit@latest my-app --template=basic
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Available templates:
|
|
41
|
+
|
|
42
|
+
- **basic** (default) - Full-featured app with styled counter using CSS-in-JS
|
|
43
|
+
- **full** - Full-stack app with dev server, API routes, and CSS-in-JS
|
|
44
|
+
- **minimal** - Minimal setup with just DOM rendering
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
✨ **Zero Configuration** - Works out of the box
|
|
49
|
+
🎨 **CSS-in-JS** - Uses Elit's `CreateStyle` for type-safe styling
|
|
50
|
+
📦 **TypeScript Ready** - Full TypeScript support
|
|
51
|
+
🚀 **Fast Setup** - Creates project in seconds
|
|
52
|
+
🎯 **Multiple Templates** - Choose the right starting point
|
|
53
|
+
|
|
54
|
+
## What's Included
|
|
55
|
+
|
|
56
|
+
Each template includes:
|
|
57
|
+
- TypeScript configuration
|
|
58
|
+
- Package.json with Elit scripts (`dev`, `build`, `preview`)
|
|
59
|
+
- Elit config file (`elit.config.mjs`)
|
|
60
|
+
- 100% TypeScript - no HTML files needed
|
|
61
|
+
- Type-safe CSS-in-JS with `CreateStyle`
|
|
62
|
+
- Server-side rendering with `dom.renderServer`
|
|
63
|
+
- Client-side hydration with `client.ts`
|
|
64
|
+
- Example code showing best practices
|
|
65
|
+
- Auto-generated README and .gitignore
|
|
66
|
+
|
|
67
|
+
## Example
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Create a new project
|
|
71
|
+
npm create elit@latest my-elit-app
|
|
72
|
+
|
|
73
|
+
# Navigate to project
|
|
74
|
+
cd my-elit-app
|
|
75
|
+
|
|
76
|
+
# Install dependencies
|
|
77
|
+
npm install
|
|
78
|
+
|
|
79
|
+
# Start dev server
|
|
80
|
+
npm run dev
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Visit http://localhost:3003 to see your app!
|
|
84
|
+
|
|
85
|
+
## Template Details
|
|
86
|
+
|
|
87
|
+
### Basic Template
|
|
88
|
+
- Counter example with increment/decrement
|
|
89
|
+
- Beautiful gradient UI with CSS-in-JS
|
|
90
|
+
- Reactive state management demo
|
|
91
|
+
- Type-safe styling with `CreateStyle`
|
|
92
|
+
- Server-side rendering with `dom.renderServer`
|
|
93
|
+
|
|
94
|
+
### Full Template
|
|
95
|
+
- Counter and API call examples
|
|
96
|
+
- Server-side routing with middleware
|
|
97
|
+
- CORS and logging setup
|
|
98
|
+
- Client-server communication
|
|
99
|
+
- Full-stack TypeScript setup
|
|
100
|
+
|
|
101
|
+
### Minimal Template
|
|
102
|
+
- Just the essentials
|
|
103
|
+
- Simple "Hello Elit!" example
|
|
104
|
+
- Perfect for learning or prototyping
|
|
105
|
+
- Pure TypeScript - zero HTML
|
|
106
|
+
|
|
107
|
+
## Learn More
|
|
108
|
+
|
|
109
|
+
- [Elit Documentation](https://d-osc.github.io/elit)
|
|
110
|
+
- [GitHub Repository](https://github.com/d-osc/elit)
|
|
111
|
+
- [npm Package](https://www.npmjs.com/package/elit)
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
5
|
+
import { join, resolve } from "path";
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
var templates = {
|
|
8
|
+
basic: "Basic Elit app with counter example",
|
|
9
|
+
full: "Full-stack app with dev server and API routes",
|
|
10
|
+
minimal: "Minimal setup with just DOM rendering"
|
|
11
|
+
};
|
|
12
|
+
var colors = {
|
|
13
|
+
reset: "\x1B[0m",
|
|
14
|
+
cyan: "\x1B[36m",
|
|
15
|
+
green: "\x1B[32m",
|
|
16
|
+
yellow: "\x1B[33m",
|
|
17
|
+
red: "\x1B[31m",
|
|
18
|
+
dim: "\x1B[2m"
|
|
19
|
+
};
|
|
20
|
+
function log(message, color = "reset") {
|
|
21
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
22
|
+
}
|
|
23
|
+
function getProjectName() {
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
return args[0] || "my-elit-app";
|
|
26
|
+
}
|
|
27
|
+
function getTemplate() {
|
|
28
|
+
const args = process.argv.slice(2);
|
|
29
|
+
const templateArg = args.find((arg) => arg.startsWith("--template="));
|
|
30
|
+
if (templateArg) {
|
|
31
|
+
const template2 = templateArg.split("=")[1];
|
|
32
|
+
if (template2 in templates) return template2;
|
|
33
|
+
}
|
|
34
|
+
return "basic";
|
|
35
|
+
}
|
|
36
|
+
async function createProject(projectName2, template2) {
|
|
37
|
+
const projectPath = resolve(process.cwd(), projectName2);
|
|
38
|
+
if (existsSync(projectPath)) {
|
|
39
|
+
log(`Error: Directory "${projectName2}" already exists!`, "red");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
log(`Creating a new Elit app in ${projectPath}...`, "cyan");
|
|
43
|
+
await mkdir(projectPath, { recursive: true });
|
|
44
|
+
await generateTemplate(projectPath, projectName2, template2);
|
|
45
|
+
log("\nSuccess! Created " + projectName2, "green");
|
|
46
|
+
log("\nInside that directory, you can run several commands:", "dim");
|
|
47
|
+
log("\n npm run dev", "cyan");
|
|
48
|
+
log(" Starts the development server with HMR\n", "dim");
|
|
49
|
+
log(" npm run build", "cyan");
|
|
50
|
+
log(" Builds the app for production\n", "dim");
|
|
51
|
+
log(" npm run preview", "cyan");
|
|
52
|
+
log(" Preview the production build\n", "dim");
|
|
53
|
+
log("\nWe suggest that you begin by typing:\n", "dim");
|
|
54
|
+
log(` cd ${projectName2}`, "cyan");
|
|
55
|
+
log(" npm install", "cyan");
|
|
56
|
+
log(" npm run dev\n", "cyan");
|
|
57
|
+
log("Happy coding! \u{1F680}", "green");
|
|
58
|
+
}
|
|
59
|
+
async function generateTemplate(projectPath, projectName2, template2) {
|
|
60
|
+
const packageJson = {
|
|
61
|
+
name: projectName2,
|
|
62
|
+
version: "0.0.0",
|
|
63
|
+
type: "module",
|
|
64
|
+
scripts: {
|
|
65
|
+
dev: "elit dev",
|
|
66
|
+
build: "elit build",
|
|
67
|
+
preview: "elit preview"
|
|
68
|
+
},
|
|
69
|
+
dependencies: {
|
|
70
|
+
elit: "^2.0.0"
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
await writeFile(
|
|
74
|
+
join(projectPath, "package.json"),
|
|
75
|
+
JSON.stringify(packageJson, null, 2)
|
|
76
|
+
);
|
|
77
|
+
const tsConfig = {
|
|
78
|
+
compilerOptions: {
|
|
79
|
+
target: "ES2020",
|
|
80
|
+
module: "ESNext",
|
|
81
|
+
moduleResolution: "bundler",
|
|
82
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
83
|
+
strict: true,
|
|
84
|
+
esModuleInterop: true,
|
|
85
|
+
skipLibCheck: true,
|
|
86
|
+
resolveJsonModule: true,
|
|
87
|
+
isolatedModules: true,
|
|
88
|
+
types: ["node"]
|
|
89
|
+
},
|
|
90
|
+
include: ["src"]
|
|
91
|
+
};
|
|
92
|
+
await writeFile(
|
|
93
|
+
join(projectPath, "tsconfig.json"),
|
|
94
|
+
JSON.stringify(tsConfig, null, 2)
|
|
95
|
+
);
|
|
96
|
+
const gitignore = `node_modules
|
|
97
|
+
dist
|
|
98
|
+
.env
|
|
99
|
+
.env.local
|
|
100
|
+
*.log
|
|
101
|
+
.DS_Store
|
|
102
|
+
`;
|
|
103
|
+
await writeFile(join(projectPath, ".gitignore"), gitignore);
|
|
104
|
+
const readme = `# ${projectName2}
|
|
105
|
+
|
|
106
|
+
A new Elit project created with create-elit.
|
|
107
|
+
|
|
108
|
+
## Getting Started
|
|
109
|
+
|
|
110
|
+
\`\`\`bash
|
|
111
|
+
npm install
|
|
112
|
+
npm run dev
|
|
113
|
+
\`\`\`
|
|
114
|
+
|
|
115
|
+
Visit http://localhost:3003 to view your app.
|
|
116
|
+
|
|
117
|
+
## Available Scripts
|
|
118
|
+
|
|
119
|
+
- \`npm run dev\` - Start development server with HMR
|
|
120
|
+
- \`npm run build\` - Build for production
|
|
121
|
+
- \`npm run preview\` - Preview production build
|
|
122
|
+
|
|
123
|
+
## Learn More
|
|
124
|
+
|
|
125
|
+
- [Elit Documentation](https://d-osc.github.io/elit)
|
|
126
|
+
- [GitHub Repository](https://github.com/d-osc/elit)
|
|
127
|
+
`;
|
|
128
|
+
await writeFile(join(projectPath, "README.md"), readme);
|
|
129
|
+
const elitConfig = `import { server } from './src/server';
|
|
130
|
+
import { client } from './src/client';
|
|
131
|
+
|
|
132
|
+
export default {
|
|
133
|
+
dev: {
|
|
134
|
+
port: 3003,
|
|
135
|
+
host: '0.0.0.0',
|
|
136
|
+
open: ${template2 === "basic" ? "true" : "false"},
|
|
137
|
+
logging: true,
|
|
138
|
+
clients: [{
|
|
139
|
+
root: '.',
|
|
140
|
+
basePath: '',
|
|
141
|
+
ssr: () => client,
|
|
142
|
+
api: server
|
|
143
|
+
}]
|
|
144
|
+
},
|
|
145
|
+
build: [{
|
|
146
|
+
entry: './src/main.ts',
|
|
147
|
+
outDir: './dist',
|
|
148
|
+
outFile: 'main.js',
|
|
149
|
+
format: 'esm',
|
|
150
|
+
minify: true,
|
|
151
|
+
sourcemap: true,
|
|
152
|
+
target: 'es2020',
|
|
153
|
+
copy: [
|
|
154
|
+
{ from: './public/index.html', to: './index.html' }
|
|
155
|
+
]
|
|
156
|
+
}],
|
|
157
|
+
preview: {
|
|
158
|
+
port: 3000,
|
|
159
|
+
host: '0.0.0.0',
|
|
160
|
+
open: false,
|
|
161
|
+
logging: true,
|
|
162
|
+
root: './dist',
|
|
163
|
+
basePath: '',
|
|
164
|
+
index: './index.html'
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
`;
|
|
168
|
+
await writeFile(join(projectPath, "elit.config.ts"), elitConfig);
|
|
169
|
+
await mkdir(join(projectPath, "public"), { recursive: true });
|
|
170
|
+
const indexHtml = `<!DOCTYPE html>
|
|
171
|
+
<html lang="en">
|
|
172
|
+
<head>
|
|
173
|
+
<meta charset="UTF-8">
|
|
174
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
175
|
+
<title>${projectName2}</title>
|
|
176
|
+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
177
|
+
<meta name="description" content="Built with Elit - Full-stack TypeScript framework">
|
|
178
|
+
</head>
|
|
179
|
+
<body>
|
|
180
|
+
<div id="root"></div>
|
|
181
|
+
<script type="module" src="/main.js"></script>
|
|
182
|
+
</body>
|
|
183
|
+
</html>
|
|
184
|
+
`;
|
|
185
|
+
await writeFile(join(projectPath, "public", "index.html"), indexHtml);
|
|
186
|
+
await mkdir(join(projectPath, "src"), { recursive: true });
|
|
187
|
+
if (template2 === "basic") {
|
|
188
|
+
await generateBasicTemplate(projectPath, projectName2);
|
|
189
|
+
} else if (template2 === "full") {
|
|
190
|
+
await generateFullTemplate(projectPath, projectName2);
|
|
191
|
+
} else {
|
|
192
|
+
await generateMinimalTemplate(projectPath, projectName2);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function generateBasicTemplate(projectPath, projectName2) {
|
|
196
|
+
const mainTs = `import { div, h1, h2, button, p } from 'elit/el';
|
|
197
|
+
import { createState, reactive } from 'elit/state';
|
|
198
|
+
import { render } from 'elit/dom';
|
|
199
|
+
import './styles.ts';
|
|
200
|
+
|
|
201
|
+
// Create reactive state (shared between SSR and client)
|
|
202
|
+
export const count = createState(0);
|
|
203
|
+
|
|
204
|
+
// Create app (shared between SSR and client)
|
|
205
|
+
export const app = div({ className: 'container' },
|
|
206
|
+
div({ className: 'card' },
|
|
207
|
+
h1('Welcome to Elit! \u{1F680}'),
|
|
208
|
+
p('A lightweight TypeScript framework with reactive state management'),
|
|
209
|
+
|
|
210
|
+
div({ className: 'counter' },
|
|
211
|
+
h2('Counter Example'),
|
|
212
|
+
reactive(count, (value) =>
|
|
213
|
+
div({ className: 'count-display' }, \`Count: \${value}\`)
|
|
214
|
+
),
|
|
215
|
+
div({ className: 'button-group' },
|
|
216
|
+
button({
|
|
217
|
+
onclick: () => count.value--,
|
|
218
|
+
className: 'btn btn-secondary'
|
|
219
|
+
}, '- Decrement'),
|
|
220
|
+
button({
|
|
221
|
+
onclick: () => count.value = 0,
|
|
222
|
+
className: 'btn btn-secondary'
|
|
223
|
+
}, 'Reset'),
|
|
224
|
+
button({
|
|
225
|
+
onclick: () => count.value++,
|
|
226
|
+
className: 'btn btn-primary'
|
|
227
|
+
}, '+ Increment')
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
render('root', app);
|
|
234
|
+
console.log('[Main] App rendered');
|
|
235
|
+
`;
|
|
236
|
+
await writeFile(join(projectPath, "src", "main.ts"), mainTs);
|
|
237
|
+
const stylesTs = `import styles from 'elit/style';
|
|
238
|
+
|
|
239
|
+
// Global styles
|
|
240
|
+
styles.addTag('*', {
|
|
241
|
+
margin: 0,
|
|
242
|
+
padding: 0,
|
|
243
|
+
boxSizing: 'border-box'
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
styles.addTag('body', {
|
|
247
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
248
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
249
|
+
minHeight: '100vh',
|
|
250
|
+
display: 'flex',
|
|
251
|
+
alignItems: 'center',
|
|
252
|
+
justifyContent: 'center',
|
|
253
|
+
padding: '2rem'
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Container
|
|
257
|
+
styles.addClass('container', {
|
|
258
|
+
width: '100%',
|
|
259
|
+
maxWidth: '600px'
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Card
|
|
263
|
+
styles.addClass('card', {
|
|
264
|
+
background: 'white',
|
|
265
|
+
borderRadius: '16px',
|
|
266
|
+
padding: '3rem',
|
|
267
|
+
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)'
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Typography
|
|
271
|
+
styles.addTag('h1', {
|
|
272
|
+
fontSize: '2.5rem',
|
|
273
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
274
|
+
WebkitBackgroundClip: 'text',
|
|
275
|
+
WebkitTextFillColor: 'transparent',
|
|
276
|
+
backgroundClip: 'text',
|
|
277
|
+
marginBottom: '1rem'
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
styles.addTag('h2', {
|
|
281
|
+
fontSize: '1.5rem',
|
|
282
|
+
color: '#333',
|
|
283
|
+
marginBottom: '1rem'
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
styles.addTag('p', {
|
|
287
|
+
color: '#666',
|
|
288
|
+
marginBottom: '2rem',
|
|
289
|
+
lineHeight: 1.6
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Counter section
|
|
293
|
+
styles.addClass('counter', {
|
|
294
|
+
marginTop: '2rem',
|
|
295
|
+
paddingTop: '2rem',
|
|
296
|
+
borderTop: '2px solid #f0f0f0'
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
styles.addClass('count-display', {
|
|
300
|
+
fontSize: '3rem',
|
|
301
|
+
fontWeight: 'bold',
|
|
302
|
+
color: '#667eea',
|
|
303
|
+
textAlign: 'center',
|
|
304
|
+
margin: '2rem 0'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Button group
|
|
308
|
+
styles.addClass('button-group', {
|
|
309
|
+
display: 'flex',
|
|
310
|
+
gap: '1rem',
|
|
311
|
+
justifyContent: 'center'
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Buttons
|
|
315
|
+
styles.addClass('btn', {
|
|
316
|
+
padding: '0.75rem 1.5rem',
|
|
317
|
+
border: 'none',
|
|
318
|
+
borderRadius: '8px',
|
|
319
|
+
fontSize: '1rem',
|
|
320
|
+
fontWeight: 600,
|
|
321
|
+
cursor: 'pointer',
|
|
322
|
+
transition: 'all 0.2s'
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
styles.addClass('btn-primary', {
|
|
326
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
327
|
+
color: 'white'
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
styles.addPseudoClass('hover', {
|
|
331
|
+
transform: 'translateY(-2px)',
|
|
332
|
+
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.4)'
|
|
333
|
+
}, '.btn-primary');
|
|
334
|
+
|
|
335
|
+
styles.addClass('btn-secondary', {
|
|
336
|
+
background: '#f0f0f0',
|
|
337
|
+
color: '#333'
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
styles.addPseudoClass('hover', {
|
|
341
|
+
background: '#e0e0e0',
|
|
342
|
+
transform: 'translateY(-2px)'
|
|
343
|
+
}, '.btn-secondary');
|
|
344
|
+
|
|
345
|
+
styles.addPseudoClass('active', {
|
|
346
|
+
transform: 'translateY(0)'
|
|
347
|
+
}, '.btn');
|
|
348
|
+
|
|
349
|
+
styles.inject('global-styles');
|
|
350
|
+
export default styles;
|
|
351
|
+
`;
|
|
352
|
+
await writeFile(join(projectPath, "src", "styles.ts"), stylesTs);
|
|
353
|
+
const clientTs = `import { div, html, head, body, title, link, script, meta } from 'elit/el';
|
|
354
|
+
|
|
355
|
+
export const client = html(
|
|
356
|
+
head(
|
|
357
|
+
title('${projectName2} - Elit App'),
|
|
358
|
+
link({ rel: 'icon', type: 'image/svg+xml', href: 'favicon.svg' }),
|
|
359
|
+
meta({ charset: 'UTF-8' }),
|
|
360
|
+
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
|
|
361
|
+
meta({ name: 'description', content: 'Elit - Full-stack TypeScript framework with dev server, HMR, routing, SSR, and REST API.' })
|
|
362
|
+
),
|
|
363
|
+
body(
|
|
364
|
+
div({ id: 'root' }),
|
|
365
|
+
script({ type: 'module', src: '/src/main.js' })
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
`;
|
|
369
|
+
await writeFile(join(projectPath, "src", "client.ts"), clientTs);
|
|
370
|
+
const serverTs = `import { ServerRouter } from 'elit/server';
|
|
371
|
+
|
|
372
|
+
export const router = new ServerRouter();
|
|
373
|
+
|
|
374
|
+
router.get('/api/hello', async (ctx) => {
|
|
375
|
+
ctx.res.setHeader('Content-Type', 'application/json');
|
|
376
|
+
ctx.res.end(JSON.stringify({ message: 'Hello from Elit ServerRouter!' }));
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
export const server = router;
|
|
380
|
+
`;
|
|
381
|
+
await writeFile(join(projectPath, "src", "server.ts"), serverTs);
|
|
382
|
+
}
|
|
383
|
+
async function generateFullTemplate(projectPath, projectName2) {
|
|
384
|
+
const mainTs = `import { div, h1, h2, button, p } from 'elit/el';
|
|
385
|
+
import { createState, reactive } from 'elit/state';
|
|
386
|
+
import { render } from 'elit/dom';
|
|
387
|
+
import './styles.ts';
|
|
388
|
+
|
|
389
|
+
// Create reactive state
|
|
390
|
+
export const count = createState(0);
|
|
391
|
+
export const message = createState<string>('');
|
|
392
|
+
|
|
393
|
+
// Fetch from API
|
|
394
|
+
async function fetchMessage() {
|
|
395
|
+
try {
|
|
396
|
+
const res = await fetch('/api/hello');
|
|
397
|
+
const data = await res.json();
|
|
398
|
+
message.value = data.message;
|
|
399
|
+
} catch (err) {
|
|
400
|
+
message.value = 'Error loading message';
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Create app
|
|
405
|
+
export const app = div({ className: 'container' },
|
|
406
|
+
div({ className: 'card' },
|
|
407
|
+
h1('Elit Full-Stack App \u{1F680}'),
|
|
408
|
+
p('Counter and API integration example'),
|
|
409
|
+
|
|
410
|
+
div({ className: 'counter' },
|
|
411
|
+
h2('Counter Example'),
|
|
412
|
+
reactive(count, (value) =>
|
|
413
|
+
div({ className: 'count-display' }, \`Count: \${value}\`)
|
|
414
|
+
),
|
|
415
|
+
div({ className: 'button-group' },
|
|
416
|
+
button({
|
|
417
|
+
onclick: () => count.value--,
|
|
418
|
+
className: 'btn btn-secondary'
|
|
419
|
+
}, '- Decrement'),
|
|
420
|
+
button({
|
|
421
|
+
onclick: () => count.value = 0,
|
|
422
|
+
className: 'btn btn-secondary'
|
|
423
|
+
}, 'Reset'),
|
|
424
|
+
button({
|
|
425
|
+
onclick: () => count.value++,
|
|
426
|
+
className: 'btn btn-primary'
|
|
427
|
+
}, '+ Increment')
|
|
428
|
+
)
|
|
429
|
+
),
|
|
430
|
+
|
|
431
|
+
div({ className: 'api-section' },
|
|
432
|
+
h2('API Example'),
|
|
433
|
+
button({
|
|
434
|
+
onclick: () => fetchMessage(),
|
|
435
|
+
className: 'btn btn-primary'
|
|
436
|
+
}, 'Fetch from API'),
|
|
437
|
+
reactive(message, (msg) =>
|
|
438
|
+
msg ? p({ className: 'api-message' }, \`API says: \${msg}\`) : p('')
|
|
439
|
+
)
|
|
440
|
+
)
|
|
441
|
+
)
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
render('root', app);
|
|
445
|
+
console.log('[Main] App rendered');
|
|
446
|
+
`;
|
|
447
|
+
await writeFile(join(projectPath, "src", "main.ts"), mainTs);
|
|
448
|
+
const serverTs = `import { ServerRouter } from 'elit/server';
|
|
449
|
+
|
|
450
|
+
export const router = new ServerRouter();
|
|
451
|
+
|
|
452
|
+
router.get('/api/hello', async (ctx) => {
|
|
453
|
+
ctx.res.setHeader('Content-Type', 'application/json');
|
|
454
|
+
ctx.res.end(JSON.stringify({ message: 'Hello from Elit ServerRouter!' }));
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
router.get('/api/count', async (ctx) => {
|
|
458
|
+
ctx.res.setHeader('Content-Type', 'application/json');
|
|
459
|
+
ctx.res.end(JSON.stringify({ count: Math.floor(Math.random() * 100) }));
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
export const server = router;
|
|
463
|
+
`;
|
|
464
|
+
await writeFile(join(projectPath, "src", "server.ts"), serverTs);
|
|
465
|
+
const stylesTs = `import styles from 'elit/style';
|
|
466
|
+
|
|
467
|
+
// Global styles
|
|
468
|
+
styles.addTag('*', {
|
|
469
|
+
margin: 0,
|
|
470
|
+
padding: 0,
|
|
471
|
+
boxSizing: 'border-box'
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
styles.addTag('body', {
|
|
475
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
476
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
477
|
+
minHeight: '100vh',
|
|
478
|
+
display: 'flex',
|
|
479
|
+
alignItems: 'center',
|
|
480
|
+
justifyContent: 'center',
|
|
481
|
+
padding: '2rem'
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Container
|
|
485
|
+
styles.addClass('container', {
|
|
486
|
+
width: '100%',
|
|
487
|
+
maxWidth: '600px'
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Card
|
|
491
|
+
styles.addClass('card', {
|
|
492
|
+
background: 'white',
|
|
493
|
+
borderRadius: '16px',
|
|
494
|
+
padding: '3rem',
|
|
495
|
+
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)'
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// Typography
|
|
499
|
+
styles.addTag('h1', {
|
|
500
|
+
fontSize: '2.5rem',
|
|
501
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
502
|
+
WebkitBackgroundClip: 'text',
|
|
503
|
+
WebkitTextFillColor: 'transparent',
|
|
504
|
+
backgroundClip: 'text',
|
|
505
|
+
marginBottom: '1rem'
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
styles.addTag('h2', {
|
|
509
|
+
fontSize: '1.5rem',
|
|
510
|
+
color: '#333',
|
|
511
|
+
marginBottom: '1rem'
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
styles.addTag('p', {
|
|
515
|
+
color: '#666',
|
|
516
|
+
marginBottom: '2rem',
|
|
517
|
+
lineHeight: 1.6
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// Counter section
|
|
521
|
+
styles.addClass('counter', {
|
|
522
|
+
marginTop: '2rem',
|
|
523
|
+
paddingTop: '2rem',
|
|
524
|
+
borderTop: '2px solid #f0f0f0'
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
styles.addClass('count-display', {
|
|
528
|
+
fontSize: '3rem',
|
|
529
|
+
fontWeight: 'bold',
|
|
530
|
+
color: '#667eea',
|
|
531
|
+
textAlign: 'center',
|
|
532
|
+
margin: '2rem 0'
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// API section
|
|
536
|
+
styles.addClass('api-section', {
|
|
537
|
+
marginTop: '2rem',
|
|
538
|
+
paddingTop: '2rem',
|
|
539
|
+
borderTop: '2px solid #f0f0f0'
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
styles.addClass('api-message', {
|
|
543
|
+
marginTop: '1rem',
|
|
544
|
+
padding: '1rem',
|
|
545
|
+
background: '#f0f0f0',
|
|
546
|
+
borderRadius: '8px',
|
|
547
|
+
color: '#333',
|
|
548
|
+
textAlign: 'center'
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Button group
|
|
552
|
+
styles.addClass('button-group', {
|
|
553
|
+
display: 'flex',
|
|
554
|
+
gap: '1rem',
|
|
555
|
+
justifyContent: 'center'
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Buttons
|
|
559
|
+
styles.addClass('btn', {
|
|
560
|
+
padding: '0.75rem 1.5rem',
|
|
561
|
+
border: 'none',
|
|
562
|
+
borderRadius: '8px',
|
|
563
|
+
fontSize: '1rem',
|
|
564
|
+
fontWeight: 600,
|
|
565
|
+
cursor: 'pointer',
|
|
566
|
+
transition: 'all 0.2s'
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
styles.addClass('btn-primary', {
|
|
570
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
571
|
+
color: 'white'
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
styles.addPseudoClass('hover', {
|
|
575
|
+
transform: 'translateY(-2px)',
|
|
576
|
+
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.4)'
|
|
577
|
+
}, '.btn-primary');
|
|
578
|
+
|
|
579
|
+
styles.addClass('btn-secondary', {
|
|
580
|
+
background: '#f0f0f0',
|
|
581
|
+
color: '#333'
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
styles.addPseudoClass('hover', {
|
|
585
|
+
background: '#e0e0e0',
|
|
586
|
+
transform: 'translateY(-2px)'
|
|
587
|
+
}, '.btn-secondary');
|
|
588
|
+
|
|
589
|
+
styles.addPseudoClass('active', {
|
|
590
|
+
transform: 'translateY(0)'
|
|
591
|
+
}, '.btn');
|
|
592
|
+
|
|
593
|
+
styles.inject('global-styles');
|
|
594
|
+
export default styles;
|
|
595
|
+
`;
|
|
596
|
+
await writeFile(join(projectPath, "src", "styles.ts"), stylesTs);
|
|
597
|
+
const clientTs = `import { div, html, head, body, title, link, script, meta } from 'elit/el';
|
|
598
|
+
|
|
599
|
+
export const client = html(
|
|
600
|
+
head(
|
|
601
|
+
title('${projectName2} - Elit Full-Stack App'),
|
|
602
|
+
link({ rel: 'icon', type: 'image/svg+xml', href: 'favicon.svg' }),
|
|
603
|
+
meta({ charset: 'UTF-8' }),
|
|
604
|
+
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
|
|
605
|
+
meta({ name: 'description', content: 'Full-stack TypeScript framework with dev server, HMR, routing, SSR, and REST API.' })
|
|
606
|
+
),
|
|
607
|
+
body(
|
|
608
|
+
div({ id: 'root' }),
|
|
609
|
+
script({ type: 'module', src: '/src/main.js' })
|
|
610
|
+
)
|
|
611
|
+
);
|
|
612
|
+
`;
|
|
613
|
+
await writeFile(join(projectPath, "src", "client.ts"), clientTs);
|
|
614
|
+
}
|
|
615
|
+
async function generateMinimalTemplate(projectPath, projectName2) {
|
|
616
|
+
const mainTs = `import { div, h1 } from 'elit/el';
|
|
617
|
+
import { render } from 'elit/dom';
|
|
618
|
+
|
|
619
|
+
// Create app
|
|
620
|
+
export const app = div(
|
|
621
|
+
h1('Hello Elit! \u{1F44B}')
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
render('root', app);
|
|
625
|
+
console.log('[Main] App rendered');
|
|
626
|
+
`;
|
|
627
|
+
await writeFile(join(projectPath, "src", "main.ts"), mainTs);
|
|
628
|
+
const clientTs = `import { div, html, head, body, title, meta, script } from 'elit/el';
|
|
629
|
+
|
|
630
|
+
export const client = html(
|
|
631
|
+
head(
|
|
632
|
+
title('${projectName2}'),
|
|
633
|
+
meta({ charset: 'UTF-8' }),
|
|
634
|
+
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' })
|
|
635
|
+
),
|
|
636
|
+
body(
|
|
637
|
+
div({ id: 'root' }),
|
|
638
|
+
script({ type: 'module', src: '/src/main.js' })
|
|
639
|
+
)
|
|
640
|
+
);
|
|
641
|
+
`;
|
|
642
|
+
await writeFile(join(projectPath, "src", "client.ts"), clientTs);
|
|
643
|
+
const serverTs = `import { ServerRouter } from 'elit/server';
|
|
644
|
+
|
|
645
|
+
export const router = new ServerRouter();
|
|
646
|
+
|
|
647
|
+
// Add your API routes here
|
|
648
|
+
// Example:
|
|
649
|
+
// router.get('/api/hello', async (ctx) => {
|
|
650
|
+
// ctx.res.setHeader('Content-Type', 'application/json');
|
|
651
|
+
// ctx.res.end(JSON.stringify({ message: 'Hello!' }));
|
|
652
|
+
// });
|
|
653
|
+
|
|
654
|
+
export const server = router;
|
|
655
|
+
`;
|
|
656
|
+
await writeFile(join(projectPath, "src", "server.ts"), serverTs);
|
|
657
|
+
}
|
|
658
|
+
var projectName = getProjectName();
|
|
659
|
+
var template = getTemplate();
|
|
660
|
+
log("\n\u{1F680} Create Elit App\n", "cyan");
|
|
661
|
+
createProject(projectName, template).catch((err) => {
|
|
662
|
+
log(`Error: ${err.message}`, "red");
|
|
663
|
+
process.exit(1);
|
|
664
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-elit",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Scaffolding tool for creating Elit projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-elit": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"create-elit",
|
|
19
|
+
"elit",
|
|
20
|
+
"scaffolding",
|
|
21
|
+
"cli",
|
|
22
|
+
"template",
|
|
23
|
+
"boilerplate"
|
|
24
|
+
],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/d-osc/elit.git",
|
|
30
|
+
"directory": "packages/create-elit"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/d-osc/elit/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://d-osc.github.io/elit/",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tsup": "^8.0.0",
|
|
38
|
+
"typescript": "^5.3.0"
|
|
39
|
+
}
|
|
40
|
+
}
|