ljr-cli 1.0.7 → 1.0.9
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/commands/demo1.js +12 -0
- package/bin/commands/demo2.js +60 -0
- package/bin/commands/init.js +130 -0
- package/bin/commands/sync.js +144 -0
- package/bin/index.js +19 -202
- package/bin/templates/vue2.7.16/README.md +15 -13
- package/bin/templates/vue2.7.16/public/index.html +5 -5
- package/bin/templates/vue3.5.25-2025.12.4/.vscode/settings.json +1 -0
- package/bin/templates/vue3.5.25-2025.12.4/README.md +28 -17
- package/bin/templates/vue3.5.25-2025.12.4/auto-imports.d.ts +229 -0
- package/bin/templates/vue3.5.25-2025.12.4/components.d.ts +49 -0
- package/bin/templates/vue3.5.25-2025.12.4/eslint.config.ts +1 -0
- package/bin/templates/vue3.5.25-2025.12.4/index.html +2 -2
- package/bin/templates/vue3.5.25-2025.12.4/package.json +3 -1
- package/bin/templates/vue3.5.25-2025.12.4/pnpm-lock.yaml +480 -11
- package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/login_bg.jpg +0 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/login_bg_black.jpg +0 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/assets/images/sc_login_icon.png +0 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/boot/el-icon.ts +9 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/boot/index.ts +2 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/boot/pinia.ts +8 -3
- package/bin/templates/vue3.5.25-2025.12.4/src/boot/style.ts +2 -1
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/header.ts +97 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/header.vue +37 -13
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/left-right.vue +3 -7
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/menu.ts +19 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/menu.vue +89 -5
- package/bin/templates/vue3.5.25-2025.12.4/src/components/layout/up-down.vue +24 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/components/login/change-password.vue +111 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/components/login/user-login.vue +61 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/css/base.css +204 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/css/global.css +1596 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/css/index.css +3 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/css/theme.css +61 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/device/index.ts +1 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/dialog.vue +66 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/helper.ts +90 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/index.ts +2 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/template.ts +41 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/template.vue +29 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/index.ts +31 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/layout.ts +47 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/layout.vue +51 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/notification.ts +27 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/notification.vue +29 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/permission.ts +22 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/dialogs/user-info/permission.vue +23 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/directive/rememberScrollPosition.ts +1 -1
- package/bin/templates/vue3.5.25-2025.12.4/src/enums/device.ts +42 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/enums/index.ts +2 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/enums/status.ts +23 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/role.ts +40 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/role.vue +39 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/permission/user.vue +10 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/base-info.vue +5 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/base-info2.vue +5 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/list.ts +40 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/list.vue +39 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index/template/store.vue +89 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/index.vue +7 -2
- package/bin/templates/vue3.5.25-2025.12.4/src/pages/login.vue +34 -64
- package/bin/templates/vue3.5.25-2025.12.4/src/stores/account(/351/200/211/351/241/271/345/274/217api/345/206/231/346/263/225/347/244/272/344/276/213).ts +49 -0
- package/bin/templates/vue3.5.25-2025.12.4/src/stores/account.ts +46 -28
- package/bin/templates/vue3.5.25-2025.12.4/src/stores/dd.ts +85 -29
- package/bin/templates/vue3.5.25-2025.12.4/src/stores/layout.ts +99 -21
- package/bin/templates/vue3.5.25-2025.12.4/typed-router.d.ts +90 -0
- package/bin/templates/vue3.5.25-2025.12.4/uno.config.ts +53 -0
- package/bin/templates/vue3.5.25-2025.12.4/vite.config.ts +12 -1
- package/package.json +4 -6
- package/bin/demo1.js +0 -39
- package/bin/demo2.js +0 -87
- package/bin/templates/vue3.5.25-2025.12.4/src/stores//347/273/204/345/220/210/345/274/217pinia/345/206/231/346/263/225(/344/273/245account/344/270/272/344/276/213).ts +0 -28
- /package/bin/templates/vue3.5.25-2025.12.4/{public → src/assets}/favicon.svg +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default function registerDemo1(program) {
|
|
2
|
+
program
|
|
3
|
+
.command("demo1 <name>")
|
|
4
|
+
.description("demo1演示")
|
|
5
|
+
.option("-l, --local", "从本地模板创建目录")
|
|
6
|
+
.option("-g, --git", "从git地址创建目录")
|
|
7
|
+
.action((name, options) => {
|
|
8
|
+
console.log("参数name=====>", name)
|
|
9
|
+
console.log("选项options=====>", options)
|
|
10
|
+
// 这里就是你真正要做的事情了
|
|
11
|
+
})
|
|
12
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as prompts from "@clack/prompts"
|
|
2
|
+
|
|
3
|
+
export default function registerDemo2(program, { gradientString }) {
|
|
4
|
+
program
|
|
5
|
+
.command("demo2")
|
|
6
|
+
.description("demo2演示")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
prompts.intro(gradientString("创建项目"))
|
|
9
|
+
|
|
10
|
+
const group = await prompts.group(
|
|
11
|
+
{
|
|
12
|
+
name: () =>
|
|
13
|
+
prompts.text({
|
|
14
|
+
message: "请输入项目名称:",
|
|
15
|
+
placeholder: "项目名称",
|
|
16
|
+
validate: (value) => {
|
|
17
|
+
if (!value.trim().length) {
|
|
18
|
+
return "请输入项目名称"
|
|
19
|
+
}
|
|
20
|
+
if (/[^a-z-_]+/i.test(value)) {
|
|
21
|
+
return "英文开头或下划线开头,且只能包含英文、数字、下划线或中划线"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
template: () =>
|
|
26
|
+
prompts.select({
|
|
27
|
+
message: "请选择模板:",
|
|
28
|
+
options: [
|
|
29
|
+
{ label: "vue3.x", value: "vue3.x", hint: "vue3项目" },
|
|
30
|
+
{ label: "vue2.7.16", value: "vue2.7.16", hint: "vue2的最后一个版本" },
|
|
31
|
+
],
|
|
32
|
+
}),
|
|
33
|
+
age: () => prompts.text({ message: "What is your age?" }),
|
|
34
|
+
shouldContinue: () =>
|
|
35
|
+
prompts.confirm({
|
|
36
|
+
message: "是否继续?",
|
|
37
|
+
}),
|
|
38
|
+
color: ({ results }) =>
|
|
39
|
+
prompts.multiselect({
|
|
40
|
+
message: `What is your favorite color ${results.name}?`,
|
|
41
|
+
options: [
|
|
42
|
+
{ value: "red", label: "Red" },
|
|
43
|
+
{ value: "green", label: "Green" },
|
|
44
|
+
{ value: "blue", label: "Blue" },
|
|
45
|
+
],
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
onCancel: ({ results }) => {
|
|
50
|
+
prompts.cancel("取消操作!")
|
|
51
|
+
process.exit(0)
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
console.log("group=====>", group)
|
|
57
|
+
|
|
58
|
+
prompts.outro(gradientString("项目创建完成"))
|
|
59
|
+
})
|
|
60
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { existsSync } from "node:fs"
|
|
3
|
+
import { copySync, emptyDirSync } from "fs-extra/esm"
|
|
4
|
+
import * as prompts from "@clack/prompts"
|
|
5
|
+
import download from "download-git-repo"
|
|
6
|
+
import { replaceInFile } from "replace-in-file"
|
|
7
|
+
|
|
8
|
+
export default function registerInit(program, { currentRunningDirPath, cwdPath, gradientString }) {
|
|
9
|
+
function downloadTemplate(gitUrl, projectName) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
download(gitUrl, path.resolve(cwdPath, projectName), { clone: true }, function (err) {
|
|
12
|
+
if (err) return reject(err)
|
|
13
|
+
resolve()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command("init")
|
|
20
|
+
.description("创建项目")
|
|
21
|
+
.action(async () => {
|
|
22
|
+
prompts.intro(gradientString("开始创建项目"))
|
|
23
|
+
|
|
24
|
+
const group = await prompts.group(
|
|
25
|
+
{
|
|
26
|
+
name: () =>
|
|
27
|
+
prompts.text({
|
|
28
|
+
message: "请输入项目名称:",
|
|
29
|
+
placeholder: "项目名称",
|
|
30
|
+
validate: (value) => {
|
|
31
|
+
if (!value.trim().length) return "请输入项目名称"
|
|
32
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_\-]*$/.test(value)) {
|
|
33
|
+
return "英文开头或下划线开头,且只能包含英文、数字、下划线或中划线"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
templateName: () =>
|
|
38
|
+
prompts.select({
|
|
39
|
+
message: "请选择模板:",
|
|
40
|
+
options: [
|
|
41
|
+
{ label: "vue3.5.25-2025.12.4", value: "vue3.5.25-2025.12.4" },
|
|
42
|
+
{ label: "vue2.7.16", value: "vue2.7.16" },
|
|
43
|
+
{ label: "react", value: "react" },
|
|
44
|
+
],
|
|
45
|
+
}),
|
|
46
|
+
source: () =>
|
|
47
|
+
prompts.select({
|
|
48
|
+
message: "请选择来源:",
|
|
49
|
+
options: [
|
|
50
|
+
{ label: "本地", value: "local" },
|
|
51
|
+
{ label: "git仓库", value: "git" },
|
|
52
|
+
],
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
onCancel: () => {
|
|
57
|
+
prompts.cancel("取消操作!")
|
|
58
|
+
process.exit(0)
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const s = prompts.spinner({ indicator: "timer" })
|
|
64
|
+
|
|
65
|
+
if (existsSync(group.name)) {
|
|
66
|
+
const confirm = await prompts.confirm({ message: gradientString("文件夹已存在,是否清空?", ["red", "red"]) })
|
|
67
|
+
if (confirm) emptyDirSync(group.name)
|
|
68
|
+
else {
|
|
69
|
+
prompts.cancel("取消操作!")
|
|
70
|
+
process.exit(0)
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
emptyDirSync(group.name)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
s.start("创建文件夹...")
|
|
77
|
+
s.stop("文件夹操作完成!")
|
|
78
|
+
|
|
79
|
+
s.start("写入模版中...")
|
|
80
|
+
try {
|
|
81
|
+
if (group.source === "local") {
|
|
82
|
+
const srcPath = path.join(currentRunningDirPath, "/templates/", group.templateName)
|
|
83
|
+
const destPath = `./${group.name}`
|
|
84
|
+
|
|
85
|
+
copySync(srcPath, destPath, {
|
|
86
|
+
recursive: true,
|
|
87
|
+
filter: (src) => {
|
|
88
|
+
const rel = path.relative(srcPath, src)
|
|
89
|
+
if (!rel) return true
|
|
90
|
+
const parts = rel.split(path.sep)
|
|
91
|
+
if (parts.includes("node_modules") || parts.includes("dist") || parts.includes(".eslintcache"))
|
|
92
|
+
return false
|
|
93
|
+
return true
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (group.source === "git") {
|
|
99
|
+
await downloadTemplate("direct:https://gitee.com/ljr-395181403/git-test.git#master", group.name)
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.log("error=====>", error)
|
|
103
|
+
prompts.cancel("模版写入失败!")
|
|
104
|
+
process.exit(0)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await new Promise((r) => setTimeout(r, 2000))
|
|
108
|
+
s.stop("模版写入完成!")
|
|
109
|
+
|
|
110
|
+
if (existsSync(path.join(cwdPath, group.name, "package.json"))) {
|
|
111
|
+
s.start("项目名操作...")
|
|
112
|
+
try {
|
|
113
|
+
const pkgFile = path.join(cwdPath, group.name, "package.json")
|
|
114
|
+
await replaceInFile({
|
|
115
|
+
files: pkgFile,
|
|
116
|
+
from: /("name"\s*:\s*)".*?"/,
|
|
117
|
+
to: `$1"${group.name}"`,
|
|
118
|
+
})
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error("替换 package.json name 失败:", err)
|
|
121
|
+
prompts.cancel("项目名修改失败")
|
|
122
|
+
process.exit(1)
|
|
123
|
+
}
|
|
124
|
+
await new Promise((r) => setTimeout(r, 1000))
|
|
125
|
+
s.stop("项目名操作完成!")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
prompts.outro(gradientString("项目创建完成! 🎉"))
|
|
129
|
+
})
|
|
130
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { existsSync } from "node:fs"
|
|
3
|
+
import { copySync } from "fs-extra/esm"
|
|
4
|
+
import * as prompts from "@clack/prompts"
|
|
5
|
+
|
|
6
|
+
export default function registerSync(program, { currentRunningDirPath, cwdPath, gradientString }) {
|
|
7
|
+
program
|
|
8
|
+
.command("sync")
|
|
9
|
+
.description("同步文件")
|
|
10
|
+
.action(async () => {
|
|
11
|
+
prompts.intro(gradientString("开始同步"))
|
|
12
|
+
|
|
13
|
+
const destPath = await prompts.text({
|
|
14
|
+
message: "输出的文件夹路径:",
|
|
15
|
+
placeholder: "输出的文件夹路径",
|
|
16
|
+
initialValue: "src",
|
|
17
|
+
validate: (value) => {
|
|
18
|
+
if (!value.trim().length) return "请输入输出的文件夹路径"
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
/** 选择同步的文件夹 */
|
|
23
|
+
const syncFolder = await prompts.multiselect({
|
|
24
|
+
message: "请选择需要同步的文件夹",
|
|
25
|
+
options: [
|
|
26
|
+
{ label: "css", value: "css" },
|
|
27
|
+
{ label: "less", value: "less" },
|
|
28
|
+
{ label: "utils", value: "utils" },
|
|
29
|
+
],
|
|
30
|
+
required: true,
|
|
31
|
+
initialValues: ["css", "utils"],
|
|
32
|
+
})
|
|
33
|
+
if (prompts.isCancel(syncFolder)) {
|
|
34
|
+
prompts.cancel("取消操作!")
|
|
35
|
+
process.exit(0)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 选择同步的css文件 */
|
|
39
|
+
let cssFiles = []
|
|
40
|
+
if (syncFolder.includes("css")) {
|
|
41
|
+
cssFiles = await prompts.multiselect({
|
|
42
|
+
message: `请选择需要同步的css文件${gradientString("(未选择的情况下,同步整个文件夹)", ["red", "red"])}`,
|
|
43
|
+
options: [
|
|
44
|
+
{ label: "index.css", value: "index.css" },
|
|
45
|
+
{ label: "base.css", value: "base.css" },
|
|
46
|
+
{ label: "theme.css", value: "theme.css" },
|
|
47
|
+
{ label: "global.css", value: "global.css" },
|
|
48
|
+
],
|
|
49
|
+
required: false,
|
|
50
|
+
initialValues: ["index.css", "base.css", "theme.css", "global.css"],
|
|
51
|
+
})
|
|
52
|
+
if (prompts.isCancel(syncFolder)) {
|
|
53
|
+
prompts.cancel("取消操作!")
|
|
54
|
+
process.exit(0)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 选择同步的util文件 */
|
|
59
|
+
let utilFiles = []
|
|
60
|
+
if (syncFolder.includes("utils")) {
|
|
61
|
+
utilFiles = await prompts.multiselect({
|
|
62
|
+
message: `请选择需要同步的util文件${gradientString("(未选择的情况下,同步整个文件夹)", ["red", "red"])}`,
|
|
63
|
+
options: [
|
|
64
|
+
{ label: "arr.js", value: "arr.js" },
|
|
65
|
+
{ label: "city.js", value: "city.js" },
|
|
66
|
+
{ label: "date.js", value: "date.js" },
|
|
67
|
+
{ label: "file.ts", value: "file.ts" },
|
|
68
|
+
{ label: "file.js", value: "file.js" },
|
|
69
|
+
{ label: "index.js", value: "index.js" },
|
|
70
|
+
],
|
|
71
|
+
required: false,
|
|
72
|
+
initialValues: ["arr.js", "city.js", "date.js", "file.js", "index.js"],
|
|
73
|
+
})
|
|
74
|
+
if (prompts.isCancel(syncFolder)) {
|
|
75
|
+
prompts.cancel("取消操作!")
|
|
76
|
+
process.exit(0)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// 模块路径
|
|
82
|
+
const moduleBase = path.join(currentRunningDirPath, "../node_modules/l-global")
|
|
83
|
+
// 输出路径
|
|
84
|
+
const destBase = path.join(cwdPath, destPath)
|
|
85
|
+
|
|
86
|
+
const s = prompts.spinner({ indicator: "timer" })
|
|
87
|
+
|
|
88
|
+
// 通用复制函数:若 selectedFiles 有值,则只复制这些文件(文件名包含扩展名),否则复制整个文件夹
|
|
89
|
+
const copyFolderOrFiles = (moduleBasePath, folderName, destBasePath, selectedFiles = []) => {
|
|
90
|
+
const folderSrc = path.join(moduleBasePath, folderName)
|
|
91
|
+
const folderDest = path.join(destBasePath, folderName)
|
|
92
|
+
|
|
93
|
+
// 如果选中了具体文件,逐个复制
|
|
94
|
+
if (selectedFiles && selectedFiles.length) {
|
|
95
|
+
for (const fname of selectedFiles) {
|
|
96
|
+
const srcFile = path.join(folderSrc, fname)
|
|
97
|
+
const destFile = path.join(folderDest, fname)
|
|
98
|
+
s.start(`复制 ${folderName}/${fname} ...`)
|
|
99
|
+
if (!existsSync(srcFile)) {
|
|
100
|
+
s.stop()
|
|
101
|
+
throw new Error(`未找到文件:${srcFile}`)
|
|
102
|
+
}
|
|
103
|
+
// 确保目标目录存在,copySync 会自动创建父目录
|
|
104
|
+
copySync(srcFile, destFile, { overwrite: true })
|
|
105
|
+
s.stop(`已复制:l-global/${folderName}/${fname} -> src/${folderName}/${fname}`)
|
|
106
|
+
}
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 否则复制整个文件夹
|
|
111
|
+
s.start(`复制 ${folderName} 文件夹...`)
|
|
112
|
+
if (!existsSync(folderSrc)) {
|
|
113
|
+
s.stop()
|
|
114
|
+
throw new Error(`未找到 l-global/${folderName}:${folderSrc}`)
|
|
115
|
+
}
|
|
116
|
+
copySync(folderSrc, folderDest, { recursive: true, overwrite: true })
|
|
117
|
+
s.stop(`已复制:l-global/${folderName} -> src/${folderName}`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 输出的文件夹
|
|
121
|
+
if (syncFolder.length) {
|
|
122
|
+
for (const e of syncFolder) {
|
|
123
|
+
if (e === "css") {
|
|
124
|
+
// 使用通用函数:传入 cssFiles(可能为空)
|
|
125
|
+
copyFolderOrFiles(moduleBase, "css", destBase, cssFiles)
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
if (e === "utils") {
|
|
129
|
+
// 使用通用函数:传入 utilFiles(可能为空)
|
|
130
|
+
copyFolderOrFiles(moduleBase, "utils", destBase, utilFiles)
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
// less / utils 等按整体复制
|
|
134
|
+
copyFolderOrFiles(moduleBase, e, destBase)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
prompts.cancel(`同步失败:${err}`)
|
|
139
|
+
process.exit(1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
prompts.outro(gradientString("同步完成! 🎉"))
|
|
143
|
+
})
|
|
144
|
+
}
|
package/bin/index.js
CHANGED
|
@@ -2,15 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
import { program } from "commander"
|
|
4
4
|
import gradient from "gradient-string"
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import { fileURLToPath } from "url"
|
|
9
|
-
import path from "path"
|
|
5
|
+
import { readFileSync } from "node:fs"
|
|
6
|
+
import { fileURLToPath } from "node:url"
|
|
7
|
+
import path from "node:path"
|
|
10
8
|
import { dateFormat } from "l-global/utils/date.js"
|
|
11
|
-
import download from "download-git-repo"
|
|
12
|
-
import { replaceInFile } from "replace-in-file"
|
|
13
9
|
import updateNotifier from "update-notifier"
|
|
10
|
+
import registerInit from "./commands/init.js"
|
|
11
|
+
import registerSync from "./commands/sync.js"
|
|
12
|
+
import registerDemo1 from "./commands/demo1.js"
|
|
13
|
+
import registerDemo2 from "./commands/demo2.js"
|
|
14
|
+
|
|
15
|
+
// 当前运行文件的路径
|
|
16
|
+
const currentRunningFilePath = fileURLToPath(import.meta.url)
|
|
17
|
+
// 当前运行文件的文件夹
|
|
18
|
+
const currentRunningDirPath = path.dirname(currentRunningFilePath)
|
|
19
|
+
// 当前命令行的路径
|
|
20
|
+
const cwdPath = process.cwd()
|
|
14
21
|
|
|
15
22
|
/** 渐变字符串 */
|
|
16
23
|
const gradientString = (str, gradientColor = ["#42d392", "#647eff"]) => {
|
|
@@ -27,12 +34,7 @@ program.hook("postAction", () => {
|
|
|
27
34
|
console.log(gradientString(`-------------------- 结束时间 - ${dateFormat()} --------------------`, ["red", "yellow"]))
|
|
28
35
|
})
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
// 当前运行文件的路径
|
|
32
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
33
|
-
// 当前运行文件的文件夹
|
|
34
|
-
const __dirname = path.dirname(__filename)
|
|
35
|
-
const pkg = JSON.parse(readFileSync(path.join(__dirname, "../package.json"), "utf-8"))
|
|
37
|
+
const pkg = JSON.parse(readFileSync(path.join(currentRunningDirPath, "../package.json"), "utf-8"))
|
|
36
38
|
const version = pkg.version
|
|
37
39
|
|
|
38
40
|
// const notifier = updateNotifier({ pkg })
|
|
@@ -44,196 +46,11 @@ if (notifier.update && notifier.update.latest && notifier.update.latest !== pkg.
|
|
|
44
46
|
notifier.notify()
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
// 当前命令行的路径
|
|
48
|
-
const cwdPath = process.cwd()
|
|
49
|
-
|
|
50
49
|
program.version(version, "-v, --version", "查看版本号信息")
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return reject(err)
|
|
57
|
-
}
|
|
58
|
-
resolve()
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 初始化项目
|
|
64
|
-
program
|
|
65
|
-
.command("init")
|
|
66
|
-
.description("创建项目")
|
|
67
|
-
.action(async () => {
|
|
68
|
-
prompts.intro(gradientString("开始创建项目"))
|
|
69
|
-
|
|
70
|
-
const group = await prompts.group(
|
|
71
|
-
{
|
|
72
|
-
name: () =>
|
|
73
|
-
prompts.text({
|
|
74
|
-
message: "请输入项目名称:",
|
|
75
|
-
placeholder: "项目名称",
|
|
76
|
-
validate: (value) => {
|
|
77
|
-
if (!value.trim().length) {
|
|
78
|
-
return "请输入项目名称"
|
|
79
|
-
}
|
|
80
|
-
if (/[^a-z-_]+/i.test(value)) {
|
|
81
|
-
return "英文开头或下划线开头,且只能包含英文、数字、下划线或中划线"
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
}),
|
|
85
|
-
templateName: () =>
|
|
86
|
-
prompts.select({
|
|
87
|
-
message: "请选择模板:",
|
|
88
|
-
options: [
|
|
89
|
-
{ label: "vue3.5.25-2025.12.4", value: "vue3.5.25-2025.12.4", hint: "2025.12.4创建的" },
|
|
90
|
-
{ label: "vue2.7.16", value: "vue2.7.16", hint: "vue2项目,这是vue2的最后一个版本" },
|
|
91
|
-
{ label: "react", value: "react", hint: "react项目" },
|
|
92
|
-
{ label: "qiankun", value: "qiankun", hint: "微前端-乾坤版本" },
|
|
93
|
-
{ label: "monorepo", value: "monorepo", hint: "monorepo架构-单仓库多项目" },
|
|
94
|
-
{ label: "node", value: "node", hint: "node服务" },
|
|
95
|
-
{ label: "java", value: "java", hint: "java服务" },
|
|
96
|
-
{ label: "mysql", value: "mysql", hint: "mysql数据库" },
|
|
97
|
-
{ label: "wx-miniapp", value: "wx-miniapp", hint: "微信原生小程序" },
|
|
98
|
-
{ label: "uni-app", value: "uni-app", hint: "uni-app项目" },
|
|
99
|
-
{ label: "flutter", value: "flutter", hint: "flutter项目" },
|
|
100
|
-
],
|
|
101
|
-
}),
|
|
102
|
-
source: () =>
|
|
103
|
-
prompts.select({
|
|
104
|
-
message: "请选择来源:",
|
|
105
|
-
options: [
|
|
106
|
-
{ label: "本地", value: "local", hint: "从本地模板创建" },
|
|
107
|
-
{
|
|
108
|
-
label: "git仓库",
|
|
109
|
-
value: "git",
|
|
110
|
-
hint: "从git地址创建,这里为了演示,只是随便用了个git仓库,并不是真正的模版仓库",
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
}),
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
onCancel: ({ results }) => {
|
|
117
|
-
prompts.cancel("取消操作!")
|
|
118
|
-
process.exit(0)
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
const s = prompts.spinner({ indicator: "timer" })
|
|
124
|
-
|
|
125
|
-
// 判断文件夹是否存在,存在询问是否清空
|
|
126
|
-
if (existsSync(group.name)) {
|
|
127
|
-
const confirm = await prompts.confirm({
|
|
128
|
-
message: gradientString("文件夹已存在,是否清空?", ["red", "red"]),
|
|
129
|
-
})
|
|
130
|
-
if (confirm) {
|
|
131
|
-
emptyDirSync(group.name)
|
|
132
|
-
} else {
|
|
133
|
-
prompts.cancel("取消操作!")
|
|
134
|
-
process.exit(0)
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
emptyDirSync(group.name)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
s.start("创建文件夹...")
|
|
141
|
-
s.stop("文件夹操作完成!")
|
|
142
|
-
|
|
143
|
-
s.start("写入模版中...")
|
|
144
|
-
try {
|
|
145
|
-
if (group.source === "local") {
|
|
146
|
-
// 源路径
|
|
147
|
-
const srcPath = path.join(__dirname, "/templates/", group.templateName)
|
|
148
|
-
// 目标路径
|
|
149
|
-
const destPath = `./${group.name}`
|
|
150
|
-
|
|
151
|
-
copySync(srcPath, destPath, {
|
|
152
|
-
recursive: true,
|
|
153
|
-
filter: (src) => {
|
|
154
|
-
// 相对于模板根的相对路径
|
|
155
|
-
const rel = path.relative(srcPath, src)
|
|
156
|
-
// 根目录本身允许
|
|
157
|
-
if (!rel) return true
|
|
158
|
-
const parts = rel.split(path.sep)
|
|
159
|
-
// 如果路径中包含 node_modules 或 dist 则过滤掉
|
|
160
|
-
if (parts.includes("node_modules") || parts.includes("dist") || parts.includes(".eslintcache")) {
|
|
161
|
-
return false
|
|
162
|
-
}
|
|
163
|
-
return true
|
|
164
|
-
},
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (group.source === "git") {
|
|
169
|
-
await downloadTemplate("direct:https://gitee.com/ljr-395181403/git-test.git#master", group.name)
|
|
170
|
-
}
|
|
171
|
-
} catch (error) {
|
|
172
|
-
console.log("error=====>", error)
|
|
173
|
-
prompts.cancel("模版写入失败!")
|
|
174
|
-
process.exit(0)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
await new Promise((resolve) => setTimeout(resolve, 2000)) // 为了更好的演示效果,强制等待
|
|
178
|
-
s.stop("模版写入完成!")
|
|
179
|
-
|
|
180
|
-
// 判断package.json是否存在
|
|
181
|
-
if (existsSync(path.join(cwdPath, group.name, "package.json"))) {
|
|
182
|
-
s.start("项目名操作...")
|
|
183
|
-
try {
|
|
184
|
-
const pkgFile = path.join(cwdPath, group.name, "package.json")
|
|
185
|
-
await replaceInFile({
|
|
186
|
-
files: pkgFile,
|
|
187
|
-
from: /("name"\s*:\s*)".*?"/,
|
|
188
|
-
to: `$1"${group.name}"`,
|
|
189
|
-
})
|
|
190
|
-
} catch (err) {
|
|
191
|
-
console.error("替换 package.json name 失败:", err)
|
|
192
|
-
prompts.cancel("项目名修改失败")
|
|
193
|
-
process.exit(1)
|
|
194
|
-
}
|
|
195
|
-
await new Promise((resolve) => setTimeout(resolve, 1000)) // 为了更好的演示效果,强制等待
|
|
196
|
-
s.stop("项目名操作完成!")
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
prompts.outro(gradientString("项目创建完成! 🎉"))
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
// 同步文件
|
|
203
|
-
program
|
|
204
|
-
.command("sync")
|
|
205
|
-
.description("同步文件")
|
|
206
|
-
.action(async () => {
|
|
207
|
-
prompts.intro(gradientString("开始同步"))
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
// 本程序所在包里 node_modules/l-global 的路径
|
|
211
|
-
const moduleBase = path.join(__dirname, "../node_modules/l-global")
|
|
212
|
-
const cssSrc = path.join(moduleBase, "css")
|
|
213
|
-
const utilsSrc = path.join(moduleBase, "utils")
|
|
214
|
-
// 当前命令行运行路径下的目标 src 文件夹
|
|
215
|
-
const destBase = path.join(cwdPath, "src")
|
|
216
|
-
|
|
217
|
-
// 逐项拷贝(fs-extra.copySync 会自动创建目标父目录)
|
|
218
|
-
if (existsSync(cssSrc)) {
|
|
219
|
-
copySync(cssSrc, path.join(destBase, "css"), { recursive: true, overwrite: true })
|
|
220
|
-
console.log("已复制:l-global/css -> src/css")
|
|
221
|
-
} else {
|
|
222
|
-
console.warn("未找到 l-global/css:", cssSrc)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (existsSync(utilsSrc)) {
|
|
226
|
-
copySync(utilsSrc, path.join(destBase, "utils"), { recursive: true, overwrite: true })
|
|
227
|
-
console.log("已复制:l-global/utils -> src/utils")
|
|
228
|
-
} else {
|
|
229
|
-
console.warn("未找到 l-global/utils:", utilsSrc)
|
|
230
|
-
}
|
|
231
|
-
} catch (err) {
|
|
232
|
-
console.error("同步出错:", err)
|
|
233
|
-
prompts.cancel("同步失败")
|
|
234
|
-
process.exit(1)
|
|
235
|
-
}
|
|
51
|
+
registerInit(program, { currentRunningDirPath, cwdPath, gradientString })
|
|
52
|
+
registerSync(program, { currentRunningDirPath, cwdPath, gradientString })
|
|
53
|
+
registerDemo1(program, { currentRunningDirPath, cwdPath, gradientString })
|
|
54
|
+
registerDemo2(program, { currentRunningDirPath, cwdPath, gradientString })
|
|
236
55
|
|
|
237
|
-
prompts.outro(gradientString("同步完成! 🎉"))
|
|
238
|
-
})
|
|
239
56
|
program.parse(process.argv)
|
|
@@ -44,28 +44,30 @@ pnpm install
|
|
|
44
44
|
### 项目运行
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
|
-
pnpm
|
|
47
|
+
pnpm dev || pnpm serve
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
### 项目打包
|
|
51
51
|
|
|
52
52
|
```sh
|
|
53
|
-
pnpm
|
|
53
|
+
pnpm build
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
### 检查和修复文件
|
|
57
57
|
|
|
58
58
|
```sh
|
|
59
|
-
pnpm
|
|
59
|
+
pnpm lint
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
| 类别 | 推荐命名方式 | 示例
|
|
65
|
-
| ------------------ | ----------------------------------------------- |
|
|
66
|
-
| 通用 | kebab-case | package-lock.json
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
62
|
+
## 命名规范
|
|
63
|
+
|
|
64
|
+
| 类别 | 推荐命名方式 | 示例 | 关键点/例外情况 |
|
|
65
|
+
| ------------------ | ----------------------------------------------- | -------------------------- | ---------------------- |
|
|
66
|
+
| 通用 | kebab-case | package-lock.json | 没有特别说明尽量用这个 |
|
|
67
|
+
| 路由名称 | kebab-case | user-info | 最通用、最推荐路径命名 |
|
|
68
|
+
| Vue 组件里的组件名 | kebab-case | user-info.vue | |
|
|
69
|
+
| Vue 组件里的 Props | 在声明时使用 camelCase,在模板中使用 kebab-case | | |
|
|
70
|
+
| 方法 / 函数 / 变量 | camelCase | getUserInfo | |
|
|
71
|
+
| 构造函数 / 类 | PascalCase | UserInfo | |
|
|
72
|
+
| 常量 | UPPER_SNAKE_CASE(全大写 + 下划线分隔) | const BASE_API_URL = "xxx" | |
|
|
73
|
+
| 私有属性 / 方法 | \_camelCase(下划线开头 + 小驼峰) | \_userInfo | |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="">
|
|
2
|
+
<html lang="zh">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<noscript>
|
|
12
|
-
<strong
|
|
13
|
-
|
|
14
|
-
enable it to continue
|
|
15
|
-
>
|
|
12
|
+
<strong>
|
|
13
|
+
We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please
|
|
14
|
+
enable it to continue.
|
|
15
|
+
</strong>
|
|
16
16
|
</noscript>
|
|
17
17
|
<div id="app"></div>
|
|
18
18
|
<!-- built files will be auto injected -->
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"explorer.fileNesting.enabled": true,
|
|
3
3
|
"explorer.fileNesting.patterns": {
|
|
4
|
+
"*.vue": "$(capture).ts, $(capture).*.ts, $(capture).*.js, $(capture).css, $(capture).scss, $(capture).less",
|
|
4
5
|
"tsconfig.json": "tsconfig.*.json, env.d.ts",
|
|
5
6
|
"vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*",
|
|
6
7
|
"package.json": "*.env, .env.*, env.d.ts, package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .prettier*, prettier*, .editorconfig, .gitignore, .gitattributes, index.html, .browserslistrc, babel.config.js, jsconfig.json, auto-imports.d.ts, components.d.ts, typed-router.d.ts"
|