create-vite-vue 1.3.1 → 1.5.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/bin/index.js CHANGED
@@ -1,17 +1,43 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  import { execSync } from 'child_process'
3
3
  import fs from 'fs'
4
4
  import path from 'path'
5
5
  import prompts from 'prompts'
6
6
  import { fileURLToPath } from 'url'
7
7
 
8
+ // 检测 Node 版本
9
+ const requiredVersion = '22.19.0'
10
+
11
+ function compareVersion (v1, v2) {
12
+ const a = v1.split('.').map(Number)
13
+ const b = v2.split('.').map(Number)
14
+
15
+ for(let i = 0; i < Math.max(a.length, b.length); i++) {
16
+ const n1 = a[i] || 0
17
+ const n2 = b[i] || 0
18
+ if(n1 > n2) return 1
19
+ if(n1 < n2) return -1
20
+ }
21
+ return 0
22
+ }
23
+
24
+ const currentVersion = process.version.replace('v', '')
25
+
26
+ if(compareVersion(currentVersion, requiredVersion) < 0) {
27
+ console.error(`❌ Node.js 版本过低`)
28
+ console.error(`当前版本: ${currentVersion}`)
29
+ console.error(`最低要求: ${requiredVersion}`)
30
+ console.error(`请升级 Node.js 后再运行`)
31
+ process.exit(1)
32
+ }
33
+
8
34
  const __filename = fileURLToPath(import.meta.url)
9
35
  const __dirname = path.dirname(__filename)
10
36
 
