create-vite-vue 2.0.0 → 2.1.1
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 +7 -8
- package/lib/cleanMain.js +11 -0
- package/lib/features.js +23 -6
- package/lib/package.js +22 -17
- package/lib/plugins/autoRoute.js +5 -0
- package/lib/plugins/axios.js +8 -10
- package/lib/plugins/elementPlus.js +20 -20
- package/lib/plugins/https.js +4 -0
- package/lib/plugins/index.js +15 -9
- package/lib/plugins/pinia.js +21 -24
- package/lib/plugins/router.js +21 -20
- package/lib/plugins/tailwind.js +8 -7
- package/lib/plugins/vant.js +21 -17
- package/lib/prompts.js +26 -0
- package/lib/template.js +14 -9
- package/lib/utils.js +57 -0
- package/package.json +9 -1
- package/types/global.d.ts +72 -0
- package/.vscode/settings.json +0 -22
package/bin/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'url'
|
|
|
6
6
|
|
|
7
7
|
// === 导入模块 ===
|
|
8
8
|
import { cleanMainFile } from '../lib/cleanMain.js'
|
|
9
|
-
import {
|
|
9
|
+
import { parsePlugins } from '../lib/features.js'
|
|
10
10
|
import { generatePackageJson } from '../lib/package.js'
|
|
11
11
|
import { setupPlugins } from '../lib/plugins/index.js'
|
|
12
12
|
import { askAutoRoute, askRunDev, chooseFeatures, chooseLanguage, getProjectName } from '../lib/prompts.js'
|
|
@@ -32,13 +32,12 @@ const requiredVersion = '22.19.0'
|
|
|
32
32
|
// 4. 选择功能
|
|
33
33
|
const featureList = await chooseFeatures()
|
|
34
34
|
|
|
35
|
-
// 5.
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const enableHttps = featureList.includes('https') || false
|
|
35
|
+
// 5. 解析插件
|
|
36
|
+
const plugins = parsePlugins(featureList)
|
|
37
|
+
const enableHttps = plugins.https
|
|
39
38
|
|
|
40
39
|
// 6. 询问自动路由
|
|
41
|
-
const autoRoute = await askAutoRoute(
|
|
40
|
+
const autoRoute = await askAutoRoute(plugins.router)
|
|
42
41
|
|
|
43
42
|
// 7. 询问是否运行 dev
|
|
44
43
|
const pkgManager = detectPackageManager()
|
|
@@ -55,7 +54,7 @@ const requiredVersion = '22.19.0'
|
|
|
55
54
|
await updateIndexHtml(projectName, targetDir)
|
|
56
55
|
|
|
57
56
|
// 10. 配置插件,并获取已使用的占位符
|
|
58
|
-
const unusedPlaceholders = await setupPlugins(
|
|
57
|
+
const unusedPlaceholders = await setupPlugins(plugins, {
|
|
59
58
|
language,
|
|
60
59
|
targetDir,
|
|
61
60
|
autoRoute,
|
|
@@ -67,7 +66,7 @@ const requiredVersion = '22.19.0'
|
|
|
67
66
|
await cleanMainFile(language, targetDir, unusedPlaceholders)
|
|
68
67
|
|
|
69
68
|
// 12. 生成 package.json
|
|
70
|
-
await generatePackageJson(projectName,
|
|
69
|
+
await generatePackageJson(projectName, plugins, autoRoute, enableHttps, language, targetDir, pkgManager)
|
|
71
70
|
|
|
72
71
|
// 13. 安装依赖
|
|
73
72
|
console.log('\n📦 正在安装依赖...')
|
package/lib/cleanMain.js
CHANGED
|
@@ -3,6 +3,12 @@ import { existsSync } from 'fs'
|
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
4
|
import path from 'path'
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 清理 main 文件中未使用的占位符
|
|
8
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
9
|
+
* @param {string} targetDir - 目标项目目录路径
|
|
10
|
+
* @param {UnusedPlaceholders} unusedPlaceholders - 未使用的占位符集合
|
|
11
|
+
*/
|
|
6
12
|
export async function cleanMainFile (language, targetDir, unusedPlaceholders) {
|
|
7
13
|
const mainFile = language === 'ts' ? 'main.ts' : 'main.js'
|
|
8
14
|
const mainPath = path.join(targetDir, `src/${mainFile}`)
|
|
@@ -31,6 +37,11 @@ export async function cleanMainFile (language, targetDir, unusedPlaceholders) {
|
|
|
31
37
|
console.log(' 🧹 已清理未使用的占位符')
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 转义正则表达式中的特殊字符
|
|
42
|
+
* @param {string} str - 需要转义的字符串
|
|
43
|
+
* @returns {string} 转义后的字符串
|
|
44
|
+
*/
|
|
34
45
|
function escapeRegExp (str) {
|
|
35
46
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
36
47
|
}
|
package/lib/features.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
// lib/features.js
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 解析功能列表为插件配置对象
|
|
4
|
+
* @param {string[]} featureList - 选择的功能列表,如 ['router', 'pinia']
|
|
5
|
+
* @returns {PluginsConfig} 插件配置对象
|
|
6
|
+
*/
|
|
7
|
+
export function parsePlugins (featureList) {
|
|
3
8
|
return {
|
|
9
|
+
// 核心插件
|
|
4
10
|
router: featureList.includes('router'),
|
|
5
11
|
pinia: featureList.includes('pinia'),
|
|
6
12
|
axios: featureList.includes('axios'),
|
|
7
|
-
ui: featureList.filter(v => ['element', 'vant'].includes(v))
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
// UI 插件
|
|
15
|
+
elementPlus: featureList.includes('element'),
|
|
16
|
+
vant: featureList.includes('vant'),
|
|
17
|
+
|
|
18
|
+
// 工具插件
|
|
19
|
+
vueuse: featureList.includes('vueuse'),
|
|
20
|
+
lodash: featureList.includes('lodash'),
|
|
21
|
+
dayjs: featureList.includes('dayjs'),
|
|
22
|
+
mitt: featureList.includes('mitt'),
|
|
23
|
+
|
|
24
|
+
// 样式插件
|
|
25
|
+
tailwind: featureList.includes('tailwind'),
|
|
26
|
+
|
|
27
|
+
// 开发工具
|
|
28
|
+
https: featureList.includes('https')
|
|
29
|
+
}
|
|
13
30
|
}
|
package/lib/package.js
CHANGED
|
@@ -3,7 +3,17 @@ import { existsSync } from 'fs'
|
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
4
|
import path from 'path'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* 生成 package.json 文件
|
|
8
|
+
* @param {string} projectName - 项目名称
|
|
9
|
+
* @param {PluginsConfig} plugins - 插件配置对象
|
|
10
|
+
* @param {boolean} autoRoute - 是否启用自动路由
|
|
11
|
+
* @param {boolean} enableHttps - 是否启用 HTTPS
|
|
12
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
13
|
+
* @param {string} targetDir - 目标目录
|
|
14
|
+
* @param {PackageManager} pkgManager - 包管理器类型
|
|
15
|
+
*/
|
|
16
|
+
export async function generatePackageJson (projectName, plugins, autoRoute, enableHttps, language, targetDir, pkgManager) {
|
|
7
17
|
const pkgPath = path.join(targetDir, 'package.json')
|
|
8
18
|
|
|
9
19
|
if(!existsSync(pkgPath)) {
|
|
@@ -12,33 +22,31 @@ export async function generatePackageJson (projectName, features, extraPlugins,
|
|
|
12
22
|
|
|
13
23
|
let pkgContent = await fs.readFile(pkgPath, 'utf-8')
|
|
14
24
|
|
|
15
|
-
// 收集可选依赖
|
|
16
25
|
const optionalDeps = {}
|
|
17
26
|
|
|
18
|
-
if(
|
|
19
|
-
if(
|
|
27
|
+
if(plugins.router) optionalDeps['vue-router'] = '^5.0.3'
|
|
28
|
+
if(plugins.pinia) {
|
|
20
29
|
optionalDeps['pinia'] = '^3.0.4'
|
|
21
30
|
optionalDeps['pinia-plugin-persistedstate'] = '^4.7.1'
|
|
22
31
|
}
|
|
23
|
-
if(
|
|
24
|
-
if(
|
|
32
|
+
if(plugins.axios) optionalDeps['axios'] = '^1.13.6'
|
|
33
|
+
if(plugins.elementPlus) {
|
|
25
34
|
optionalDeps['element-plus'] = '^2.13.5'
|
|
26
35
|
optionalDeps['@element-plus/icons-vue'] = '^2.3.2'
|
|
27
36
|
}
|
|
28
|
-
if(
|
|
29
|
-
if(
|
|
30
|
-
if(
|
|
31
|
-
if(
|
|
32
|
-
if(
|
|
37
|
+
if(plugins.vant) optionalDeps['vant'] = '^4.9.22'
|
|
38
|
+
if(plugins.vueuse) optionalDeps['@vueuse/core'] = '^14.2.1'
|
|
39
|
+
if(plugins.dayjs) optionalDeps['dayjs'] = '^1.11.20'
|
|
40
|
+
if(plugins.lodash) optionalDeps['lodash'] = '^4.17.23'
|
|
41
|
+
if(plugins.tailwind) {
|
|
33
42
|
optionalDeps['tailwindcss'] = '^4.2.2'
|
|
34
43
|
optionalDeps['@tailwindcss/postcss'] = '^4.2.2'
|
|
35
44
|
optionalDeps['postcss'] = '^8.5.8'
|
|
36
45
|
}
|
|
37
|
-
if(
|
|
46
|
+
if(plugins.mitt) optionalDeps['mitt'] = '^3.0.1'
|
|
38
47
|
if(enableHttps) optionalDeps['vite-plugin-mkcert'] = '^1.17.10'
|
|
39
48
|
if(autoRoute) optionalDeps['vite-plugin-pages'] = '^0.33.3'
|
|
40
49
|
|
|
41
|
-
// 构建依赖字符串
|
|
42
50
|
const depsKeys = Object.keys(optionalDeps)
|
|
43
51
|
let depsStr = ''
|
|
44
52
|
|
|
@@ -46,15 +54,12 @@ export async function generatePackageJson (projectName, features, extraPlugins,
|
|
|
46
54
|
depsStr = ',\n' + depsKeys.map(k => ` "${k}": "${optionalDeps[k]}"`).join(',\n')
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
// 替换占位符
|
|
50
57
|
pkgContent = pkgContent.replace('__PROJECT_NAME__', projectName)
|
|
51
58
|
pkgContent = pkgContent.replace('__OPTIONAL_DEP__', depsStr)
|
|
52
59
|
|
|
53
|
-
// 解析并重新格式化 JSON
|
|
54
60
|
const pkgObj = JSON.parse(pkgContent)
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
if(pkgManager === 'pnpm' && features.ui.includes('vant')) {
|
|
62
|
+
if(pkgManager === 'pnpm' && plugins.vant) {
|
|
58
63
|
pkgObj.pnpm = { overrides: { "@vant/use": "^1.0.0", "@vant/popperjs": "^1.0.0" } }
|
|
59
64
|
}
|
|
60
65
|
|
package/lib/plugins/autoRoute.js
CHANGED
|
@@ -3,6 +3,11 @@ import { existsSync } from 'fs'
|
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
4
|
import path from 'path'
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 设置自动路由(vite-plugin-pages)
|
|
8
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
9
|
+
* @param {string} targetDir - 目标目录
|
|
10
|
+
*/
|
|
6
11
|
export async function setupAutoRoute (language, targetDir) {
|
|
7
12
|
console.log(' 🚀 配置自动路由...')
|
|
8
13
|
|
package/lib/plugins/axios.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
// lib/plugins/axios.js
|
|
2
|
-
import {
|
|
3
|
-
import fs from 'fs/promises'
|
|
4
|
-
import path from 'path'
|
|
2
|
+
import { copyTemplate } from '../utils'
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 配置 Axios
|
|
6
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
7
|
+
* @param {string} targetDir - 目标目录
|
|
8
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
9
|
+
*/
|
|
6
10
|
export async function setupAxios (language, targetDir, __dirname) {
|
|
7
11
|
console.log(' 🌐 配置 Axios...')
|
|
8
12
|
|
|
9
13
|
// 复制模板
|
|
10
14
|
const axiosTemplate = language === 'ts' ? 'axios-ts' : 'axios-js'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if(!existsSync(templatePath)) {
|
|
14
|
-
throw new Error(`模板不存在: ${templatePath}`)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
await fs.cp(templatePath, targetDir, { recursive: true })
|
|
15
|
+
await copyTemplate(axiosTemplate, targetDir, __dirname)
|
|
18
16
|
console.log(' ✅ Axios 模板复制完成')
|
|
19
17
|
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
// lib/plugins/elementPlus.js
|
|
2
|
-
import {
|
|
3
|
-
import fs from 'fs/promises'
|
|
4
|
-
import path from 'path'
|
|
2
|
+
import { configurationMain } from "../utils"
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 配置 Element Plus
|
|
6
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
7
|
+
* @param {string} targetDir - 目标目录
|
|
8
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
9
|
+
*/
|
|
6
10
|
export async function setupElementPlus (language, targetDir, __dirname) {
|
|
7
11
|
console.log(' 🎨 配置 Element Plus...')
|
|
8
12
|
|
|
9
13
|
// 修改 main 文件
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'/* __ELEMENT_USE__ */',
|
|
24
|
-
`app.use(ElementPlus, { locale: zhCn })\nfor (const [key, component] of Object.entries(ElementPlusIconsVue)) {\n app.component(key, component)\n}`
|
|
25
|
-
)
|
|
26
|
-
await fs.writeFile(mainPath, content)
|
|
14
|
+
const elementPlusImport = `import ElementPlus from 'element-plus'\nimport zhCn from 'element-plus/es/locale/lang/zh-cn'\nimport 'element-plus/dist/index.css'\nimport * as ElementPlusIconsVue from '@element-plus/icons-vue'`
|
|
15
|
+
const elementPlusUse = `app.use(ElementPlus, { locale: zhCn })\nfor (const [key, component] of Object.entries(ElementPlusIconsVue)) {\n app.component(key, component)\n}`
|
|
16
|
+
let array = [
|
|
17
|
+
{
|
|
18
|
+
template: '/* __ELEMENT_IMPORT__ */',
|
|
19
|
+
content: elementPlusImport
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
template: '/* __ELEMENT_USE__ */',
|
|
23
|
+
content: elementPlusUse
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
configurationMain(language, targetDir, array)
|
|
27
27
|
console.log(' ✅ main 文件已更新')
|
|
28
28
|
}
|
package/lib/plugins/https.js
CHANGED
package/lib/plugins/index.js
CHANGED
|
@@ -8,7 +8,13 @@ import { setupRouter } from './router.js'
|
|
|
8
8
|
import { setupTailwind } from './tailwind.js'
|
|
9
9
|
import { setupVant } from './vant.js'
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* 配置所有选中的插件
|
|
13
|
+
* @param {PluginsConfig} plugins - 插件配置对象
|
|
14
|
+
* @param {PluginContext} context - 上下文对象
|
|
15
|
+
* @returns {Promise<UnusedPlaceholders>} 未使用的占位符集合
|
|
16
|
+
*/
|
|
17
|
+
export async function setupPlugins (plugins, context) {
|
|
12
18
|
const { language, targetDir, autoRoute, enableHttps, __dirname } = context
|
|
13
19
|
|
|
14
20
|
// 收集未使用的占位符
|
|
@@ -19,8 +25,8 @@ export async function setupPlugins (features, extraPlugins, context) {
|
|
|
19
25
|
|
|
20
26
|
console.log('\n🔌 配置插件...')
|
|
21
27
|
|
|
22
|
-
// Router
|
|
23
|
-
if(
|
|
28
|
+
// Router
|
|
29
|
+
if(plugins.router) {
|
|
24
30
|
await setupRouter(language, targetDir, __dirname)
|
|
25
31
|
if(autoRoute) await setupAutoRoute(language, targetDir)
|
|
26
32
|
} else {
|
|
@@ -29,7 +35,7 @@ export async function setupPlugins (features, extraPlugins, context) {
|
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
// Pinia
|
|
32
|
-
if(
|
|
38
|
+
if(plugins.pinia) {
|
|
33
39
|
await setupPinia(language, targetDir, __dirname)
|
|
34
40
|
} else {
|
|
35
41
|
unusedPlaceholders.import.push('/* __PINIA_IMPORT__ */')
|
|
@@ -37,7 +43,7 @@ export async function setupPlugins (features, extraPlugins, context) {
|
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
// Element Plus
|
|
40
|
-
if(
|
|
46
|
+
if(plugins.elementPlus) {
|
|
41
47
|
await setupElementPlus(language, targetDir, __dirname)
|
|
42
48
|
} else {
|
|
43
49
|
unusedPlaceholders.import.push('/* __ELEMENT_IMPORT__ */')
|
|
@@ -45,7 +51,7 @@ export async function setupPlugins (features, extraPlugins, context) {
|
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
// Vant
|
|
48
|
-
if(
|
|
54
|
+
if(plugins.vant) {
|
|
49
55
|
await setupVant(language, targetDir, __dirname)
|
|
50
56
|
} else {
|
|
51
57
|
unusedPlaceholders.import.push('/* __VANT_IMPORT__ */')
|
|
@@ -53,17 +59,17 @@ export async function setupPlugins (features, extraPlugins, context) {
|
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
// Axios
|
|
56
|
-
if(
|
|
62
|
+
if(plugins.axios) {
|
|
57
63
|
await setupAxios(language, targetDir, __dirname)
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
// Tailwind
|
|
61
|
-
if(
|
|
67
|
+
if(plugins.tailwind) {
|
|
62
68
|
await setupTailwind(language, targetDir, __dirname)
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
// HTTPS
|
|
66
|
-
if(
|
|
72
|
+
if(plugins.https) {
|
|
67
73
|
await setupHttps(targetDir)
|
|
68
74
|
}
|
|
69
75
|
|
package/lib/plugins/pinia.js
CHANGED
|
@@ -1,36 +1,33 @@
|
|
|
1
1
|
// lib/plugins/pinia.js
|
|
2
|
-
import {
|
|
3
|
-
import fs from 'fs/promises'
|
|
4
|
-
import path from 'path'
|
|
2
|
+
import { configurationMain } from "../utils"
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 配置 Pinia
|
|
6
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
7
|
+
* @param {string} targetDir - 目标目录
|
|
8
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
9
|
+
*/
|
|
6
10
|
export async function setupPinia (language, targetDir, __dirname) {
|
|
7
11
|
console.log(' 📦 配置 Pinia...')
|
|
8
12
|
|
|
9
13
|
// 复制模板
|
|
10
14
|
const piniaTemplate = language === 'ts' ? 'pinia-ts' : 'pinia-js'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if(!existsSync(templatePath)) {
|
|
14
|
-
throw new Error(`模板不存在: ${templatePath}`)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
await fs.cp(templatePath, targetDir, { recursive: true })
|
|
15
|
+
await copyTemplate(piniaTemplate, targetDir, __dirname)
|
|
18
16
|
console.log(' ✅ Pinia 模板复制完成')
|
|
19
17
|
|
|
20
18
|
// 修改 main 文件
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
await fs.writeFile(mainPath, content)
|
|
19
|
+
const piniaImport = `import { createPinia } from 'pinia'\nimport persistedstate from 'pinia-plugin-persistedstate'`
|
|
20
|
+
const piniaUse = 'app.use(createPinia().use(persistedstate))'
|
|
21
|
+
let array = [
|
|
22
|
+
{
|
|
23
|
+
template: '/* __PINIA_IMPORT__ */',
|
|
24
|
+
content: piniaImport
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
template: '/* __PINIA_USE__ */',
|
|
28
|
+
content: piniaUse
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
configurationMain(language, targetDir, array)
|
|
35
32
|
console.log(' ✅ main 文件已更新')
|
|
36
33
|
}
|
package/lib/plugins/router.js
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
// lib/plugins/router.js
|
|
2
|
-
import {
|
|
3
|
-
import fs from 'fs/promises'
|
|
4
|
-
import path from 'path'
|
|
2
|
+
import { configurationMain, copyTemplate } from '../utils'
|
|
5
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 配置 Vue Router
|
|
6
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
7
|
+
* @param {string} targetDir - 目标目录
|
|
8
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
9
|
+
*/
|
|
6
10
|
export async function setupRouter (language, targetDir, __dirname) {
|
|
7
11
|
console.log(' 🛤️ 配置 Router...')
|
|
8
12
|
|
|
9
13
|
// 复制模板
|
|
10
14
|
const routerTemplate = language === 'ts' ? 'router-ts' : 'router-js'
|
|
11
|
-
|
|
12
|
-
if(!existsSync(templatePath)) {
|
|
13
|
-
throw new Error(`模板不存在: ${templatePath}`)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
await fs.cp(templatePath, targetDir, { recursive: true })
|
|
15
|
+
await copyTemplate(routerTemplate, targetDir, __dirname)
|
|
17
16
|
console.log(' ✅ Router 模板复制完成')
|
|
18
17
|
|
|
19
18
|
// 修改 main 文件
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
const routerImport = "import router from './router'"
|
|
20
|
+
const routerUse = 'app.use(router)'
|
|
21
|
+
let array = [
|
|
22
|
+
{
|
|
23
|
+
template: '/* __ROUTER_IMPORT__ */',
|
|
24
|
+
content: routerImport
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
template: '/* __ROUTER_USE__ */',
|
|
28
|
+
content: routerUse
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
configurationMain(language, targetDir, array)
|
|
31
32
|
console.log(' ✅ main 文件已更新')
|
|
32
33
|
}
|
package/lib/plugins/tailwind.js
CHANGED
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
import { existsSync } from 'fs'
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
4
|
import path from 'path'
|
|
5
|
+
import { copyTemplate } from '../utils'
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 配置 Tailwind CSS
|
|
9
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
10
|
+
* @param {string} targetDir - 目标目录
|
|
11
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
12
|
+
*/
|
|
6
13
|
export async function setupTailwind (language, targetDir, __dirname) {
|
|
7
14
|
console.log(' 🎨 配置 Tailwind CSS...')
|
|
8
15
|
|
|
9
16
|
// 复制模板
|
|
10
17
|
const tailwindTemplate = language === 'ts' ? 'tailwind-ts' : 'tailwind-js'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if(!existsSync(templatePath)) {
|
|
14
|
-
throw new Error(`模板不存在: ${templatePath}`)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
await fs.cp(templatePath, targetDir, { recursive: true })
|
|
18
|
+
await copyTemplate(tailwindTemplate, targetDir, __dirname)
|
|
18
19
|
console.log(' ✅ Tailwind 模板复制完成')
|
|
19
20
|
|
|
20
21
|
// 更新 style.css
|
package/lib/plugins/vant.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
// lib/plugins/vant.js
|
|
2
|
-
import {
|
|
3
|
-
import fs from 'fs/promises'
|
|
4
|
-
import path from 'path'
|
|
2
|
+
import { configurationMain } from "../utils"
|
|
5
3
|
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 配置 Vant
|
|
7
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
8
|
+
* @param {string} targetDir - 目标目录
|
|
9
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
10
|
+
*/
|
|
6
11
|
export async function setupVant (language, targetDir, __dirname) {
|
|
7
12
|
console.log(' 📱 配置 Vant...')
|
|
8
13
|
|
|
9
14
|
// 修改 main 文件
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
await fs.writeFile(mainPath, content)
|
|
15
|
+
const vantImport = `import Vant from 'vant'\nimport 'vant/lib/index.css'`
|
|
16
|
+
const vantUSE = 'app.use(Vant)'
|
|
17
|
+
let array = [
|
|
18
|
+
{
|
|
19
|
+
template: '/* __VANT_IMPORT__ */',
|
|
20
|
+
content: vantImport
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
template: '/* __VANT_USE__ */',
|
|
24
|
+
content: vantUSE
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
configurationMain(language, targetDir, array)
|
|
24
28
|
console.log(' ✅ main 文件已更新')
|
|
25
29
|
}
|
package/lib/prompts.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
// lib/prompts.js
|
|
2
2
|
import prompts from 'prompts'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 获取项目名称(交互式输入)
|
|
6
|
+
* @param {Object} fs - fs 模块
|
|
7
|
+
* @param {Function} fs.existsSync - 检查文件是否存在
|
|
8
|
+
* @param {Object} path - path 模块
|
|
9
|
+
* @param {Function} path.resolve - 解析路径
|
|
10
|
+
* @returns {Promise<string>} 项目名称
|
|
11
|
+
*/
|
|
4
12
|
export async function getProjectName (fs, path) {
|
|
5
13
|
while(true) {
|
|
6
14
|
const res = await prompts({
|
|
@@ -20,6 +28,10 @@ export async function getProjectName (fs, path) {
|
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 选择项目语言(交互式选择)
|
|
33
|
+
* @returns {Promise<'ts' | 'js'>} 选择的语言
|
|
34
|
+
*/
|
|
23
35
|
export async function chooseLanguage () {
|
|
24
36
|
const { language } = await prompts({
|
|
25
37
|
type: 'select',
|
|
@@ -33,6 +45,10 @@ export async function chooseLanguage () {
|
|
|
33
45
|
return language
|
|
34
46
|
}
|
|
35
47
|
|
|
48
|
+
/**
|
|
49
|
+
* 选择功能特性(交互式多选)
|
|
50
|
+
* @returns {Promise<string[]>} 选择的功能列表
|
|
51
|
+
*/
|
|
36
52
|
export async function chooseFeatures () {
|
|
37
53
|
const { featureList } = await prompts({
|
|
38
54
|
type: 'multiselect',
|
|
@@ -56,6 +72,11 @@ export async function chooseFeatures () {
|
|
|
56
72
|
return featureList || []
|
|
57
73
|
}
|
|
58
74
|
|
|
75
|
+
/**
|
|
76
|
+
* 询问是否开启自动路由
|
|
77
|
+
* @param {boolean} routerEnabled - 是否已启用 Router
|
|
78
|
+
* @returns {Promise<boolean>} 是否开启自动路由
|
|
79
|
+
*/
|
|
59
80
|
export async function askAutoRoute (routerEnabled) {
|
|
60
81
|
if(!routerEnabled) return false
|
|
61
82
|
const { enableAutoRoute } = await prompts({
|
|
@@ -69,6 +90,11 @@ export async function askAutoRoute (routerEnabled) {
|
|
|
69
90
|
return enableAutoRoute
|
|
70
91
|
}
|
|
71
92
|
|
|
93
|
+
/**
|
|
94
|
+
* 询问是否立即运行开发服务器
|
|
95
|
+
* @param {string} devCommand - 开发服务器命令
|
|
96
|
+
* @returns {Promise<boolean>} 是否立即运行
|
|
97
|
+
*/
|
|
72
98
|
export async function askRunDev (devCommand) {
|
|
73
99
|
const { runDev } = await prompts({
|
|
74
100
|
type: 'select',
|
package/lib/template.js
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import { existsSync } from 'fs'
|
|
3
3
|
import fs from 'fs/promises'
|
|
4
4
|
import path from 'path'
|
|
5
|
-
|
|
5
|
+
import { copyTemplate } from './utils'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 复制基础模板到目标目录
|
|
9
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
10
|
+
* @param {string} targetDir - 目标目录
|
|
11
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
12
|
+
*/
|
|
6
13
|
export async function copyBaseTemplate (language, targetDir, __dirname) {
|
|
7
14
|
const baseTemplate = language === 'ts' ? 'base-ts' : 'base-js'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if(!existsSync(templatePath)) {
|
|
11
|
-
throw new Error(`基础模板不存在: ${templatePath}`)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// 复制整个模板目录
|
|
15
|
-
await fs.cp(templatePath, targetDir, { recursive: true })
|
|
15
|
+
await copyTemplate(baseTemplate, targetDir, __dirname)
|
|
16
16
|
|
|
17
17
|
// 重命名 main 文件(去掉 .tpl 后缀)
|
|
18
18
|
const mainTplPath = path.join(targetDir, `src/main.${language === 'ts' ? 'ts' : 'js'}.tpl`)
|
|
@@ -33,6 +33,11 @@ export async function copyBaseTemplate (language, targetDir, __dirname) {
|
|
|
33
33
|
console.log(' ✅ 基础模板复制完成')
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 更新 index.html 中的标题
|
|
38
|
+
* @param {string} projectName - 项目名称
|
|
39
|
+
* @param {string} targetDir - 目标目录
|
|
40
|
+
*/
|
|
36
41
|
export async function updateIndexHtml (projectName, targetDir) {
|
|
37
42
|
const indexPath = path.join(targetDir, 'index.html')
|
|
38
43
|
if(!existsSync(indexPath)) return
|
package/lib/utils.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// lib/utils.js
|
|
2
2
|
import { execSync } from 'child_process'
|
|
3
3
|
import fs from 'fs'
|
|
4
|
+
import fsPromise from 'fs/promises'
|
|
5
|
+
import path from 'path'
|
|
4
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 检查 Node.js 版本是否符合要求
|
|
9
|
+
* @param {string} requiredVersion - 要求的版本号,如 "16.0.0"
|
|
10
|
+
*/
|
|
5
11
|
export function checkNodeVersion (requiredVersion) {
|
|
6
12
|
const currentVersion = process.version.replace('v', '')
|
|
7
13
|
if(compareVersion(currentVersion, requiredVersion) < 0) {
|
|
@@ -13,6 +19,12 @@ export function checkNodeVersion (requiredVersion) {
|
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* 比较两个版本号
|
|
24
|
+
* @param {string} v1 - 版本号1
|
|
25
|
+
* @param {string} v2 - 版本号2
|
|
26
|
+
* @returns {-1 | 0 | 1} 1: v1 > v2, -1: v1 < v2, 0: 相等
|
|
27
|
+
*/
|
|
16
28
|
export function compareVersion (v1, v2) {
|
|
17
29
|
const a = v1.split('.').map(Number)
|
|
18
30
|
const b = v2.split('.').map(Number)
|
|
@@ -25,6 +37,10 @@ export function compareVersion (v1, v2) {
|
|
|
25
37
|
return 0
|
|
26
38
|
}
|
|
27
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 检测使用的包管理器
|
|
42
|
+
* @returns {PackageManager} 包管理器类型 ('npm' 或 'pnpm')
|
|
43
|
+
*/
|
|
28
44
|
export function detectPackageManager () {
|
|
29
45
|
const userAgent = process.env.npm_config_user_agent || ''
|
|
30
46
|
if(userAgent.startsWith('pnpm')) return 'pnpm'
|
|
@@ -33,6 +49,47 @@ export function detectPackageManager () {
|
|
|
33
49
|
return 'npm'
|
|
34
50
|
}
|
|
35
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 执行命令
|
|
54
|
+
* @param {string} cmd - 要执行的命令
|
|
55
|
+
* @param {string} [cwd=process.cwd()] - 工作目录
|
|
56
|
+
*/
|
|
36
57
|
export function runCmd (cmd, cwd = process.cwd()) {
|
|
37
58
|
execSync(cmd, { cwd, stdio: 'inherit' })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 复制模板目录到目标位置
|
|
63
|
+
* @param {string} templateName - 模板名称
|
|
64
|
+
* @param {string} targetDir - 目标目录
|
|
65
|
+
* @param {string} __dirname - 当前模块目录路径
|
|
66
|
+
*/
|
|
67
|
+
export async function copyTemplate (templateName, targetDir, __dirname) {
|
|
68
|
+
const templatePath = path.resolve(__dirname, `../template/${templateName}`)
|
|
69
|
+
if(!existsSync(templatePath)) {
|
|
70
|
+
throw new Error(`模板不存在: ${templatePath}`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
await fsPromise.cp(templatePath, targetDir, { recursive: true })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 配置 main 文件(替换模板占位符)
|
|
78
|
+
* @param {'ts' | 'js'} language - 项目语言
|
|
79
|
+
* @param {string} targetDir - 目标目录
|
|
80
|
+
* @param {ConfigurationItem[]} configuration - 配置项数组
|
|
81
|
+
*/
|
|
82
|
+
export async function configurationMain (language, targetDir, configuration) {
|
|
83
|
+
const mainFile = language === 'ts' ? 'main.ts' : 'main.js'
|
|
84
|
+
const mainPath = path.join(targetDir, `src/${mainFile}`)
|
|
85
|
+
|
|
86
|
+
if(!existsSync(mainPath)) {
|
|
87
|
+
throw new Error(`main 文件不存在: ${mainPath}`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let content = await fsPromise.readFile(mainPath, 'utf-8')
|
|
91
|
+
for(const item of configuration) {
|
|
92
|
+
content = content.replace(item.template, item.content)
|
|
93
|
+
}
|
|
94
|
+
await fsPromise.writeFile(mainPath, content)
|
|
38
95
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-vite-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "基于Vite+Vue3创建基础项目模板",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "YwaiX",
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
"pinia",
|
|
23
23
|
"axios"
|
|
24
24
|
],
|
|
25
|
+
"files": [
|
|
26
|
+
"bin/",
|
|
27
|
+
"lib/",
|
|
28
|
+
"template/",
|
|
29
|
+
"types/",
|
|
30
|
+
"package.json",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
25
33
|
"dependencies": {
|
|
26
34
|
"prompts": "^2.4.2"
|
|
27
35
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// types/global.d.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 插件配置对象
|
|
5
|
+
*/
|
|
6
|
+
interface PluginsConfig {
|
|
7
|
+
router: boolean
|
|
8
|
+
pinia: boolean
|
|
9
|
+
axios: boolean
|
|
10
|
+
elementPlus: boolean
|
|
11
|
+
vant: boolean
|
|
12
|
+
vueuse: boolean
|
|
13
|
+
lodash: boolean
|
|
14
|
+
dayjs: boolean
|
|
15
|
+
mitt: boolean
|
|
16
|
+
tailwind: boolean
|
|
17
|
+
https: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 未使用的占位符集合
|
|
22
|
+
*/
|
|
23
|
+
interface UnusedPlaceholders {
|
|
24
|
+
import: string[]
|
|
25
|
+
use: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 插件上下文对象
|
|
30
|
+
*/
|
|
31
|
+
interface PluginContext {
|
|
32
|
+
language: 'ts' | 'js'
|
|
33
|
+
targetDir: string
|
|
34
|
+
autoRoute: boolean
|
|
35
|
+
enableHttps: boolean
|
|
36
|
+
__dirname: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* main 文件配置项
|
|
41
|
+
*/
|
|
42
|
+
interface ConfigurationItem {
|
|
43
|
+
template: string
|
|
44
|
+
content: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 包管理器类型
|
|
49
|
+
*/
|
|
50
|
+
type PackageManager = 'npm' | 'pnpm'
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 可选依赖版本映射
|
|
54
|
+
*/
|
|
55
|
+
interface OptionalDeps {
|
|
56
|
+
'vue-router'?: string
|
|
57
|
+
'pinia'?: string
|
|
58
|
+
'pinia-plugin-persistedstate'?: string
|
|
59
|
+
'axios'?: string
|
|
60
|
+
'element-plus'?: string
|
|
61
|
+
'@element-plus/icons-vue'?: string
|
|
62
|
+
'vant'?: string
|
|
63
|
+
'@vueuse/core'?: string
|
|
64
|
+
'dayjs'?: string
|
|
65
|
+
'lodash'?: string
|
|
66
|
+
'tailwindcss'?: string
|
|
67
|
+
'@tailwindcss/postcss'?: string
|
|
68
|
+
'postcss'?: string
|
|
69
|
+
'mitt'?: string
|
|
70
|
+
'vite-plugin-mkcert'?: string
|
|
71
|
+
'vite-plugin-pages'?: string
|
|
72
|
+
}
|
package/.vscode/settings.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"workbench.colorCustomizations": {
|
|
3
|
-
"activityBar.activeBackground": "#65c89b",
|
|
4
|
-
"activityBar.background": "#65c89b",
|
|
5
|
-
"activityBar.foreground": "#15202b",
|
|
6
|
-
"activityBar.inactiveForeground": "#15202b99",
|
|
7
|
-
"activityBarBadge.background": "#945bc4",
|
|
8
|
-
"activityBarBadge.foreground": "#e7e7e7",
|
|
9
|
-
"commandCenter.border": "#15202b99",
|
|
10
|
-
"sash.hoverBorder": "#65c89b",
|
|
11
|
-
"statusBar.background": "#42b883",
|
|
12
|
-
"statusBar.foreground": "#15202b",
|
|
13
|
-
"statusBarItem.hoverBackground": "#359268",
|
|
14
|
-
"statusBarItem.remoteBackground": "#42b883",
|
|
15
|
-
"statusBarItem.remoteForeground": "#15202b",
|
|
16
|
-
"titleBar.activeBackground": "#42b883",
|
|
17
|
-
"titleBar.activeForeground": "#15202b",
|
|
18
|
-
"titleBar.inactiveBackground": "#42b88399",
|
|
19
|
-
"titleBar.inactiveForeground": "#15202b99"
|
|
20
|
-
},
|
|
21
|
-
"peacock.color": "#42b883"
|
|
22
|
-
}
|