create-laju-app 1.0.10 → 1.0.11
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 +309 -322
- package/bin/cli.js +90 -90
- package/package.json +28 -28
package/README.md
CHANGED
|
@@ -1,322 +1,309 @@
|
|
|
1
|
-
# Laju
|
|
2
|
-
|
|
3
|
-
A high-performance TypeScript web framework combining HyperExpress, Svelte 5, and Inertia.js for building modern full-stack applications. Features server-side rendering, real-time capabilities, and seamless client-server state management.
|
|
4
|
-
|
|
5
|
-
Visit [laju.dev](https://laju.dev)
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- Fast server-side rendering with HyperExpress
|
|
10
|
-
- Modern frontend with Svelte 5
|
|
11
|
-
- TypeScript support for better type safety
|
|
12
|
-
- Inertia.js integration for seamless client-server communication
|
|
13
|
-
- Built-in authentication system
|
|
14
|
-
- SQLite database with Knex query builder
|
|
15
|
-
- Email support with Nodemailer
|
|
16
|
-
- Google APIs integration
|
|
17
|
-
- Redis caching support
|
|
18
|
-
- Asset bundling with Vite
|
|
19
|
-
- TailwindCSS for styling
|
|
20
|
-
|
|
21
|
-
## Prerequisites
|
|
22
|
-
|
|
23
|
-
- Node.js (Latest LTS version recommended)
|
|
24
|
-
- npm or yarn
|
|
25
|
-
- Redis server (optional, for caching)
|
|
26
|
-
|
|
27
|
-
## Installation
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npx create-laju-app project-name
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return response.
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
<div class="
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
</
|
|
251
|
-
|
|
252
|
-
<div
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
2. **Code Structure**
|
|
312
|
-
- Use TypeScript types for better type safety
|
|
313
|
-
- Keep controllers focused on single responsibilities
|
|
314
|
-
- Use Inertia.js for state management between server and client
|
|
315
|
-
|
|
316
|
-
3. **Database**
|
|
317
|
-
- Always use migrations for database changes
|
|
318
|
-
- Use the Query Builder for complex queries
|
|
319
|
-
- Include timestamps for tracking record changes
|
|
320
|
-
|
|
321
|
-
Need help with anything specific? Feel free to ask!
|
|
322
|
-
|
|
1
|
+
# Laju
|
|
2
|
+
|
|
3
|
+
A high-performance TypeScript web framework combining HyperExpress, Svelte 5, and Inertia.js for building modern full-stack applications. Features server-side rendering, real-time capabilities, and seamless client-server state management.
|
|
4
|
+
|
|
5
|
+
Visit [laju.dev](https://laju.dev)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Fast server-side rendering with HyperExpress
|
|
10
|
+
- Modern frontend with Svelte 5
|
|
11
|
+
- TypeScript support for better type safety
|
|
12
|
+
- Inertia.js integration for seamless client-server communication
|
|
13
|
+
- Built-in authentication system
|
|
14
|
+
- SQLite database with Knex query builder
|
|
15
|
+
- Email support with Nodemailer
|
|
16
|
+
- Google APIs integration
|
|
17
|
+
- Redis caching support
|
|
18
|
+
- Asset bundling with Vite
|
|
19
|
+
- TailwindCSS for styling
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
|
|
23
|
+
- Node.js (Latest LTS version recommended)
|
|
24
|
+
- npm or yarn
|
|
25
|
+
- Redis server (optional, for caching)
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Run the following command
|
|
30
|
+
```bash
|
|
31
|
+
npx create-laju-app project-name
|
|
32
|
+
```
|
|
33
|
+
## Development
|
|
34
|
+
|
|
35
|
+
To start the development server:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This will:
|
|
42
|
+
- Start the Vite development server for frontend assets
|
|
43
|
+
- Run the backend server with nodemon for auto-reloading
|
|
44
|
+
|
|
45
|
+
## Building for Production
|
|
46
|
+
|
|
47
|
+
To build the application for production:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm run build
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This command will:
|
|
54
|
+
- Clean the build directory
|
|
55
|
+
- Build frontend assets with Vite
|
|
56
|
+
- Compile TypeScript files
|
|
57
|
+
- Copy necessary files to the build directory
|
|
58
|
+
|
|
59
|
+
## Project Structure
|
|
60
|
+
|
|
61
|
+
- `/app` - Core application files
|
|
62
|
+
- `/middlewares` - Custom middleware functions
|
|
63
|
+
- `/services` - Service layer implementations
|
|
64
|
+
- `/controllers` - Application controllers
|
|
65
|
+
- `/resources` - Frontend resources
|
|
66
|
+
- `/views` - Svelte components and views
|
|
67
|
+
- `/js` - JavaScript assets and modules
|
|
68
|
+
- `/routes` - Route definitions
|
|
69
|
+
- `/migrations` - Database migrations
|
|
70
|
+
- `/public` - Static files
|
|
71
|
+
- `/dist` - Compiled assets (generated)
|
|
72
|
+
- `/build` - Production build output
|
|
73
|
+
|
|
74
|
+
## Key Dependencies
|
|
75
|
+
|
|
76
|
+
### Backend
|
|
77
|
+
- HyperExpress - High-performance web server
|
|
78
|
+
- Knex - SQL query builder
|
|
79
|
+
- SQLite3 - Database
|
|
80
|
+
- Nodemailer - Email sending
|
|
81
|
+
- Redis - Caching (optional)
|
|
82
|
+
|
|
83
|
+
### Frontend
|
|
84
|
+
- Svelte 5 - UI framework
|
|
85
|
+
- Inertia.js - Client-server communication
|
|
86
|
+
- TailwindCSS - Utility-first CSS framework
|
|
87
|
+
- Vite - Build tool and dev server
|
|
88
|
+
|
|
89
|
+
## Scripts
|
|
90
|
+
|
|
91
|
+
- `npm run dev` - Start development server
|
|
92
|
+
- `npm run build` - Build for production
|
|
93
|
+
|
|
94
|
+
## Contributing
|
|
95
|
+
|
|
96
|
+
1. Fork the repository
|
|
97
|
+
2. Create your feature branch
|
|
98
|
+
3. Commit your changes
|
|
99
|
+
4. Push to the branch
|
|
100
|
+
5. Create a new Pull Request
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
ISC License
|
|
105
|
+
|
|
106
|
+
## Tutorial: Building Your First App
|
|
107
|
+
|
|
108
|
+
This tutorial will guide you through building a simple application using this framework.
|
|
109
|
+
|
|
110
|
+
### 1. Setting Up a New Route and Controller
|
|
111
|
+
|
|
112
|
+
First, let's create a new route and controller for a blog post feature.
|
|
113
|
+
|
|
114
|
+
1. Create a new controller file `app/controllers/PostController.ts`:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { Request, Response } from "../../type";
|
|
118
|
+
import DB from "../services/DB";
|
|
119
|
+
|
|
120
|
+
class Controller {
|
|
121
|
+
public async index(request: Request, response: Response) {
|
|
122
|
+
const posts = await DB.from("posts");
|
|
123
|
+
return response.inertia("posts/index", { posts });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public async create(request: Request, response: Response) {
|
|
127
|
+
return response.inertia("posts/create");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public async store(request: Request, response: Response) {
|
|
131
|
+
const { title, content } = request.body;
|
|
132
|
+
|
|
133
|
+
await DB.table("posts").insert({
|
|
134
|
+
title,
|
|
135
|
+
content,
|
|
136
|
+
created_at: Date.now(),
|
|
137
|
+
updated_at: Date.now()
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return response.redirect("/posts");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export default new Controller();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. Add routes in `routes/web.ts`:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import PostController from "../app/controllers/PostController";
|
|
151
|
+
|
|
152
|
+
// Add these routes with your existing routes
|
|
153
|
+
Route.get("/posts", PostController.index);
|
|
154
|
+
Route.get("/posts/create", PostController.create);
|
|
155
|
+
Route.post("/posts", PostController.store);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 2. Creating the Database Migration
|
|
159
|
+
|
|
160
|
+
Create a migration for the posts table:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npx knex migrate:make create_posts_table
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
In the generated migration file:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { Knex } from "knex";
|
|
170
|
+
|
|
171
|
+
export async function up(knex: Knex): Promise<void> {
|
|
172
|
+
await knex.schema.createTable('posts', function (table) {
|
|
173
|
+
table.increments('id').primary();
|
|
174
|
+
table.string('title').notNullable();
|
|
175
|
+
table.text('content').notNullable();
|
|
176
|
+
table.bigInteger('created_at');
|
|
177
|
+
table.bigInteger('updated_at');
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function down(knex: Knex): Promise<void> {
|
|
182
|
+
await knex.schema.dropTable('posts');
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Run the migration:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npx knex migrate:latest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 3. Creating Svelte Components
|
|
193
|
+
|
|
194
|
+
1. Create `resources/views/posts/index.svelte`:
|
|
195
|
+
|
|
196
|
+
```svelte
|
|
197
|
+
<script>
|
|
198
|
+
export let posts = [];
|
|
199
|
+
</script>
|
|
200
|
+
|
|
201
|
+
<div class="max-w-4xl mx-auto p-4">
|
|
202
|
+
<div class="flex justify-between items-center mb-6">
|
|
203
|
+
<h1 class="text-2xl font-bold">Blog Posts</h1>
|
|
204
|
+
<a
|
|
205
|
+
href="/posts/create"
|
|
206
|
+
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
|
|
207
|
+
>
|
|
208
|
+
Create Post
|
|
209
|
+
</a>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<div class="space-y-4">
|
|
213
|
+
{#each posts as post}
|
|
214
|
+
<div class="border p-4 rounded">
|
|
215
|
+
<h2 class="text-xl font-semibold">{post.title}</h2>
|
|
216
|
+
<p class="mt-2 text-gray-600">{post.content}</p>
|
|
217
|
+
</div>
|
|
218
|
+
{/each}
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
2. Create `resources/views/posts/create.svelte`:
|
|
224
|
+
|
|
225
|
+
```svelte
|
|
226
|
+
<script>
|
|
227
|
+
import { router } from '@inertiajs/svelte';
|
|
228
|
+
|
|
229
|
+
let form = {
|
|
230
|
+
title: '',
|
|
231
|
+
content: ''
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
function handleSubmit() {
|
|
235
|
+
router.post('/posts', form);
|
|
236
|
+
}
|
|
237
|
+
</script>
|
|
238
|
+
|
|
239
|
+
<div class="max-w-4xl mx-auto p-4">
|
|
240
|
+
<h1 class="text-2xl font-bold mb-6">Create New Post</h1>
|
|
241
|
+
|
|
242
|
+
<form on:submit|preventDefault={handleSubmit} class="space-y-4">
|
|
243
|
+
<div>
|
|
244
|
+
<label class="block text-sm font-medium mb-1">Title</label>
|
|
245
|
+
<input
|
|
246
|
+
type="text"
|
|
247
|
+
bind:value={form.title}
|
|
248
|
+
class="w-full px-3 py-2 border rounded"
|
|
249
|
+
/>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<div>
|
|
253
|
+
<label class="block text-sm font-medium mb-1">Content</label>
|
|
254
|
+
<textarea
|
|
255
|
+
bind:value={form.content}
|
|
256
|
+
class="w-full px-3 py-2 border rounded h-32"
|
|
257
|
+
></textarea>
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<div>
|
|
261
|
+
<button
|
|
262
|
+
type="submit"
|
|
263
|
+
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
|
|
264
|
+
>
|
|
265
|
+
Create Post
|
|
266
|
+
</button>
|
|
267
|
+
</div>
|
|
268
|
+
</form>
|
|
269
|
+
</div>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 4. Testing Your Application
|
|
273
|
+
|
|
274
|
+
1. Start the development server:
|
|
275
|
+
```bash
|
|
276
|
+
npm run dev
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
2. Visit `http://localhost:5555/posts` in your browser
|
|
280
|
+
3. Try creating a new post using the form
|
|
281
|
+
4. View the list of posts on the index page
|
|
282
|
+
|
|
283
|
+
### Key Concepts
|
|
284
|
+
|
|
285
|
+
1. **Routing**: Routes are defined in `routes/web.ts` using the HyperExpress router
|
|
286
|
+
2. **Controllers**: Handle business logic and return Inertia responses
|
|
287
|
+
3. **Database**: Use Knex.js for database operations and migrations
|
|
288
|
+
4. **Frontend**: Svelte components with Inertia.js for seamless page transitions
|
|
289
|
+
5. **Styling**: TailwindCSS for utility-first styling
|
|
290
|
+
|
|
291
|
+
### Best Practices
|
|
292
|
+
|
|
293
|
+
1. **File Organization**
|
|
294
|
+
- Keep controllers in `app/controllers`
|
|
295
|
+
- Place Svelte components in `resources/views`
|
|
296
|
+
- Database migrations in `migrations`
|
|
297
|
+
|
|
298
|
+
2. **Code Structure**
|
|
299
|
+
- Use TypeScript types for better type safety
|
|
300
|
+
- Keep controllers focused on single responsibilities
|
|
301
|
+
- Use Inertia.js for state management between server and client
|
|
302
|
+
|
|
303
|
+
3. **Database**
|
|
304
|
+
- Always use migrations for database changes
|
|
305
|
+
- Use the Query Builder for complex queries
|
|
306
|
+
- Include timestamps for tracking record changes
|
|
307
|
+
|
|
308
|
+
Need help with anything specific? Feel free to ask!
|
|
309
|
+
|
package/bin/cli.js
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { program } = require('commander');
|
|
4
|
-
const prompts = require('prompts');
|
|
5
|
-
const degit = require('degit');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const { execSync } = require('child_process');
|
|
9
|
-
|
|
10
|
-
program
|
|
11
|
-
.name('create-laju-app')
|
|
12
|
-
.description('CLI to create a new project from template')
|
|
13
|
-
.version('1.0.0');
|
|
14
|
-
|
|
15
|
-
program
|
|
16
|
-
.argument('[project-directory]', 'Project directory name')
|
|
17
|
-
.action(async (projectDirectory) => {
|
|
18
|
-
try {
|
|
19
|
-
// If no project name, ask user
|
|
20
|
-
if (!projectDirectory) {
|
|
21
|
-
const response = await prompts({
|
|
22
|
-
type: 'text',
|
|
23
|
-
name: 'projectDirectory',
|
|
24
|
-
message: 'Enter project name:'
|
|
25
|
-
});
|
|
26
|
-
projectDirectory = response.projectDirectory;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!projectDirectory) {
|
|
30
|
-
console.log('Project name is required to continue.');
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const targetPath = path.resolve(projectDirectory);
|
|
35
|
-
|
|
36
|
-
// Check if directory exists
|
|
37
|
-
if (fs.existsSync(targetPath)) {
|
|
38
|
-
console.log(`Directory ${projectDirectory} already exists. Choose another name.`);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
console.log(`Creating a new project in ${targetPath}...`);
|
|
43
|
-
|
|
44
|
-
// Clone template from GitHub
|
|
45
|
-
const emitter = degit('maulanashalihin/laju');
|
|
46
|
-
|
|
47
|
-
await emitter.clone(targetPath);
|
|
48
|
-
|
|
49
|
-
// Read package.json from template
|
|
50
|
-
const packageJsonPath = path.join(targetPath, 'package.json');
|
|
51
|
-
const packageJson = require(packageJsonPath);
|
|
52
|
-
|
|
53
|
-
// Update project name in package.json
|
|
54
|
-
packageJson.name = projectDirectory;
|
|
55
|
-
|
|
56
|
-
// Write back package.json
|
|
57
|
-
fs.writeFileSync(
|
|
58
|
-
packageJsonPath,
|
|
59
|
-
JSON.stringify(packageJson, null, 2)
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Change directory and run setup commands
|
|
63
|
-
process.chdir(targetPath);
|
|
64
|
-
console.log('📦 Installing dependencies...');
|
|
65
|
-
execSync('npm install', { stdio: 'inherit' });
|
|
66
|
-
console.log('📝 Copying environment file...');
|
|
67
|
-
|
|
68
|
-
execSync(process.platform === 'win32' ? 'copy .env.example .env' : 'cp .env.example .env', { stdio: 'inherit' });
|
|
69
|
-
console.log('🔄 Running migrations...');
|
|
70
|
-
execSync('npx knex migrate:latest', { stdio: 'inherit' });
|
|
71
|
-
console.log('🎉 Project created successfully!');
|
|
72
|
-
console.log('');
|
|
73
|
-
console.log('🚀 Your project is ready! You can now start developing.');
|
|
74
|
-
|
|
75
|
-
console.log('');
|
|
76
|
-
console.log('👉 Next steps:');
|
|
77
|
-
console.log('📁 cd ' + projectDirectory);
|
|
78
|
-
console.log('🔥 npm run dev to start the development server.');
|
|
79
|
-
console.log('📦 npm run build to build the production files.');
|
|
80
|
-
console.log('');
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error('Error:', error.message);
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const prompts = require('prompts');
|
|
5
|
+
const degit = require('degit');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('create-laju-app')
|
|
12
|
+
.description('CLI to create a new project from template')
|
|
13
|
+
.version('1.0.0');
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.argument('[project-directory]', 'Project directory name')
|
|
17
|
+
.action(async (projectDirectory) => {
|
|
18
|
+
try {
|
|
19
|
+
// If no project name, ask user
|
|
20
|
+
if (!projectDirectory) {
|
|
21
|
+
const response = await prompts({
|
|
22
|
+
type: 'text',
|
|
23
|
+
name: 'projectDirectory',
|
|
24
|
+
message: 'Enter project name:'
|
|
25
|
+
});
|
|
26
|
+
projectDirectory = response.projectDirectory;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!projectDirectory) {
|
|
30
|
+
console.log('Project name is required to continue.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const targetPath = path.resolve(projectDirectory);
|
|
35
|
+
|
|
36
|
+
// Check if directory exists
|
|
37
|
+
if (fs.existsSync(targetPath)) {
|
|
38
|
+
console.log(`Directory ${projectDirectory} already exists. Choose another name.`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(`Creating a new project in ${targetPath}...`);
|
|
43
|
+
|
|
44
|
+
// Clone template from GitHub
|
|
45
|
+
const emitter = degit('maulanashalihin/laju');
|
|
46
|
+
|
|
47
|
+
await emitter.clone(targetPath);
|
|
48
|
+
|
|
49
|
+
// Read package.json from template
|
|
50
|
+
const packageJsonPath = path.join(targetPath, 'package.json');
|
|
51
|
+
const packageJson = require(packageJsonPath);
|
|
52
|
+
|
|
53
|
+
// Update project name in package.json
|
|
54
|
+
packageJson.name = projectDirectory;
|
|
55
|
+
|
|
56
|
+
// Write back package.json
|
|
57
|
+
fs.writeFileSync(
|
|
58
|
+
packageJsonPath,
|
|
59
|
+
JSON.stringify(packageJson, null, 2)
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Change directory and run setup commands
|
|
63
|
+
process.chdir(targetPath);
|
|
64
|
+
console.log('📦 Installing dependencies...');
|
|
65
|
+
execSync('npm install', { stdio: 'inherit' });
|
|
66
|
+
console.log('📝 Copying environment file...');
|
|
67
|
+
|
|
68
|
+
execSync(process.platform === 'win32' ? 'copy .env.example .env' : 'cp .env.example .env', { stdio: 'inherit' });
|
|
69
|
+
console.log('🔄 Running migrations...');
|
|
70
|
+
execSync('npx knex migrate:latest', { stdio: 'inherit' });
|
|
71
|
+
console.log('🎉 Project created successfully!');
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log('🚀 Your project is ready! You can now start developing.');
|
|
74
|
+
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log('👉 Next steps:');
|
|
77
|
+
console.log('1. 📁 cd ' + projectDirectory);
|
|
78
|
+
console.log('2. 🔥 npm run dev to start the development server.');
|
|
79
|
+
console.log('3. 📦 npm run build to build the production files.');
|
|
80
|
+
console.log('');
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Error:', error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
91
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "create-laju-app",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"keywords": [
|
|
5
|
-
"laju",
|
|
6
|
-
"svelte",
|
|
7
|
-
"tailwindcss",
|
|
8
|
-
"hyper-express",
|
|
9
|
-
"sqlite",
|
|
10
|
-
"boilerplate",
|
|
11
|
-
"template",
|
|
12
|
-
"generator"
|
|
13
|
-
],
|
|
14
|
-
"bin": {
|
|
15
|
-
"create-laju-app": "./bin/cli.js"
|
|
16
|
-
},
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"child_process": "^1.0.2",
|
|
19
|
-
"commander": "^11.0.0",
|
|
20
|
-
"degit": "^2.8.4",
|
|
21
|
-
"prompts": "^2.4.2"
|
|
22
|
-
},
|
|
23
|
-
"homepage": "https://laju.dev",
|
|
24
|
-
"repository": {
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/maulanashalihin/laju.git"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "create-laju-app",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"laju",
|
|
6
|
+
"svelte",
|
|
7
|
+
"tailwindcss",
|
|
8
|
+
"hyper-express",
|
|
9
|
+
"sqlite",
|
|
10
|
+
"boilerplate",
|
|
11
|
+
"template",
|
|
12
|
+
"generator"
|
|
13
|
+
],
|
|
14
|
+
"bin": {
|
|
15
|
+
"create-laju-app": "./bin/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"child_process": "^1.0.2",
|
|
19
|
+
"commander": "^11.0.0",
|
|
20
|
+
"degit": "^2.8.4",
|
|
21
|
+
"prompts": "^2.4.2"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://laju.dev",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/maulanashalihin/laju.git"
|
|
27
|
+
}
|
|
28
|
+
}
|