11
37
  ; (async () => {
12
38
  // 1️⃣ 输入项目名
13
39
  let projectName
14
- while (true) {
40
+ while(true) {
15
41
  const res = await prompts({
16
42
  type: 'text',
17
43
  name: 'projectName',
@@ -19,10 +45,10 @@ const __dirname = path.dirname(__filename)
19
45
  validate: v => v ? true : '项目名不能为空'
20
46
  })
21
47
  projectName = res.projectName
22
- if (!projectName) process.exit(1)
48
+ if(!projectName) process.exit(1)
23
49
 
24
50
  const targetDir = path.resolve(process.cwd(), projectName)
25
- if (fs.existsSync(targetDir)) {
51
+ if(fs.existsSync(targetDir)) {
26
52
  console.log('❌ 目录已存在,请重新输入')
27
53
  continue
28
54
  }
@@ -31,6 +57,7 @@ const __dirname = path.dirname(__filename)
31
57
 
32
58
  const targetDir = path.resolve(process.cwd(), projectName)
33
59
 
60
+ // 选择语言
34
61
  const { language } = await prompts({
35
62
  type: 'select',
36
63
  name: 'language',
@@ -41,71 +68,50 @@ const __dirname = path.dirname(__filename)
41
68
  ]
42
69
  })
43
70
 
44
- // 2️⃣ 功能选择
45
- const features = await prompts([
46
- {
47
- type: 'select',
48
- name: 'router',
49
- message: '是否使用 vue-router?',
50
- choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
51
- },
52
- {
53
- type: 'select',
54
- name: 'pinia',
55
- message: '是否使用 Pinia(含持久化)?',
56
- choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
57
- },
58
- {
59
- type: 'select',
60
- name: 'axios',
61
- message: '是否使用 Axios?',
62
- choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
63
- },
64
- {
65
- type: 'select',
66
- name: 'ui',
67
- message: '请选择 UI 框架',
68
- choices: [
69
- { title: 'Element Plus(PC)', value: 'element' },
70
- { title: 'Vant(Mobile)', value: 'vant' },
71
- { title: '不使用 UI 框架', value: 'none' }
72
- ]
73
- }
74
- ])
75
-
76
- // ========== 新增:增强插件配置==========
77
- let extraPlugins = []
78
-
79
- const { wantExtra } = await prompts({
80
- type: 'toggle',
81
- name: 'wantExtra',
82
- message: '是否需要添加额外工具?',
83
- initial: false,
84
- active: '是',
85
- inactive: '否'
86
- })
87
-
88
- if (wantExtra) {
89
- const pluginOptions = [
71
+ // 2️⃣ 功能选择(多选)
72
+ const { featureList } = await prompts({
73
+ type: 'multiselect',
74
+ name: 'featureList',
75
+ message: '请选择基础功能(↑↓选择,空格确认,回车完成)',
76
+ instructions: false,
77
+ choices: [
78
+ { title: 'Vue Router', value: 'router' },
79
+ { title: 'Pinia(含持久化)', value: 'pinia' },
80
+ { title: 'Axios', value: 'axios' },
81
+ { title: 'Element Plus(PC UI)', value: 'element' },
82
+ { title: 'Vant(Mobile UI)', value: 'vant' },
90
83
  { title: 'VueUse(实用 Composition API)', value: 'vueuse' },
91
- { title: 'Lodash(实用工具库)', value: 'lodash' },
92
- { title: 'Day.js(轻量日期处理)', value: 'dayjs' },
84
+ { title: 'Lodash(工具库)', value: 'lodash' },
85
+ { title: 'Day.js(日期处理)', value: 'dayjs' },
93
86
  { title: 'Tailwind CSS(原子化 CSS)', value: 'tailwind' }
94
87
  ]
88
+ })
95
89
 
96
- const { selectedPlugins } = await prompts({
97
- type: 'multiselect',
98
- name: 'selectedPlugins',
99
- message: '请选择额外工具(↑↓选择,空格确认,回车完成)',
100
- choices: pluginOptions.map(p => ({ title: p.title, value: p.value })),
101
- instructions: false
102
- })
90
+ // 转换成原来的结构(保证后面代码基本不用动)
91
+ const features = {
92
+ router: featureList?.includes('router') || false,
93
+ pinia: featureList?.includes('pinia') || false,
94
+ axios: featureList?.includes('axios') || false,
95
+ ui: featureList?.filter(v => ['element', 'vant'].includes(v)) || []
96
+ }
103
97
 
104
- if (selectedPlugins?.length) {
105
- extraPlugins = selectedPlugins
106
- }
98
+ const extraPlugins = featureList?.filter(v =>
99
+ ['vueuse', 'lodash', 'dayjs', 'tailwind'].includes(v)
100
+ ) || []
101
+
102
+ // 询问是否开启自动路由
103
+ let autoRoute = false
104
+ if(features.router) {
105
+ const { enableAutoRoute } = await prompts({
106
+ type: 'toggle',
107
+ name: 'enableAutoRoute',
108
+ message: '是否开启自动配置路由(vite-plugin-pages)?',
109
+ initial: false,
110
+ active: '是',
111
+ inactive: '否'
112
+ })
113
+ autoRoute = enableAutoRoute
107
114
  }
108
- // ========== 增强插件配置结束 ==========
109
115
 
110
116
  // 3️⃣ 是否立即运行 dev
111
117
  const { runDev } = await prompts({
@@ -123,21 +129,21 @@ const __dirname = path.dirname(__filename)
123
129
  { recursive: true }
124
130
  )
125
131
 
126
- // 4️⃣-1️⃣ 替换 index.html 的 title
132
+ // 替换 index.html 的 title
127
133
  const indexPath = path.join(targetDir, 'index.html')
128
- if (fs.existsSync(indexPath)) {
134
+ if(fs.existsSync(indexPath)) {
129
135
  const indexContent = fs.readFileSync(indexPath, 'utf-8')
130
136
  fs.writeFileSync(
131
137
  indexPath,
132
138
  indexContent.replace(/<title>.*<\/title>/, `<title>${projectName}</title>`)
133
139
  )
134
140
  }
141
+
135
142
  // 追加 Tailwind CSS 导入
136
- if (extraPlugins.includes('tailwind')) {
143
+ if(extraPlugins.includes('tailwind')) {
137
144
  const stylePath = path.join(targetDir, 'src/style.css')
138
145
  const original = fs.readFileSync(stylePath, 'utf-8')
139
- // 在第一行追加,不重复添加
140
- if (!original.startsWith('@import "tailwindcss";')) {
146
+ if(!original.startsWith('@import "tailwindcss";')) {
141
147
  fs.writeFileSync(stylePath, `@import "tailwindcss";\n${original}`)
142
148
  }
143
149
  }
@@ -150,68 +156,56 @@ const __dirname = path.dirname(__filename)
150
156
  features.pinia && copy(language === 'ts' ? 'pinia-ts' : 'pinia-js')
151
157
  features.axios && copy(language === 'ts' ? 'axios-ts' : 'axios-js')
152
158
 
153
- // ========== 新增:拷贝增强插件模板 ==========
154
- for (const plugin of extraPlugins) {
159
+ // 拷贝增强插件模板
160
+ for(const plugin of extraPlugins) {
155
161
  const templateName = `${plugin}-${language === 'ts' ? 'ts' : 'js'}`
156
162
  const templatePath = path.resolve(__dirname, `../template/${templateName}`)
157
- if (fs.existsSync(templatePath)) {
163
+ if(fs.existsSync(templatePath)) {
158
164
  fs.cpSync(templatePath, targetDir, { recursive: true })
159
165
  }
160
166
  }
161
- // ========== 增强插件模板拷贝结束 ==========
162
167
 
163
- // 6️⃣ 生成 main.js
168
+ // 6️⃣ 生成 main.js / main.ts
164
169
  const mainFile = language === 'ts' ? 'main.ts' : 'main.js'
165
170
  const mainTplPath = path.join(targetDir, `src/${mainFile}.tpl`)
166
171
  let main = fs.readFileSync(mainTplPath, 'utf-8')
167
172
 
168
173
  const replacements = {
169
- // import
170
- // vue-router
171
174
  '/* __ROUTER_IMPORT__ */': features.router ? "import router from './router'" : '',
172
- // pinia
173
175
  '/* __PINIA_IMPORT__ */': features.pinia
174
176
  ? "import { createPinia } from 'pinia'\nimport persistedstate from 'pinia-plugin-persistedstate'"
175
177
  : '',
176
- // element-plus
177
- '/* __ELEMENT_IMPORT__ */': features.ui === 'element'
178
+ '/* __ELEMENT_IMPORT__ */': features.ui.includes('element')
178
179
  ? `import ElementPlus from 'element-plus'
179
180
  import zhCn from 'element-plus/es/locale/lang/zh-cn'
180
181
  import 'element-plus/dist/index.css'
181
182
  import * as ElementPlusIconsVue from '@element-plus/icons-vue'`
182
183
  : '',
183
- // vant
184
- '/* __VANT_IMPORT__ */': features.ui === 'vant'
184
+ '/* __VANT_IMPORT__ */': features.ui.includes('vant')
185
185
  ? `import Vant from 'vant'
186
186
  import 'vant/lib/index.css'`
187
187
  : '',
188
- // use
189
- //router
190
188
  '/* __ROUTER_USE__ */': features.router ? 'app.use(router)' : '',
191
- // pinia
192
189
  '/* __PINIA_USE__ */': features.pinia
193
190
  ? 'app.use(createPinia().use(persistedstate))'
194
191
  : '',
195
- // element-plus
196
- '/* __ELEMENT_USE__ */': features.ui === 'element'
192
+ '/* __ELEMENT_USE__ */': features.ui.includes('element')
197
193
  ? `app.use(ElementPlus, { locale: zhCn })
198
194
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
199
195
  app.component(key, component)
200
196
  }`
201
197
  : '',
202
- // vant
203
- '/* __VANT_USE__ */': features.ui === 'vant'
198
+ '/* __VANT_USE__ */': features.ui.includes('vant')
204
199
  ? 'app.use(Vant)'
205
200
  : ''
206
201
  }
207
- // ========== 增强插件占位符结束 ==========
208
202
 
209
203
  function escapeRegExp (str) {
210
204
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
211
205
  }
212
206
 
213
- for (const [placeholder, content] of Object.entries(replacements)) {
214
- if (content) {
207
+ for(const [placeholder, content] of Object.entries(replacements)) {
208
+ if(content) {
215
209
  main = main.replace(placeholder, content)
216
210
  } else {
217
211
  const re = new RegExp(`^\\s*${escapeRegExp(placeholder)}\\s*$\\n?`, 'gm')
@@ -222,42 +216,37 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
222
216
  main = main.replace(/(\s*)const app = createApp\(App\)/, '\n\n$1const app = createApp(App)')
223
217
  main = main.replace(/\n{3,}/g, '\n\n')
224
218
 
225
- fs.writeFileSync(
226
- path.join(targetDir, `src/${mainFile}`),
227
- main
228
- )
219
+ fs.writeFileSync(path.join(targetDir, `src/${mainFile}`), main)
229
220
  fs.unlinkSync(mainTplPath)
230
221
 
231
222
  // 7️⃣ 生成 package.json
232
223
  const pkgTpl = path.join(targetDir, 'package.json.tpl')
233
- if (fs.existsSync(pkgTpl)) {
224
+ if(fs.existsSync(pkgTpl)) {
234
225
  let pkg = fs.readFileSync(pkgTpl, 'utf-8')
235
226
 
236
227
  const optionalDeps = {}
237
- if (features.router) optionalDeps['vue-router'] = '^4.4.0'
238
- if (features.pinia) {
239
- optionalDeps['pinia'] = '^2.2.2'
240
- optionalDeps['pinia-plugin-persistedstate'] = '^3.2.1'
228
+ if(features.router) optionalDeps['vue-router'] = '^5.0.3'
229
+ if(features.pinia) {
230
+ optionalDeps['pinia'] = '^3.0.4'
231
+ optionalDeps['pinia-plugin-persistedstate'] = '^4.7.1'
241
232
  }
242
- if (features.axios) optionalDeps['axios'] = '^1.7.7'
243
- if (features.ui === 'element') {
244
- optionalDeps['element-plus'] = '^2.8.8'
245
- optionalDeps['@element-plus/icons-vue'] = '^2.3.1'
233
+ if(features.axios) optionalDeps['axios'] = '^1.13.6'
234
+ if(features.ui.includes('element')) {
235
+ optionalDeps['element-plus'] = '^2.13.3'
236
+ optionalDeps['@element-plus/icons-vue'] = '^2.3.2'
246
237
  }
247
- if (features.ui === 'vant') {
238
+ if(features.ui.includes('vant')) {
248
239
  optionalDeps['vant'] = '^4.9.22'
249
240
  }
250
-
251
- // ========== 新增:增强插件的依赖 ==========
252
- if (extraPlugins.includes('vueuse')) optionalDeps['@vueuse/core'] = '^14.1.0'
253
- if (extraPlugins.includes('dayjs')) optionalDeps['dayjs'] = '^1.11.19'
254
- if (extraPlugins.includes('lodash')) optionalDeps['lodash'] = '^4.17.23'
255
-
256
- // ========== 增强插件依赖结束 ==========
241
+ // 增强插件依赖
242
+ if(extraPlugins.includes('vueuse')) optionalDeps['@vueuse/core'] = '^14.2.1'
243
+ if(extraPlugins.includes('dayjs')) optionalDeps['dayjs'] = '^1.11.19'
244
+ if(extraPlugins.includes('lodash')) optionalDeps['lodash'] = '^4.17.23'
245
+ if(autoRoute) optionalDeps['vite-plugin-pages'] = '^0.33.3'
257
246
 
258
247
  let depsStr = ''
259
248
  const keys = Object.keys(optionalDeps)
260
- if (keys.length > 0) {
249
+ if(keys.length > 0) {
261
250
  depsStr = ',\n' + keys.map(k => ` "${k}": "${optionalDeps[k]}"`).join(',\n')
262
251
  }
263
252
 
@@ -269,18 +258,118 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
269
258
  fs.unlinkSync(pkgTpl)
270
259
  }
271
260
 
272
- // 8️⃣ 安装依赖
261
+ // 8️⃣ 配置自动路由
262
+ if(autoRoute) {
263
+ const viteConfigPath = path.join(targetDir, `vite.config.${language === 'ts' ? 'ts' : 'js'}`)
264
+ if(fs.existsSync(viteConfigPath)) {
265
+ let viteConfig = fs.readFileSync(viteConfigPath, 'utf-8')
266
+ if(!viteConfig.includes("import fs from 'fs'")) {
267
+ viteConfig = `import fs from 'fs'\n${viteConfig}`
268
+ }
269
+ // 确保顶部 import Pages
270
+ if(!viteConfig.includes("import Pages from 'vite-plugin-pages'")) {
271
+ viteConfig = viteConfig.replace(/(import .*?from .*?\n)/, `$1import Pages from 'vite-plugin-pages'\n`)
272
+ }
273
+ viteConfig = viteConfig.replace(/plugins:\s*\[/, `plugins: [
274
+ Pages({
275
+ dirs: 'src/views',
276
+ extensions: ['vue'],
277
+ exclude: ['**/_*.vue'],
278
+ async extendRoute(route) {
279
+ const componentPath = path.resolve(process.cwd(), route.component.slice(1))
280
+ const dirPath = path.dirname(componentPath)
281
+ const metaFile = path.resolve(dirPath, 'meta.json')
282
+ if(fs.existsSync(metaFile)) {
283
+ try {
284
+ const metaContent = fs.readFileSync(metaFile, 'utf-8')
285
+ const meta = JSON.parse(metaContent)
286
+ route.meta = { ...(route.meta || {}), ...meta }
287
+ } catch(err) {
288
+ console.warn(\`加载 \${metaFile} 失败:\`, err)
289
+ }
290
+ }
291
+ return { ...route }
292
+ }
293
+ }),`)
294
+ fs.writeFileSync(viteConfigPath, viteConfig)
295
+ }
296
+
297
+ // 创建 Home/meta.json
298
+ const homeMetaPath = path.join(targetDir, 'src/views/home/meta.json')
299
+ if(!fs.existsSync(homeMetaPath)) {
300
+ fs.writeFileSync(homeMetaPath, JSON.stringify({ title: '首页' }, null, 2))
301
+ }
302
+ if(language === 'ts') {
303
+ // 生成 types 目录
304
+ const typesDir = path.join(targetDir, 'src/types')
305
+ if(!fs.existsSync(typesDir)) fs.mkdirSync(typesDir, { recursive: true })
306
+
307
+ // 创建 vite-plugin-pages.d.ts
308
+ const vitePagesDtsPath = path.join(typesDir, 'vite-plugin-pages.d.ts')
309
+ const vitePagesDtsContent = `declare module '~pages' {
310
+ import type { RouteRecordRaw } from 'vue-router'
311
+ const routes: RouteRecordRaw[]
312
+ export default routes
313
+ }
314
+ `
315
+ fs.writeFileSync(vitePagesDtsPath, vitePagesDtsContent)
316
+ }
317
+
318
+ }
319
+
320
+ // 9️⃣ 替换 router/index.js
321
+ if(features.router) {
322
+ const routerIndexPath = path.join(targetDir, `src/router/index.${language === 'ts' ? 'ts' : 'js'}`)
323
+ if(autoRoute) {
324
+ fs.writeFileSync(
325
+ routerIndexPath,
326
+ `import { createRouter, createWebHistory } from 'vue-router'
327
+ import routes from '~pages'
328
+
329
+ routes.unshift({
330
+ path: '/',
331
+ redirect: '/home'
332
+ })
333
+
334
+ export default createRouter({
335
+ history: createWebHistory(),
336
+ routes
337
+ })
338
+ `
339
+ )
340
+ } else {
341
+ fs.writeFileSync(
342
+ routerIndexPath,
343
+ `import { createRouter, createWebHistory } from 'vue-router'
344
+
345
+ const routes = [
346
+ {
347
+ path: '/',
348
+ component: () => import('@/views/home/index.vue')
349
+ }
350
+ ]
351
+
352
+ export default createRouter({
353
+ history: createWebHistory(),
354
+ routes
355
+ })
356
+ `
357
+ )
358
+ }
359
+ }
360
+
361
+ // 1️⃣0️⃣ 安装依赖
273
362
  console.log('📦 安装依赖中...')
274
363
  execSync('npm install', { cwd: targetDir, stdio: 'inherit' })
275
- if (extraPlugins.includes('tailwind')) {
364
+ if(extraPlugins.includes('tailwind')) {
276
365
  execSync('npm install tailwindcss @tailwindcss/postcss postcss', { cwd: targetDir, stdio: 'inherit' })
277
366
  }
278
367
 
279
- // 9️⃣ 运行 dev
280
- if (runDev) {
368
+ // 1️⃣1️⃣ 运行 dev
369
+ if(runDev) {
281
370
  console.log('🚀 启动开发服务器...')
282
371
  execSync('npm run dev', { cwd: targetDir, stdio: 'inherit' })
283
372
  } else {
284
373
  console.log(`\n✅ 项目创建完成\n👉 cd ${projectName}\n👉 npm run dev\n`)
285
374
  }
286
- })()
375
+ })()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-vite-vue",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "基于Vite+Vue3创建基础项目模板",
5
5
  "main": "index.js",
6
6
  "author": "YwaiX",
@@ -9,7 +9,7 @@
9
9
 
10
10
  - ⚡ 基于 Vite + Vue 3,启动快、构建快
11
11
  - 📜 支持 JavaScript / TypeScript 自由选择
12
- - 🧭 可选集成 Vue Router
12
+ - 🧭 可选集成 Vue Router(支持动态参数路由)
13
13
  - 🗂️ 可选集成 Pinia(含持久化)
14
14
  - 📡 内置 Axios 请求方案
15
15
  - 🖥️ / 📱 支持 Element Plus / Vant
@@ -70,6 +70,11 @@ project-name
70
70
  │ ├─ types/ —— 类型声明文件
71
71
  │ ├─ utils/ —— 工具方法、请求封装
72
72
  │ ├─ views/ —— 页面级组件(路由页面)
73
+ │ │ └─ home/ —— 示例页面文件夹
74
+ │ │ ├─ index.vue —— 默认首页 /home
75
+ │ │ ├─ meta.json —— 页面 meta 信息
76
+ │ │ └─ [id]/ —— 动态参数路由示例
77
+ │ │ └─ [name].vue —— 路由 /home/:id/:name
73
78
  │ ├─ App.vue —— 根组件
74
79
  │ ├─ main.js / main.ts —— 项目启动入口
75
80
  │ └─ style.css —— 全局样式文件
@@ -125,18 +130,18 @@ npm run dev
125
130
  ## 🌐 技术栈官网链接
126
131
 
127
132
  - [Vite](https://vitejs.dev/)
128
- - [Vue 3](https://vuejs.org/)
133
+ - [Vue 3](https://vuejs.org/)
129
134
  - [JavaScript](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)
130
135
  - [TypeScript](https://www.typescriptlang.org/)
131
- - [Vue Router](https://router.vuejs.org/)
132
- - [Pinia](https://pinia.vuejs.org/)
133
- - [Axios](https://axios-http.com/)
136
+ - [Vue Router](https://router.vuejs.org/)
137
+ - [Pinia](https://pinia.vuejs.org/)
138
+ - [Axios](https://axios-http.com/)
134
139
  - [Element Plus](https://element-plus.org/)
135
140
  - [Vant](https://vant-contrib.gitee.io/vant/)
136
141
  - [VueUse](https://vueuse.org/)
137
142
  - [Lodash](https://lodash.com/)
138
143
  - [Day.js](https://day.js.org/)
139
- - [Tailwind CSS](https://tailwindcss.com/)
144
+ - [Tailwind CSS](https://tailwindcss.com/)
140
145
 
141
146
  ---
142
147
 
@@ -189,33 +194,41 @@ export default defineConfig({
189
194
 
190
195
  ---
191
196
 
192
- ### 3️⃣ 路由结构
197
+ ### 3️⃣ 路由结构(支持动态参数)
193
198
 
194
199
  文件:`src/router/index.ts` `src/router/index.js`
195
200
  ```ts
196
- import { createRouter, createWebHistory } from 'vue-router';
197
- import Home from '../views/Home.vue';
198
-
199
- const routes = [
200
- { path: '/', name: 'Home', component: Home },
201
- { path: '/about', name: 'About', component: () => import('../views/About.vue') },
202
- ];
201
+ import { createRouter, createWebHistory } from 'vue-router'
202
+ import routes from '~pages' // 自动生成的路由
203
203
 
204
204
  const router = createRouter({
205
205
  history: createWebHistory(),
206
- routes,
207
- });
206
+ routes
207
+ })
208
+
209
+ export default router
210
+ ```
208
211
 
209
- export default router;
212
+ > 🔹 页面文件夹结构示例:
213
+ ```text
214
+ src/views/home/
215
+ ├─ index.vue -> /home
216
+ └─ [id]/[name].vue -> /home/:id/:name
210
217
  ```
211
218
 
212
- > 🔹 根据实际业务新增或删除路由,并修改页面组件路径
219
+ > 🔹 获取路由参数:
220
+ ```ts
221
+ import { useRoute } from 'vue-router'
222
+ const route = useRoute()
223
+ console.log(route.params.id)
224
+ console.log(route.params.name)
225
+ ```
213
226
 
214
227
  ---
215
228
 
216
229
  ### 4️⃣ 页面内容与样式
217
230
 
218
- 文件示例:`src/views/Home.vue`
231
+ 文件示例:`src/views/home/index.vue`
219
232
  ```vue
220
233
  <template>
221
234
  <div class="home-container">
@@ -11,13 +11,13 @@
11
11
  "dependencies": {
12
12
  "less": "^4.5.1",
13
13
  "tslib": "^2.8.1",
14
- "vue": "^3.5.24"__OPTIONAL_DEP__
14
+ "vue": "^3.5.25"__OPTIONAL_DEP__
15
15
  },
16
16
  "devDependencies": {
17
- "@vitejs/plugin-vue": "^6.0.1",
18
- "vite": "npm:rolldown-vite@7.2.5"
17
+ "@vitejs/plugin-vue": "^6.0.2",
18
+ "vite": "^8.0.0-beta.13"
19
19
  },
20
20
  "overrides": {
21
- "vite": "npm:rolldown-vite@7.2.5"
21
+ "vite": "^8.0.0-beta.13"
22
22
  }
23
23
  }
@@ -9,7 +9,7 @@
9
9
 
10
10
  - ⚡ 基于 Vite + Vue 3,启动快、构建快
11
11
  - 📜 支持 JavaScript / TypeScript 自由选择
12
- - 🧭 可选集成 Vue Router
12
+ - 🧭 可选集成 Vue Router(支持动态参数路由)
13
13
  - 🗂️ 可选集成 Pinia(含持久化)
14
14
  - 📡 内置 Axios 请求方案
15
15
  - 🖥️ / 📱 支持 Element Plus / Vant
@@ -70,6 +70,11 @@ project-name
70
70
  │ ├─ types/ —— 类型声明文件
71
71
  │ ├─ utils/ —— 工具方法、请求封装
72
72
  │ ├─ views/ —— 页面级组件(路由页面)
73
+ │ │ └─ home/ —— 示例页面文件夹
74
+ │ │ ├─ index.vue —— 默认首页 /home
75
+ │ │ ├─ meta.json —— 页面 meta 信息
76
+ │ │ └─ [id]/ —— 动态参数路由示例
77
+ │ │ └─ [name].vue —— 路由 /home/:id/:name
73
78
  │ ├─ App.vue —— 根组件
74
79
  │ ├─ main.js / main.ts —— 项目启动入口
75
80
  │ └─ style.css —— 全局样式文件
@@ -125,18 +130,18 @@ npm run dev
125
130
  ## 🌐 技术栈官网链接
126
131
 
127
132
  - [Vite](https://vitejs.dev/)
128
- - [Vue 3](https://vuejs.org/)
133
+ - [Vue 3](https://vuejs.org/)
129
134
  - [JavaScript](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)
130
135
  - [TypeScript](https://www.typescriptlang.org/)
131
- - [Vue Router](https://router.vuejs.org/)
132
- - [Pinia](https://pinia.vuejs.org/)
133
- - [Axios](https://axios-http.com/)
136
+ - [Vue Router](https://router.vuejs.org/)
137
+ - [Pinia](https://pinia.vuejs.org/)
138
+ - [Axios](https://axios-http.com/)
134
139
  - [Element Plus](https://element-plus.org/)
135
140
  - [Vant](https://vant-contrib.gitee.io/vant/)
136
141
  - [VueUse](https://vueuse.org/)
137
142
  - [Lodash](https://lodash.com/)
138
143
  - [Day.js](https://day.js.org/)
139
- - [Tailwind CSS](https://tailwindcss.com/)
144
+ - [Tailwind CSS](https://tailwindcss.com/)
140
145
 
141
146
  ---
142
147
 
@@ -189,33 +194,41 @@ export default defineConfig({
189
194
 
190
195
  ---
191
196
 
192
- ### 3️⃣ 路由结构
197
+ ### 3️⃣ 路由结构(支持动态参数)
193
198
 
194
199
  文件:`src/router/index.ts` `src/router/index.js`
195
200
  ```ts
196
- import { createRouter, createWebHistory } from 'vue-router';
197
- import Home from '../views/Home.vue';
198
-
199
- const routes = [
200
- { path: '/', name: 'Home', component: Home },
201
- { path: '/about', name: 'About', component: () => import('../views/About.vue') },
202
- ];
201
+ import { createRouter, createWebHistory } from 'vue-router'
202
+ import routes from '~pages' // 自动生成的路由
203
203
 
204
204
  const router = createRouter({
205
205
  history: createWebHistory(),
206
- routes,
207
- });
206
+ routes
207
+ })
208
+
209
+ export default router
210
+ ```
208
211
 
209
- export default router;
212
+ > 🔹 页面文件夹结构示例:
213
+ ```text
214
+ src/views/home/
215
+ ├─ index.vue -> /home
216
+ └─ [id]/[name].vue -> /home/:id/:name
210
217
  ```
211
218
 
212
- > 🔹 根据实际业务新增或删除路由,并修改页面组件路径
219
+ > 🔹 获取路由参数:
220
+ ```ts
221
+ import { useRoute } from 'vue-router'
222
+ const route = useRoute()
223
+ console.log(route.params.id)
224
+ console.log(route.params.name)
225
+ ```
213
226
 
214
227
  ---
215
228
 
216
229
  ### 4️⃣ 页面内容与样式
217
230
 
218
- 文件示例:`src/views/Home.vue`
231
+ 文件示例:`src/views/home/index.vue`
219
232
  ```vue
220
233
  <template>
221
234
  <div class="home-container">
@@ -11,17 +11,17 @@
11
11
  "dependencies": {
12
12
  "less": "^4.5.1",
13
13
  "tslib": "^2.8.1",
14
- "vue": "^3.5.24"__OPTIONAL_DEP__
14
+ "vue": "^3.5.25"__OPTIONAL_DEP__
15
15
  },
16
16
  "devDependencies": {
17
- "@types/node": "^24.10.4",
18
- "@vitejs/plugin-vue": "^6.0.1",
17
+ "@types/node": "^24.11.0",
18
+ "@vitejs/plugin-vue": "^6.0.2",
19
19
  "@vue/tsconfig": "^0.8.1",
20
20
  "typescript": "~5.9.3",
21
- "vite": "npm:rolldown-vite@7.2.5",
22
- "vue-tsc": "^3.1.4"
21
+ "vite": "^8.0.0-beta.13",
22
+ "vue-tsc": "^3.1.5"
23
23
  },
24
24
  "overrides": {
25
- "vite": "npm:rolldown-vite@7.2.5"
25
+ "vite": "^8.0.0-beta.13"
26
26
  }
27
27
  }
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <router-view />
3
+ </template>
@@ -3,7 +3,7 @@ import { createRouter, createWebHistory } from 'vue-router'
3
3
  const routes = [
4
4
  {
5
5
  path: '/',
6
- component: () => import('@/views/Home.vue')
6
+ component: () => import('@/views/home/index.vue')
7
7
  }
8
8
  ]
9
9
 
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <router-view />
3
+ </template>
@@ -3,7 +3,7 @@ import { createRouter, createWebHistory } from 'vue-router'
3
3
  const routes = [
4
4
  {
5
5
  path: '/',
6
- component: () => import('@/views/Home.vue')
6
+ component: () => import('@/views/home/index.vue')
7
7
  }
8
8
  ]
9
9