my-project-scaffold 1.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
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# my-project-scaffold
|
|
2
|
+
|
|
3
|
+
A CLI tool to generate project templates for Vue, React, Node.js, Angular and Svelte.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g my-project-scaffold
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Create a new project
|
|
15
|
+
scaffold create <project-name>
|
|
16
|
+
|
|
17
|
+
# Select project type (use arrow keys to navigate, enter to confirm)
|
|
18
|
+
? 选择项目类型: (Use arrow keys)
|
|
19
|
+
❯ Vue
|
|
20
|
+
React
|
|
21
|
+
Node.js
|
|
22
|
+
Angular
|
|
23
|
+
Svelte
|
|
24
|
+
|
|
25
|
+
# Enter project directory
|
|
26
|
+
cd <project-name>
|
|
27
|
+
|
|
28
|
+
# Install dependencies
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
# Run project
|
|
32
|
+
# Vue: npm run dev
|
|
33
|
+
# React: npm start
|
|
34
|
+
# Node.js: npm start or npm run dev
|
|
35
|
+
# Angular: npm start
|
|
36
|
+
# Svelte: npm run dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Supported Project Types
|
|
40
|
+
|
|
41
|
+
- **Vue**: Vue 3 + Vite
|
|
42
|
+
- **React**: React 18 + React Scripts
|
|
43
|
+
- **Node.js**: Express server
|
|
44
|
+
- **Angular**: Angular 16
|
|
45
|
+
- **Svelte**: Svelte 4 + Vite
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Interactive command-line interface
|
|
50
|
+
- Multiple project templates
|
|
51
|
+
- Automatic directory creation
|
|
52
|
+
- Pre-configured dependencies
|
|
53
|
+
- Standard project structure
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
ISC
|
package/index.js
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const inquirer = require('inquirer').default;
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
// 定义脚手架命令
|
|
9
|
+
program
|
|
10
|
+
.version('1.0.0')
|
|
11
|
+
.command('create <name>')
|
|
12
|
+
.description('创建一个新的项目')
|
|
13
|
+
.action(async (name) => {
|
|
14
|
+
console.log(`正在创建项目 ${name}...`);
|
|
15
|
+
|
|
16
|
+
// 询问用户项目类型
|
|
17
|
+
const answers = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'type',
|
|
21
|
+
message: '选择项目类型:',
|
|
22
|
+
choices: ['Vue', 'React', 'Node.js', 'Angular', 'Svelte']
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
console.log(`选择的项目类型: ${answers.type}`);
|
|
26
|
+
|
|
27
|
+
// 创建项目目录
|
|
28
|
+
const projectPath = path.join(process.cwd(), name);
|
|
29
|
+
console.log(`项目路径: ${projectPath}`);
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(projectPath)) {
|
|
32
|
+
console.log('创建项目目录...');
|
|
33
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
34
|
+
console.log('项目目录创建成功');
|
|
35
|
+
} else {
|
|
36
|
+
console.log('项目目录已存在');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 根据项目类型创建不同的模板
|
|
40
|
+
const projectType = answers.type.toLowerCase();
|
|
41
|
+
switch (projectType) {
|
|
42
|
+
case 'vue':
|
|
43
|
+
createVueProject(projectPath, name);
|
|
44
|
+
break;
|
|
45
|
+
case 'react':
|
|
46
|
+
createReactProject(projectPath, name);
|
|
47
|
+
break;
|
|
48
|
+
case 'node.js':
|
|
49
|
+
createNodeProject(projectPath, name);
|
|
50
|
+
break;
|
|
51
|
+
case 'angular':
|
|
52
|
+
createAngularProject(projectPath, name);
|
|
53
|
+
break;
|
|
54
|
+
case 'svelte':
|
|
55
|
+
createSvelteProject(projectPath, name);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`项目 ${name} 创建完成!`);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 创建 Vue 项目模板
|
|
63
|
+
function createVueProject(projectPath, name) {
|
|
64
|
+
// 创建 package.json
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(projectPath, 'package.json'),
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
name,
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
private: true,
|
|
71
|
+
scripts: {
|
|
72
|
+
dev: 'vite',
|
|
73
|
+
build: 'vite build',
|
|
74
|
+
preview: 'vite preview'
|
|
75
|
+
},
|
|
76
|
+
dependencies: {
|
|
77
|
+
vue: '^3.3.4'
|
|
78
|
+
},
|
|
79
|
+
devDependencies: {
|
|
80
|
+
'@vitejs/plugin-vue': '^4.2.3',
|
|
81
|
+
vite: '^4.3.9'
|
|
82
|
+
}
|
|
83
|
+
}, null, 2)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// 创建 vite.config.js
|
|
87
|
+
fs.writeFileSync(
|
|
88
|
+
path.join(projectPath, 'vite.config.js'),
|
|
89
|
+
`import { defineConfig } from 'vite'
|
|
90
|
+
import vue from '@vitejs/plugin-vue'
|
|
91
|
+
|
|
92
|
+
export default defineConfig({
|
|
93
|
+
plugins: [vue()],
|
|
94
|
+
})
|
|
95
|
+
`
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// 创建 index.html
|
|
99
|
+
fs.writeFileSync(
|
|
100
|
+
path.join(projectPath, 'index.html'),
|
|
101
|
+
`<!DOCTYPE html>
|
|
102
|
+
<html lang="zh-CN">
|
|
103
|
+
<head>
|
|
104
|
+
<meta charset="UTF-8" />
|
|
105
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
106
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
107
|
+
<title>${name}</title>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div id="app"></div>
|
|
111
|
+
<script type="module" src="/src/main.js"></script>
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
114
|
+
`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// 创建 src 目录
|
|
118
|
+
const srcPath = path.join(projectPath, 'src');
|
|
119
|
+
if (!fs.existsSync(srcPath)) {
|
|
120
|
+
fs.mkdirSync(srcPath);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 创建 main.js
|
|
124
|
+
fs.writeFileSync(
|
|
125
|
+
path.join(srcPath, 'main.js'),
|
|
126
|
+
`import { createApp } from 'vue'
|
|
127
|
+
import App from './App.vue'
|
|
128
|
+
|
|
129
|
+
createApp(App).mount('#app')
|
|
130
|
+
`
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// 创建 App.vue
|
|
134
|
+
fs.writeFileSync(
|
|
135
|
+
path.join(srcPath, 'App.vue'),
|
|
136
|
+
`<template>
|
|
137
|
+
<div>
|
|
138
|
+
<h1>Hello Vue 3!</h1>
|
|
139
|
+
<p>Welcome to ${name}</p>
|
|
140
|
+
</div>
|
|
141
|
+
</template>
|
|
142
|
+
|
|
143
|
+
<script>
|
|
144
|
+
export default {
|
|
145
|
+
name: 'App'
|
|
146
|
+
}
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<style>
|
|
150
|
+
body {
|
|
151
|
+
font-family: Arial, sans-serif;
|
|
152
|
+
margin: 0;
|
|
153
|
+
padding: 20px;
|
|
154
|
+
background-color: #f0f0f0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
h1 {
|
|
158
|
+
color: #333;
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
161
|
+
`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 创建 React 项目模板
|
|
166
|
+
function createReactProject(projectPath, name) {
|
|
167
|
+
// 创建 package.json
|
|
168
|
+
fs.writeFileSync(
|
|
169
|
+
path.join(projectPath, 'package.json'),
|
|
170
|
+
JSON.stringify({
|
|
171
|
+
name,
|
|
172
|
+
version: '1.0.0',
|
|
173
|
+
private: true,
|
|
174
|
+
scripts: {
|
|
175
|
+
start: 'react-scripts start',
|
|
176
|
+
build: 'react-scripts build',
|
|
177
|
+
test: 'react-scripts test',
|
|
178
|
+
eject: 'react-scripts eject'
|
|
179
|
+
},
|
|
180
|
+
dependencies: {
|
|
181
|
+
react: '^18.2.0',
|
|
182
|
+
'react-dom': '^18.2.0'
|
|
183
|
+
},
|
|
184
|
+
devDependencies: {
|
|
185
|
+
'@testing-library/jest-dom': '^5.16.5',
|
|
186
|
+
'@testing-library/react': '^13.4.0',
|
|
187
|
+
'@testing-library/user-event': '^13.5.0',
|
|
188
|
+
'react-scripts': '5.0.1'
|
|
189
|
+
}
|
|
190
|
+
}, null, 2)
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// 创建 public 目录
|
|
194
|
+
const publicPath = path.join(projectPath, 'public');
|
|
195
|
+
if (!fs.existsSync(publicPath)) {
|
|
196
|
+
fs.mkdirSync(publicPath);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 创建 index.html
|
|
200
|
+
fs.writeFileSync(
|
|
201
|
+
path.join(publicPath, 'index.html'),
|
|
202
|
+
`<!DOCTYPE html>
|
|
203
|
+
<html lang="zh-CN">
|
|
204
|
+
<head>
|
|
205
|
+
<meta charset="utf-8" />
|
|
206
|
+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
207
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
208
|
+
<title>${name}</title>
|
|
209
|
+
</head>
|
|
210
|
+
<body>
|
|
211
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
212
|
+
<div id="root"></div>
|
|
213
|
+
</body>
|
|
214
|
+
</html>
|
|
215
|
+
`
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// 创建 src 目录
|
|
219
|
+
const srcPath = path.join(projectPath, 'src');
|
|
220
|
+
if (!fs.existsSync(srcPath)) {
|
|
221
|
+
fs.mkdirSync(srcPath);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 创建 index.js
|
|
225
|
+
fs.writeFileSync(
|
|
226
|
+
path.join(srcPath, 'index.js'),
|
|
227
|
+
`import React from 'react';
|
|
228
|
+
import ReactDOM from 'react-dom/client';
|
|
229
|
+
import './index.css';
|
|
230
|
+
import App from './App';
|
|
231
|
+
|
|
232
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
233
|
+
root.render(
|
|
234
|
+
<React.StrictMode>
|
|
235
|
+
<App />
|
|
236
|
+
</React.StrictMode>
|
|
237
|
+
);
|
|
238
|
+
`
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// 创建 index.css
|
|
242
|
+
fs.writeFileSync(
|
|
243
|
+
path.join(srcPath, 'index.css'),
|
|
244
|
+
`body {
|
|
245
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
246
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
247
|
+
sans-serif;
|
|
248
|
+
-webkit-font-smoothing: antialiased;
|
|
249
|
+
-moz-osx-font-smoothing: grayscale;
|
|
250
|
+
margin: 0;
|
|
251
|
+
padding: 20px;
|
|
252
|
+
background-color: #f0f0f0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
code {
|
|
256
|
+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
257
|
+
monospace;
|
|
258
|
+
}
|
|
259
|
+
`
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// 创建 App.js
|
|
263
|
+
fs.writeFileSync(
|
|
264
|
+
path.join(srcPath, 'App.js'),
|
|
265
|
+
`import './App.css';
|
|
266
|
+
|
|
267
|
+
function App() {
|
|
268
|
+
return (
|
|
269
|
+
<div className="App">
|
|
270
|
+
<h1>Hello React!</h1>
|
|
271
|
+
<p>Welcome to ${name}</p>
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export default App;
|
|
277
|
+
`
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
// 创建 App.css
|
|
281
|
+
fs.writeFileSync(
|
|
282
|
+
path.join(srcPath, 'App.css'),
|
|
283
|
+
`.App {
|
|
284
|
+
text-align: center;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
h1 {
|
|
288
|
+
color: #333;
|
|
289
|
+
}
|
|
290
|
+
`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 创建 Node.js 项目模板
|
|
295
|
+
function createNodeProject(projectPath, name) {
|
|
296
|
+
// 创建 package.json
|
|
297
|
+
fs.writeFileSync(
|
|
298
|
+
path.join(projectPath, 'package.json'),
|
|
299
|
+
JSON.stringify({
|
|
300
|
+
name,
|
|
301
|
+
version: '1.0.0',
|
|
302
|
+
main: 'index.js',
|
|
303
|
+
scripts: {
|
|
304
|
+
start: 'node index.js',
|
|
305
|
+
dev: 'nodemon index.js'
|
|
306
|
+
},
|
|
307
|
+
dependencies: {
|
|
308
|
+
express: '^4.18.2'
|
|
309
|
+
},
|
|
310
|
+
devDependencies: {
|
|
311
|
+
nodemon: '^2.0.22'
|
|
312
|
+
}
|
|
313
|
+
}, null, 2)
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
// 创建 index.js
|
|
317
|
+
fs.writeFileSync(
|
|
318
|
+
path.join(projectPath, 'index.js'),
|
|
319
|
+
`const express = require('express');
|
|
320
|
+
const app = express();
|
|
321
|
+
const port = 3000;
|
|
322
|
+
|
|
323
|
+
app.get('/', (req, res) => {
|
|
324
|
+
res.send('Hello Node.js!');
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
app.listen(port, () => {
|
|
328
|
+
console.log('Server running at http://localhost:' + port);
|
|
329
|
+
});
|
|
330
|
+
`
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
// 创建 README.md
|
|
334
|
+
fs.writeFileSync(
|
|
335
|
+
path.join(projectPath, 'README.md'),
|
|
336
|
+
`# ${name}
|
|
337
|
+
|
|
338
|
+
Node.js 项目
|
|
339
|
+
|
|
340
|
+
## 安装依赖
|
|
341
|
+
|
|
342
|
+
bash
|
|
343
|
+
npm install
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
## 运行
|
|
347
|
+
|
|
348
|
+
bash
|
|
349
|
+
npm start
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
## 开发模式
|
|
353
|
+
|
|
354
|
+
bash
|
|
355
|
+
npm run dev
|
|
356
|
+
|
|
357
|
+
`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 创建 Angular 项目模板
|
|
362
|
+
function createAngularProject(projectPath, name) {
|
|
363
|
+
// 创建 package.json
|
|
364
|
+
fs.writeFileSync(
|
|
365
|
+
path.join(projectPath, 'package.json'),
|
|
366
|
+
JSON.stringify({
|
|
367
|
+
name,
|
|
368
|
+
version: '0.0.0',
|
|
369
|
+
scripts: {
|
|
370
|
+
ng: 'ng',
|
|
371
|
+
start: 'ng serve',
|
|
372
|
+
build: 'ng build',
|
|
373
|
+
test: 'ng test',
|
|
374
|
+
lint: 'ng lint',
|
|
375
|
+
e2e: 'ng e2e'
|
|
376
|
+
},
|
|
377
|
+
private: true,
|
|
378
|
+
dependencies: {
|
|
379
|
+
'@angular/animations': '^16.0.0',
|
|
380
|
+
'@angular/common': '^16.0.0',
|
|
381
|
+
'@angular/compiler': '^16.0.0',
|
|
382
|
+
'@angular/core': '^16.0.0',
|
|
383
|
+
'@angular/forms': '^16.0.0',
|
|
384
|
+
'@angular/platform-browser': '^16.0.0',
|
|
385
|
+
'@angular/platform-browser-dynamic': '^16.0.0',
|
|
386
|
+
'@angular/router': '^16.0.0',
|
|
387
|
+
'rxjs': '~7.8.0',
|
|
388
|
+
'tslib': '^2.3.0',
|
|
389
|
+
'zone.js': '~0.13.0'
|
|
390
|
+
},
|
|
391
|
+
devDependencies: {
|
|
392
|
+
'@angular-devkit/build-angular': '^16.0.0',
|
|
393
|
+
'@angular/cli': '^16.0.0',
|
|
394
|
+
'@angular/compiler-cli': '^16.0.0',
|
|
395
|
+
'@types/jasmine': '~4.3.0',
|
|
396
|
+
'jasmine-core': '~4.6.0',
|
|
397
|
+
'karma': '~6.4.0',
|
|
398
|
+
'karma-chrome-launcher': '~3.2.0',
|
|
399
|
+
'karma-coverage': '~2.2.0',
|
|
400
|
+
'karma-jasmine': '~5.1.0',
|
|
401
|
+
'karma-jasmine-html-reporter': '~2.0.0',
|
|
402
|
+
'typescript': '~5.0.0'
|
|
403
|
+
}
|
|
404
|
+
}, null, 2)
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
// 创建 README.md
|
|
408
|
+
fs.writeFileSync(
|
|
409
|
+
path.join(projectPath, 'README.md'),
|
|
410
|
+
`# ${name}
|
|
411
|
+
|
|
412
|
+
Angular 项目
|
|
413
|
+
|
|
414
|
+
## 安装依赖
|
|
415
|
+
|
|
416
|
+
bash
|
|
417
|
+
npm install
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
## 运行
|
|
421
|
+
|
|
422
|
+
bash
|
|
423
|
+
npm start
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
## 构建
|
|
427
|
+
|
|
428
|
+
bash
|
|
429
|
+
npm run build
|
|
430
|
+
|
|
431
|
+
`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 创建 Svelte 项目模板
|
|
436
|
+
function createSvelteProject(projectPath, name) {
|
|
437
|
+
// 创建 package.json
|
|
438
|
+
fs.writeFileSync(
|
|
439
|
+
path.join(projectPath, 'package.json'),
|
|
440
|
+
JSON.stringify({
|
|
441
|
+
name,
|
|
442
|
+
private: true,
|
|
443
|
+
version: '0.0.0',
|
|
444
|
+
type: 'module',
|
|
445
|
+
scripts: {
|
|
446
|
+
dev: 'vite',
|
|
447
|
+
build: 'vite build',
|
|
448
|
+
preview: 'vite preview'
|
|
449
|
+
},
|
|
450
|
+
dependencies: {
|
|
451
|
+
svelte: '^4.0.0'
|
|
452
|
+
},
|
|
453
|
+
devDependencies: {
|
|
454
|
+
'@sveltejs/vite-plugin-svelte': '^2.0.0',
|
|
455
|
+
vite: '^4.0.0'
|
|
456
|
+
}
|
|
457
|
+
}, null, 2)
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
// 创建 vite.config.js
|
|
461
|
+
fs.writeFileSync(
|
|
462
|
+
path.join(projectPath, 'vite.config.js'),
|
|
463
|
+
`import { defineConfig } from 'vite'
|
|
464
|
+
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
|
465
|
+
|
|
466
|
+
export default defineConfig({
|
|
467
|
+
plugins: [svelte()],
|
|
468
|
+
})
|
|
469
|
+
`
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// 创建 index.html
|
|
473
|
+
fs.writeFileSync(
|
|
474
|
+
path.join(projectPath, 'index.html'),
|
|
475
|
+
`<!DOCTYPE html>
|
|
476
|
+
<html lang="zh-CN">
|
|
477
|
+
<head>
|
|
478
|
+
<meta charset="UTF-8" />
|
|
479
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
480
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
481
|
+
<title>${name}</title>
|
|
482
|
+
</head>
|
|
483
|
+
<body>
|
|
484
|
+
<div id="app"></div>
|
|
485
|
+
<script type="module" src="/src/main.js"></script>
|
|
486
|
+
</body>
|
|
487
|
+
</html>
|
|
488
|
+
`
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// 创建 src 目录
|
|
492
|
+
const srcPath = path.join(projectPath, 'src');
|
|
493
|
+
if (!fs.existsSync(srcPath)) {
|
|
494
|
+
fs.mkdirSync(srcPath);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 创建 main.js
|
|
498
|
+
fs.writeFileSync(
|
|
499
|
+
path.join(srcPath, 'main.js'),
|
|
500
|
+
`import App from './App.svelte'
|
|
501
|
+
|
|
502
|
+
const app = new App({
|
|
503
|
+
target: document.getElementById('app'),
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
export default app
|
|
507
|
+
`
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
// 创建 App.svelte
|
|
511
|
+
fs.writeFileSync(
|
|
512
|
+
path.join(srcPath, 'App.svelte'),
|
|
513
|
+
`<script>
|
|
514
|
+
let name = 'Svelte';
|
|
515
|
+
</script>
|
|
516
|
+
|
|
517
|
+
<main>
|
|
518
|
+
<h1>Hello {name}!</h1>
|
|
519
|
+
<p>Welcome to ${name}</p>
|
|
520
|
+
</main>
|
|
521
|
+
|
|
522
|
+
<style>
|
|
523
|
+
main {
|
|
524
|
+
font-family: Arial, sans-serif;
|
|
525
|
+
margin: 0;
|
|
526
|
+
padding: 20px;
|
|
527
|
+
background-color: #f0f0f0;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
h1 {
|
|
531
|
+
color: #333;
|
|
532
|
+
}
|
|
533
|
+
</style>
|
|
534
|
+
`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// 解析命令行参数
|
|
539
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-project-scaffold",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"scaffold": "./index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"scaffold",
|
|
13
|
+
"cli",
|
|
14
|
+
"project-generator",
|
|
15
|
+
"vue",
|
|
16
|
+
"react",
|
|
17
|
+
"nodejs",
|
|
18
|
+
"angular",
|
|
19
|
+
"svelte"
|
|
20
|
+
],
|
|
21
|
+
"author": "Your Name",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"description": "A CLI tool to generate project templates for Vue, React, Node.js, Angular and Svelte",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"commander": "^14.0.3",
|
|
26
|
+
"inquirer": "^13.3.2"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# 脚手架工具实现文档
|
|
2
|
+
|
|
3
|
+
## 1. 项目概述
|
|
4
|
+
|
|
5
|
+
这是一个基于 Node.js 开发的脚手架工具,用于快速创建不同类型的前端和后端项目。支持创建 Vue、React、Node.js、Angular 和 Svelte 项目模板。
|
|
6
|
+
|
|
7
|
+
## 2. 技术栈
|
|
8
|
+
|
|
9
|
+
- **Node.js**: 运行环境
|
|
10
|
+
- **commander**: 命令行参数解析
|
|
11
|
+
- **inquirer**: 交互式命令行界面
|
|
12
|
+
- **fs**: 文件系统操作
|
|
13
|
+
- **path**: 路径处理
|
|
14
|
+
|
|
15
|
+
## 3. 核心实现
|
|
16
|
+
|
|
17
|
+
### 3.1 项目结构
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
├── index.js # 脚手架主入口文件
|
|
21
|
+
├── package.json # 项目配置文件
|
|
22
|
+
└── README.md # 项目说明文档
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 3.2 命令行解析
|
|
26
|
+
|
|
27
|
+
使用 `commander` 库实现命令行参数解析,支持 `create` 命令创建新项目:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const { program } = require('commander');
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.version('1.0.0')
|
|
34
|
+
.command('create <name>')
|
|
35
|
+
.description('创建一个新的项目')
|
|
36
|
+
.action(async (name) => {
|
|
37
|
+
// 实现逻辑
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
program.parse(process.argv);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3.3 交互式选择
|
|
44
|
+
|
|
45
|
+
使用 `inquirer` 库实现交互式选择项目类型:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const inquirer = require('inquirer').default;
|
|
49
|
+
|
|
50
|
+
const answers = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'list',
|
|
53
|
+
name: 'type',
|
|
54
|
+
message: '选择项目类型:',
|
|
55
|
+
choices: ['Vue', 'React', 'Node.js', 'Angular', 'Svelte']
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3.4 目录创建
|
|
61
|
+
|
|
62
|
+
使用 `fs` 模块创建项目目录:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const fs = require('fs');
|
|
66
|
+
const path = require('path');
|
|
67
|
+
|
|
68
|
+
const projectPath = path.join(process.cwd(), name);
|
|
69
|
+
if (!fs.existsSync(projectPath)) {
|
|
70
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3.5 模板生成
|
|
75
|
+
|
|
76
|
+
根据用户选择的项目类型,调用对应的模板生成函数:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const projectType = answers.type.toLowerCase();
|
|
80
|
+
switch (projectType) {
|
|
81
|
+
case 'vue':
|
|
82
|
+
createVueProject(projectPath, name);
|
|
83
|
+
break;
|
|
84
|
+
case 'react':
|
|
85
|
+
createReactProject(projectPath, name);
|
|
86
|
+
break;
|
|
87
|
+
case 'node.js':
|
|
88
|
+
createNodeProject(projectPath, name);
|
|
89
|
+
break;
|
|
90
|
+
case 'angular':
|
|
91
|
+
createAngularProject(projectPath, name);
|
|
92
|
+
break;
|
|
93
|
+
case 'svelte':
|
|
94
|
+
createSvelteProject(projectPath, name);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 4. 项目模板实现
|
|
100
|
+
|
|
101
|
+
### 4.1 Vue 项目模板
|
|
102
|
+
|
|
103
|
+
- **package.json**: 配置 Vue 3 和 Vite 依赖
|
|
104
|
+
- **vite.config.js**: Vite 配置文件
|
|
105
|
+
- **index.html**: 入口 HTML 文件
|
|
106
|
+
- **src/main.js**: Vue 应用入口
|
|
107
|
+
- **src/App.vue**: 主组件
|
|
108
|
+
|
|
109
|
+
### 4.2 React 项目模板
|
|
110
|
+
|
|
111
|
+
- **package.json**: 配置 React 和 React Scripts 依赖
|
|
112
|
+
- **public/index.html**: 入口 HTML 文件
|
|
113
|
+
- **src/index.js**: React 应用入口
|
|
114
|
+
- **src/App.js**: 主组件
|
|
115
|
+
- **src/index.css** 和 **src/App.css**: 样式文件
|
|
116
|
+
|
|
117
|
+
### 4.3 Node.js 项目模板
|
|
118
|
+
|
|
119
|
+
- **package.json**: 配置 Express 依赖
|
|
120
|
+
- **index.js**: Express 服务器
|
|
121
|
+
- **README.md**: 项目说明
|
|
122
|
+
|
|
123
|
+
### 4.4 Angular 项目模板
|
|
124
|
+
|
|
125
|
+
- **package.json**: 配置 Angular 依赖
|
|
126
|
+
- **README.md**: 项目说明
|
|
127
|
+
|
|
128
|
+
### 4.5 Svelte 项目模板
|
|
129
|
+
|
|
130
|
+
- **package.json**: 配置 Svelte 和 Vite 依赖
|
|
131
|
+
- **vite.config.js**: Vite 配置文件
|
|
132
|
+
- **index.html**: 入口 HTML 文件
|
|
133
|
+
- **src/main.js**: Svelte 应用入口
|
|
134
|
+
- **src/App.svelte**: 主组件
|
|
135
|
+
|
|
136
|
+
## 5. 安装与使用
|
|
137
|
+
|
|
138
|
+
### 5.1 本地安装
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# 克隆项目
|
|
142
|
+
git clone <repository-url>
|
|
143
|
+
|
|
144
|
+
# 进入项目目录
|
|
145
|
+
cd cli
|
|
146
|
+
|
|
147
|
+
# 安装依赖
|
|
148
|
+
npm install
|
|
149
|
+
|
|
150
|
+
# 链接到全局
|
|
151
|
+
npm link
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 5.2 使用方法
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# 创建新项目
|
|
158
|
+
cli create <项目名称>
|
|
159
|
+
|
|
160
|
+
# 选择项目类型(使用方向键切换,回车确定)
|
|
161
|
+
? 选择项目类型: (Use arrow keys)
|
|
162
|
+
❯ Vue
|
|
163
|
+
React
|
|
164
|
+
Node.js
|
|
165
|
+
Angular
|
|
166
|
+
Svelte
|
|
167
|
+
|
|
168
|
+
# 进入项目目录
|
|
169
|
+
cd <项目名称>
|
|
170
|
+
|
|
171
|
+
# 安装依赖
|
|
172
|
+
npm install
|
|
173
|
+
|
|
174
|
+
# 运行项目
|
|
175
|
+
# Vue: npm run dev
|
|
176
|
+
# React: npm start
|
|
177
|
+
# Node.js: npm start 或 npm run dev
|
|
178
|
+
# Angular: npm start
|
|
179
|
+
# Svelte: npm run dev
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 6. 核心功能
|
|
183
|
+
|
|
184
|
+
1. **命令行界面**: 支持 `create` 命令创建新项目
|
|
185
|
+
2. **交互式选择**: 使用方向键切换项目类型,回车确定
|
|
186
|
+
3. **多项目类型**: 支持 Vue、React、Node.js、Angular 和 Svelte
|
|
187
|
+
4. **自动生成**: 自动创建项目目录和配置文件
|
|
188
|
+
5. **依赖管理**: 自动配置项目依赖
|
|
189
|
+
|
|
190
|
+
## 7. 实现细节
|
|
191
|
+
|
|
192
|
+
### 7.1 命令行参数处理
|
|
193
|
+
|
|
194
|
+
使用 `commander` 库解析命令行参数,支持 `create` 命令和项目名称参数。
|
|
195
|
+
|
|
196
|
+
### 7.2 交互式选择实现
|
|
197
|
+
|
|
198
|
+
使用 `inquirer` 库的 `list` 类型实现交互式选择,用户可以使用方向键切换选项,回车确定选择。
|
|
199
|
+
|
|
200
|
+
### 7.3 模板生成逻辑
|
|
201
|
+
|
|
202
|
+
为每种项目类型创建独立的生成函数,根据项目类型生成对应的文件结构和配置。
|
|
203
|
+
|
|
204
|
+
### 7.4 文件操作
|
|
205
|
+
|
|
206
|
+
使用 `fs.writeFileSync` 写入文件,`fs.mkdirSync` 创建目录,确保项目结构的完整性。
|
|
207
|
+
|
|
208
|
+
## 8. 扩展与定制
|
|
209
|
+
|
|
210
|
+
### 8.1 添加新的项目类型
|
|
211
|
+
|
|
212
|
+
1. 在 `inquirer.prompt` 的 `choices` 数组中添加新的项目类型
|
|
213
|
+
2. 在 `switch` 语句中添加对应的 case 分支
|
|
214
|
+
3. 创建对应的模板生成函数
|
|
215
|
+
|
|
216
|
+
### 8.2 自定义模板
|
|
217
|
+
|
|
218
|
+
修改对应的模板生成函数,调整文件内容和结构以满足特定需求。
|
|
219
|
+
|
|
220
|
+
## 9. 测试
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# 测试脚手架
|
|
224
|
+
node index.js create test-project
|
|
225
|
+
|
|
226
|
+
# 检查生成的项目结构ls test-project
|
|
227
|
+
|
|
228
|
+
# 验证项目配置
|
|
229
|
+
cat test-project/package.json
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 10. 总结
|
|
233
|
+
|
|
234
|
+
本脚手架工具通过 Node.js 实现了一个功能完整的项目生成器,支持多种项目类型,提供了友好的交互式界面,能够快速创建标准化的项目结构。核心实现包括命令行解析、交互式选择、目录创建和模板生成等功能,为开发者提供了便捷的项目初始化工具。
|