create-unibest 3.3.0 → 4.0.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/README.md +60 -44
- package/bin/index.js +0 -1
- package/dist/index.js +598 -121
- package/package.json +11 -11
- package/dist/index.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,63 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
# create-unibest
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<a href="https://www.npmjs.com/package/create-unibest"><img src="https://img.shields.io/npm/dm/create-unibest?colorA=363a4f&colorB=f5a97f&style=for-the-badge"></a>
|
|
5
|
-
<a href="https://www.npmjs.com/package/create-unibest"><img src="https://img.shields.io/npm/v/create-unibest?colorA=363a4f&colorB=a6da95&style=for-the-badge"></a>
|
|
6
|
-
</p>
|
|
3
|
+
跨平台 uniapp 项目脚手架工具。
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
<sub>>_ Easy to use create unibest</sub>
|
|
10
|
-
</h2>
|
|
5
|
+
## 功能特性
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
- 🚀 **快速创建** - 通过命令行快速生成 unibest 项目
|
|
8
|
+
- 🎯 **灵活配置** - 支持选择平台、UI库、Feature
|
|
9
|
+
- 🔧 **Feature 注入** - 创建后可动态添加 i18n、login 等功能
|
|
10
|
+
- 📦 **多平台支持** - H5、小程序、App 一键生成
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
## 使用方式
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
### 安装
|
|
17
15
|
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
pnpm create unibest -v # 查看版本信息
|
|
22
|
-
pnpm create unibest -h # 查看帮助信息
|
|
23
|
-
```
|
|
16
|
+
```bash
|
|
17
|
+
# 全局安装(可选)
|
|
18
|
+
npm i -g create-unibest
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
# 或直接使用
|
|
21
|
+
pnpm create unibest
|
|
22
|
+
```
|
|
26
23
|
|
|
27
|
-
|
|
24
|
+
### 创建项目
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
```bash
|
|
27
|
+
# 交互式创建
|
|
28
|
+
pnpm create unibest my-project
|
|
29
|
+
|
|
30
|
+
# 命令行参数创建
|
|
31
|
+
pnpm create unibest my-project \
|
|
32
|
+
--platform h5,mp-weixin \
|
|
33
|
+
--ui none \
|
|
34
|
+
--i18n \
|
|
35
|
+
--login
|
|
36
|
+
```
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
### 添加 Feature
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
cd my-project
|
|
42
|
+
|
|
43
|
+
# 添加多语言
|
|
44
|
+
pnpm create unibest add i18n
|
|
41
45
|
|
|
42
|
-
#
|
|
43
|
-
pnpm create unibest
|
|
46
|
+
# 添加登录策略
|
|
47
|
+
pnpm create unibest add login
|
|
44
48
|
|
|
45
|
-
#
|
|
46
|
-
pnpm create unibest
|
|
49
|
+
# 强制重新注入(覆盖已有配置)
|
|
50
|
+
pnpm create unibest add i18n --force
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
## 参数说明
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
npm i -g create-unibest # 全局安装,得到 best 命令
|
|
53
|
-
npm update -g create-unibest # 更新 create-unibest 包
|
|
54
|
-
```
|
|
55
|
+
### 创建项目参数
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
| 参数 | 说明 |
|
|
58
|
+
|------|------|
|
|
59
|
+
| `-p, --platform` | 平台类型,支持 `h5`, `mp-weixin`, `app`, `mp-alipay`, `mp-toutiao` |
|
|
60
|
+
| `-u, --ui` | UI 库,支持 `none`, `wot-ui`, `uview-pro`, `sard-uniapp`, `uv-ui`, `uview-plus` |
|
|
61
|
+
| `-l, --login` | 启用登录策略 |
|
|
62
|
+
| `-i, --i18n` | 启用多语言 |
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
### 添加 Feature 参数
|
|
65
|
+
|
|
66
|
+
| 参数 | 说明 |
|
|
67
|
+
|------|------|
|
|
68
|
+
| `--path` | 项目路径,默认当前目录 |
|
|
69
|
+
| `--force` | 强制重新注入 Feature |
|
|
70
|
+
|
|
71
|
+
## 与 unibest 模板版本对应关系
|
|
72
|
+
|
|
73
|
+
| create-unibest 版本 | unibest 模板版本 |
|
|
74
|
+
|---------------------|------------------|
|
|
75
|
+
| 4.0.0 | 4.3.0+ |
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
package/bin/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,11 +1,258 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
4
|
+
import process6 from "process";
|
|
5
|
+
import { green as green6, yellow as yellow5 } from "kolorist";
|
|
5
6
|
import minimist from "minimist";
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
|
|
8
|
+
// package.json
|
|
9
|
+
var version = "4.0.1";
|
|
10
|
+
var package_default = {
|
|
11
|
+
name: "create-unibest",
|
|
12
|
+
type: "module",
|
|
13
|
+
version,
|
|
14
|
+
packageManager: "pnpm@10.10.0",
|
|
15
|
+
description: "\u5FEB\u901F\u521B\u5EFA unibest \u9879\u76EE\u7684\u811A\u624B\u67B6\u5DE5\u5177",
|
|
16
|
+
author: "feige996",
|
|
17
|
+
license: "MIT",
|
|
18
|
+
homepage: "https://unibest.tech",
|
|
19
|
+
bin: {
|
|
20
|
+
best: "bin/index.js",
|
|
21
|
+
"create-unibest": "bin/index.js",
|
|
22
|
+
unibest: "bin/index.js"
|
|
23
|
+
},
|
|
24
|
+
files: [
|
|
25
|
+
"bin",
|
|
26
|
+
"dist",
|
|
27
|
+
"features"
|
|
28
|
+
],
|
|
29
|
+
scripts: {
|
|
30
|
+
dev: "cross-env NODE_ENV=development tsup --watch",
|
|
31
|
+
build: "cross-env NODE_ENV=production tsup",
|
|
32
|
+
prepare: "pnpm build",
|
|
33
|
+
start: "cross-env NODE_ENV=development node bin/index.js"
|
|
34
|
+
},
|
|
35
|
+
dependencies: {
|
|
36
|
+
"@clack/prompts": "^0.11.0",
|
|
37
|
+
dayjs: "^1.11.18",
|
|
38
|
+
ejs: "^3.1.10",
|
|
39
|
+
"fs-extra": "^11.3.0",
|
|
40
|
+
kolorist: "^1.8.0",
|
|
41
|
+
minimist: "^1.2.8",
|
|
42
|
+
"node-fetch": "^3.3.2"
|
|
43
|
+
},
|
|
44
|
+
devDependencies: {
|
|
45
|
+
"@types/ejs": "^3.1.5",
|
|
46
|
+
"@types/fs-extra": "^11.0.4",
|
|
47
|
+
"@types/minimist": "^1.2.5",
|
|
48
|
+
"@types/node": "^24.5.0",
|
|
49
|
+
"cross-env": "^7.0.3",
|
|
50
|
+
tsup: "^8.5.0",
|
|
51
|
+
typescript: "^5.9.0"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/commands/add.ts
|
|
56
|
+
import fs4 from "fs";
|
|
57
|
+
import path3 from "path";
|
|
58
|
+
import process2 from "process";
|
|
59
|
+
import { cancel, intro, isCancel, log, multiselect } from "@clack/prompts";
|
|
60
|
+
import { bold as bold2, green as green2 } from "kolorist";
|
|
61
|
+
|
|
62
|
+
// src/features/interface.ts
|
|
63
|
+
var AVAILABLE_FEATURES = [
|
|
64
|
+
{
|
|
65
|
+
name: "i18n",
|
|
66
|
+
description: "\u591A\u8BED\u8A00\u652F\u6301",
|
|
67
|
+
dependencies: {
|
|
68
|
+
"vue-i18n": "^9.0.0",
|
|
69
|
+
"dayjs": "^1.11.0"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "login",
|
|
74
|
+
description: "\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09",
|
|
75
|
+
dependencies: {}
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
function getFeatureByName(name) {
|
|
79
|
+
return AVAILABLE_FEATURES.find((f) => f.name === name);
|
|
80
|
+
}
|
|
81
|
+
function getSelectedFeatures(options) {
|
|
82
|
+
const features = [];
|
|
83
|
+
if (options.i18n) {
|
|
84
|
+
const feature = getFeatureByName("i18n");
|
|
85
|
+
if (feature) features.push(feature);
|
|
86
|
+
}
|
|
87
|
+
if (options.loginStrategy) {
|
|
88
|
+
const feature = getFeatureByName("login");
|
|
89
|
+
if (feature) features.push(feature);
|
|
90
|
+
}
|
|
91
|
+
return features;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/features/loader.ts
|
|
95
|
+
import fs from "fs";
|
|
96
|
+
import path from "path";
|
|
97
|
+
import { fileURLToPath } from "url";
|
|
98
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
99
|
+
var __dirname = path.dirname(__filename);
|
|
100
|
+
var FEATURES_DIR = path.resolve(__dirname, "../../features");
|
|
101
|
+
async function loadFeatureHooks(featureName) {
|
|
102
|
+
const hooksPath = path.join(FEATURES_DIR, featureName, "hooks.ts");
|
|
103
|
+
if (!fs.existsSync(hooksPath)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const module = await import(hooksPath);
|
|
107
|
+
return module;
|
|
108
|
+
}
|
|
109
|
+
function getAvailableFeatureNames() {
|
|
110
|
+
if (!fs.existsSync(FEATURES_DIR)) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const entries = fs.readdirSync(FEATURES_DIR, { withFileTypes: true });
|
|
114
|
+
return entries.filter((e) => e.isDirectory() && fs.existsSync(path.join(FEATURES_DIR, e.name, "files"))).map((e) => e.name);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/utils/injector.ts
|
|
118
|
+
import fs2 from "fs";
|
|
119
|
+
import path2 from "path";
|
|
120
|
+
import { dirname } from "path";
|
|
121
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
122
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
123
|
+
var __dirname2 = dirname(__filename2);
|
|
124
|
+
var FEATURES_PATH = path2.join(__dirname2, "..", "..", "..", "features");
|
|
125
|
+
var FeatureInjector = class {
|
|
126
|
+
constructor(projectPath) {
|
|
127
|
+
this.projectPath = projectPath;
|
|
128
|
+
}
|
|
129
|
+
injectFile(targetPath, featureCode, placeholder) {
|
|
130
|
+
const fullPath = path2.join(this.projectPath, targetPath);
|
|
131
|
+
if (!fs2.existsSync(fullPath)) {
|
|
132
|
+
return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` };
|
|
133
|
+
}
|
|
134
|
+
const content = fs2.readFileSync(fullPath, "utf-8");
|
|
135
|
+
if (!content.includes(placeholder)) {
|
|
136
|
+
return { success: false, message: `\u5360\u4F4D\u7B26\u4E0D\u5B58\u5728: ${placeholder}` };
|
|
137
|
+
}
|
|
138
|
+
const newContent = content.replace(placeholder, featureCode);
|
|
139
|
+
fs2.writeFileSync(fullPath, newContent);
|
|
140
|
+
return { success: true, message: `\u6CE8\u5165\u6210\u529F: ${targetPath}` };
|
|
141
|
+
}
|
|
142
|
+
replaceFile(targetPath, featureFilePath) {
|
|
143
|
+
const targetFullPath = path2.join(this.projectPath, targetPath);
|
|
144
|
+
const featureFullPath = path2.join(FEATURES_PATH, featureFilePath);
|
|
145
|
+
if (!fs2.existsSync(featureFullPath)) {
|
|
146
|
+
return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` };
|
|
147
|
+
}
|
|
148
|
+
const featureContent = fs2.readFileSync(featureFullPath, "utf-8");
|
|
149
|
+
fs2.writeFileSync(targetFullPath, featureContent);
|
|
150
|
+
return { success: true, message: `\u66FF\u6362\u6210\u529F: ${targetPath}` };
|
|
151
|
+
}
|
|
152
|
+
createFile(relativePath, featureFilePath) {
|
|
153
|
+
const targetFullPath = path2.join(this.projectPath, relativePath);
|
|
154
|
+
const featureFullPath = path2.join(FEATURES_PATH, featureFilePath);
|
|
155
|
+
if (!fs2.existsSync(featureFullPath)) {
|
|
156
|
+
return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` };
|
|
157
|
+
}
|
|
158
|
+
const dir = path2.dirname(targetFullPath);
|
|
159
|
+
if (!fs2.existsSync(dir)) {
|
|
160
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
161
|
+
}
|
|
162
|
+
const featureContent = fs2.readFileSync(featureFullPath, "utf-8");
|
|
163
|
+
fs2.writeFileSync(targetFullPath, featureContent);
|
|
164
|
+
return { success: true, message: `\u521B\u5EFA\u6210\u529F: ${relativePath}` };
|
|
165
|
+
}
|
|
166
|
+
appendAfter(targetPath, marker, code) {
|
|
167
|
+
const fullPath = path2.join(this.projectPath, targetPath);
|
|
168
|
+
if (!fs2.existsSync(fullPath)) {
|
|
169
|
+
return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` };
|
|
170
|
+
}
|
|
171
|
+
const content = fs2.readFileSync(fullPath, "utf-8");
|
|
172
|
+
if (!content.includes(marker)) {
|
|
173
|
+
return { success: false, message: `\u6807\u8BB0\u4E0D\u5B58\u5728: ${marker}` };
|
|
174
|
+
}
|
|
175
|
+
const newContent = content.replace(marker, `${marker}
|
|
176
|
+
${code}`);
|
|
177
|
+
fs2.writeFileSync(fullPath, newContent);
|
|
178
|
+
return { success: true, message: `\u8FFD\u52A0\u6210\u529F: ${targetPath}` };
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
async function injectI18n(projectPath) {
|
|
182
|
+
const results = [];
|
|
183
|
+
const injector = new FeatureInjector(projectPath);
|
|
184
|
+
results.push(injector.appendAfter(
|
|
185
|
+
"src/main.ts",
|
|
186
|
+
`import 'virtual:uno.css'`,
|
|
187
|
+
`import i18n from './locale/index'`
|
|
188
|
+
));
|
|
189
|
+
results.push(injector.appendAfter(
|
|
190
|
+
"src/main.ts",
|
|
191
|
+
` app.use(requestInterceptor)`,
|
|
192
|
+
` app.use(i18n)`
|
|
193
|
+
));
|
|
194
|
+
results.push(injector.replaceFile(
|
|
195
|
+
"src/tabbar/config.ts",
|
|
196
|
+
"i18n/files/src/tabbar/config.ts"
|
|
197
|
+
));
|
|
198
|
+
results.push(injector.replaceFile(
|
|
199
|
+
"src/tabbar/index.vue",
|
|
200
|
+
"i18n/files/src/tabbar/index.vue"
|
|
201
|
+
));
|
|
202
|
+
results.push(injector.replaceFile(
|
|
203
|
+
"src/tabbar/TabbarItem.vue",
|
|
204
|
+
"i18n/files/src/tabbar/TabbarItem.vue"
|
|
205
|
+
));
|
|
206
|
+
results.push(injector.replaceFile(
|
|
207
|
+
"src/utils/index.ts",
|
|
208
|
+
"i18n/files/src/utils/index.ts"
|
|
209
|
+
));
|
|
210
|
+
results.push(injector.replaceFile(
|
|
211
|
+
"src/store/token.ts",
|
|
212
|
+
"i18n/files/src/store/token.ts"
|
|
213
|
+
));
|
|
214
|
+
const i18nFiles = [
|
|
215
|
+
"src/locale/index.ts",
|
|
216
|
+
"src/locale/en.json",
|
|
217
|
+
"src/locale/zh-Hans.json",
|
|
218
|
+
"src/locale/README.md",
|
|
219
|
+
"src/utils/i18n.ts",
|
|
220
|
+
"src/types/i18n.d.ts",
|
|
221
|
+
"src/tabbar/i18n.ts",
|
|
222
|
+
"src/pages/i18n/index.vue"
|
|
223
|
+
];
|
|
224
|
+
for (const file of i18nFiles) {
|
|
225
|
+
const featurePath = `i18n/files/${file}`;
|
|
226
|
+
results.push(injector.createFile(file, featurePath));
|
|
227
|
+
}
|
|
228
|
+
return results;
|
|
229
|
+
}
|
|
230
|
+
async function injectLogin(projectPath) {
|
|
231
|
+
const results = [];
|
|
232
|
+
const injector = new FeatureInjector(projectPath);
|
|
233
|
+
results.push(injector.replaceFile(
|
|
234
|
+
"src/router/interceptor.ts",
|
|
235
|
+
"login/files/src/router/interceptor.ts"
|
|
236
|
+
));
|
|
237
|
+
results.push(injector.replaceFile(
|
|
238
|
+
"src/router/config.ts",
|
|
239
|
+
"login/files/src/router/config.ts"
|
|
240
|
+
));
|
|
241
|
+
results.push(injector.replaceFile(
|
|
242
|
+
"src/pages/me/me.vue",
|
|
243
|
+
"login/files/src/pages/me.vue"
|
|
244
|
+
));
|
|
245
|
+
const loginFiles = [
|
|
246
|
+
"src/pages/auth/login.vue",
|
|
247
|
+
"src/pages/auth/register.vue",
|
|
248
|
+
"src/pages/auth/README.md"
|
|
249
|
+
];
|
|
250
|
+
for (const file of loginFiles) {
|
|
251
|
+
const featurePath = `login/files/${file}`;
|
|
252
|
+
results.push(injector.createFile(file, featurePath));
|
|
253
|
+
}
|
|
254
|
+
return results;
|
|
255
|
+
}
|
|
9
256
|
|
|
10
257
|
// src/utils/logger.ts
|
|
11
258
|
import { bold, green, red, yellow, cyan } from "kolorist";
|
|
@@ -32,6 +279,178 @@ var logger = {
|
|
|
32
279
|
}
|
|
33
280
|
};
|
|
34
281
|
|
|
282
|
+
// src/utils/readPackageJson.ts
|
|
283
|
+
import fs3 from "fs";
|
|
284
|
+
function readPackageJson(pkgPath) {
|
|
285
|
+
if (!fs3.existsSync(pkgPath)) {
|
|
286
|
+
throw new Error(`package.json not found: ${pkgPath}`);
|
|
287
|
+
}
|
|
288
|
+
const content = fs3.readFileSync(pkgPath, "utf-8");
|
|
289
|
+
return JSON.parse(content);
|
|
290
|
+
}
|
|
291
|
+
function writePackageJson(pkgPath, pkg) {
|
|
292
|
+
fs3.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
293
|
+
`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/commands/add.ts
|
|
297
|
+
function getFeatureStatusFromPackageJson(pkgPath) {
|
|
298
|
+
try {
|
|
299
|
+
const pkg = readPackageJson(pkgPath);
|
|
300
|
+
return {
|
|
301
|
+
i18n: pkg.unibest?.i18n === true,
|
|
302
|
+
login: pkg.unibest?.loginStrategy === true
|
|
303
|
+
};
|
|
304
|
+
} catch {
|
|
305
|
+
return { i18n: false, login: false };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function updatePackageJsonForFeature(pkgPath, featureName) {
|
|
309
|
+
const pkg = readPackageJson(pkgPath);
|
|
310
|
+
if (!pkg.unibest) {
|
|
311
|
+
pkg.unibest = {};
|
|
312
|
+
}
|
|
313
|
+
switch (featureName) {
|
|
314
|
+
case "i18n":
|
|
315
|
+
pkg.unibest.i18n = true;
|
|
316
|
+
break;
|
|
317
|
+
case "login":
|
|
318
|
+
pkg.unibest.loginStrategy = true;
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
writePackageJson(pkgPath, pkg);
|
|
322
|
+
}
|
|
323
|
+
async function checkFeatureStatus(projectPath) {
|
|
324
|
+
const pkgPath = path3.join(projectPath, "package.json");
|
|
325
|
+
const statusFromPkg = getFeatureStatusFromPackageJson(pkgPath);
|
|
326
|
+
return [
|
|
327
|
+
{ name: "i18n", enabled: statusFromPkg.i18n },
|
|
328
|
+
{ name: "login", enabled: statusFromPkg.login }
|
|
329
|
+
];
|
|
330
|
+
}
|
|
331
|
+
async function addFeature(featureName, projectPath, options = {}) {
|
|
332
|
+
const feature = getFeatureByName(featureName);
|
|
333
|
+
if (!feature) {
|
|
334
|
+
logger.error(`\u672A\u77E5\u7684 Feature: ${featureName}`);
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
const pkgPath = path3.join(projectPath, "package.json");
|
|
338
|
+
const pkg = readPackageJson(pkgPath);
|
|
339
|
+
let alreadyAdded = false;
|
|
340
|
+
if (featureName === "i18n" && pkg.unibest?.i18n === true) {
|
|
341
|
+
alreadyAdded = true;
|
|
342
|
+
} else if (featureName === "login" && pkg.unibest?.loginStrategy === true) {
|
|
343
|
+
alreadyAdded = true;
|
|
344
|
+
}
|
|
345
|
+
if (alreadyAdded && !options.force) {
|
|
346
|
+
logger.warn(`Feature ${featureName} \u5DF2\u6DFB\u52A0\u8FC7\uFF0C\u5982\u9700\u91CD\u65B0\u6CE8\u5165\u8BF7\u4F7F\u7528 --force \u53C2\u6570`);
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
log.info(`\u6B63\u5728\u6DFB\u52A0 Feature: ${green2(featureName)} - ${feature.description}`);
|
|
350
|
+
try {
|
|
351
|
+
let results;
|
|
352
|
+
switch (featureName) {
|
|
353
|
+
case "i18n":
|
|
354
|
+
results = await injectI18n(projectPath);
|
|
355
|
+
break;
|
|
356
|
+
case "login":
|
|
357
|
+
results = await injectLogin(projectPath);
|
|
358
|
+
break;
|
|
359
|
+
default:
|
|
360
|
+
logger.error(`\u4E0D\u652F\u6301\u7684 Feature: ${featureName}`);
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
for (const result of results) {
|
|
364
|
+
if (result.success) {
|
|
365
|
+
logger.success(result.message);
|
|
366
|
+
} else {
|
|
367
|
+
logger.warn(result.message);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const hooks = await loadFeatureHooks(featureName);
|
|
371
|
+
if (hooks?.postApply) {
|
|
372
|
+
await hooks.postApply({
|
|
373
|
+
options: { projectName: "", platforms: [], uiLibrary: "none", i18n: true, loginStrategy: true },
|
|
374
|
+
projectPath,
|
|
375
|
+
featureName
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
updatePackageJsonForFeature(pkgPath, featureName);
|
|
379
|
+
logger.success(`\u5DF2\u66F4\u65B0 package.json \u7684 unibest \u914D\u7F6E`);
|
|
380
|
+
if (feature.dependencies && Object.keys(feature.dependencies).length > 0) {
|
|
381
|
+
logger.info(`\u5B89\u88C5\u4F9D\u8D56: ${Object.keys(feature.dependencies).join(", ")}`);
|
|
382
|
+
}
|
|
383
|
+
logger.success(`Feature ${featureName} \u6DFB\u52A0\u6210\u529F\uFF01`);
|
|
384
|
+
return true;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`);
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async function addCommand(args) {
|
|
391
|
+
const options = {
|
|
392
|
+
path: args.path || args.p || ".",
|
|
393
|
+
feature: args._[1] || args.feature || args.f,
|
|
394
|
+
force: args.force || args.f
|
|
395
|
+
};
|
|
396
|
+
intro(bold2(green2(`create-unibest@v${version} \u6DFB\u52A0 Feature`)));
|
|
397
|
+
const projectPath = path3.isAbsolute(options.path) ? options.path : path3.join(process2.cwd(), options.path);
|
|
398
|
+
const pkgPath = path3.join(projectPath, "package.json");
|
|
399
|
+
if (!fs4.existsSync(pkgPath)) {
|
|
400
|
+
logger.error(`\u9879\u76EE\u4E0D\u5B58\u5728: ${projectPath}`);
|
|
401
|
+
process2.exit(1);
|
|
402
|
+
}
|
|
403
|
+
const pkg = readPackageJson(pkgPath);
|
|
404
|
+
if (pkg.name !== "unibest") {
|
|
405
|
+
logger.warn(`\u5F53\u524D\u9879\u76EE\u53EF\u80FD\u4E0D\u662F unibest \u9879\u76EE: ${pkg.name}`);
|
|
406
|
+
}
|
|
407
|
+
const availableFeatures = getAvailableFeatureNames();
|
|
408
|
+
try {
|
|
409
|
+
if (!options.feature) {
|
|
410
|
+
const detected = await checkFeatureStatus(projectPath);
|
|
411
|
+
const available = availableFeatures.filter((f) => !detected.find((d) => d.name === f && d.enabled));
|
|
412
|
+
if (available.length === 0) {
|
|
413
|
+
logger.info("\u6240\u6709\u53EF\u7528 Feature \u5DF2\u542F\u7528");
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const selectedFeatures = await multiselect({
|
|
417
|
+
message: `\u8BF7\u9009\u62E9\u8981\u6DFB\u52A0\u7684 Feature`,
|
|
418
|
+
options: available.map((name) => {
|
|
419
|
+
const feature = getFeatureByName(name);
|
|
420
|
+
return {
|
|
421
|
+
value: name,
|
|
422
|
+
label: feature?.name || name,
|
|
423
|
+
hint: feature?.description || ""
|
|
424
|
+
};
|
|
425
|
+
}),
|
|
426
|
+
required: false
|
|
427
|
+
});
|
|
428
|
+
if (isCancel(selectedFeatures)) {
|
|
429
|
+
cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
430
|
+
process2.exit(0);
|
|
431
|
+
}
|
|
432
|
+
if (!Array.isArray(selectedFeatures) || selectedFeatures.length === 0) {
|
|
433
|
+
logger.info("\u672A\u9009\u62E9\u4EFB\u4F55 Feature");
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
for (const featureName of selectedFeatures) {
|
|
437
|
+
await addFeature(featureName, projectPath, options);
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
const features = Array.isArray(options.feature) ? options.feature : [options.feature];
|
|
441
|
+
for (const featureName of features) {
|
|
442
|
+
await addFeature(featureName, projectPath, options);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`);
|
|
447
|
+
process2.exit(1);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/commands/create/prompts.ts
|
|
452
|
+
import { text, multiselect as multiselect2, select, confirm, cancel as cancel2, isCancel as isCancel2 } from "@clack/prompts";
|
|
453
|
+
|
|
35
454
|
// src/utils/validate.ts
|
|
36
455
|
import { existsSync } from "fs";
|
|
37
456
|
import { yellow as yellow2 } from "kolorist";
|
|
@@ -58,8 +477,8 @@ function checkProjectNameExistAndValidate(_projectName) {
|
|
|
58
477
|
}
|
|
59
478
|
|
|
60
479
|
// src/commands/create/prompts.ts
|
|
61
|
-
import { green as
|
|
62
|
-
import
|
|
480
|
+
import { green as green3, red as red2 } from "kolorist";
|
|
481
|
+
import process3 from "process";
|
|
63
482
|
var VALID_PLATFORMS = ["h5", "mp-weixin", "app", "mp-alipay", "mp-toutiao"];
|
|
64
483
|
var VALID_UI_LIBRARIES = ["none", "wot-ui", "uview-pro", "sard-uniapp", "uv-ui", "uview-plus"];
|
|
65
484
|
async function promptUser(projectName, argv = {}) {
|
|
@@ -79,7 +498,7 @@ async function promptUser(projectName, argv = {}) {
|
|
|
79
498
|
if (invalidPlatforms.length > 0) {
|
|
80
499
|
console.error(red2(`\u65E0\u6548\u7684\u5E73\u53F0\u53C2\u6570: ${invalidPlatforms.join(", ")}`));
|
|
81
500
|
console.error(red2(`\u53EF\u9009\u503C: ${VALID_PLATFORMS.join(", ")}`));
|
|
82
|
-
|
|
501
|
+
process3.exit(1);
|
|
83
502
|
}
|
|
84
503
|
platforms = parsedPlatforms;
|
|
85
504
|
}
|
|
@@ -88,20 +507,26 @@ async function promptUser(projectName, argv = {}) {
|
|
|
88
507
|
if (!VALID_UI_LIBRARIES.includes(uiArg)) {
|
|
89
508
|
console.error(red2(`\u65E0\u6548\u7684UI\u5E93\u53C2\u6570: ${uiArg}`));
|
|
90
509
|
console.error(red2(`\u53EF\u9009\u503C: ${VALID_UI_LIBRARIES.join(", ")}`));
|
|
91
|
-
|
|
510
|
+
process3.exit(1);
|
|
92
511
|
}
|
|
93
512
|
uiLibrary = uiArg;
|
|
94
513
|
}
|
|
95
|
-
|
|
514
|
+
const loginArg = argv.l ?? argv.login;
|
|
515
|
+
if (loginArg === true || loginArg === "true") {
|
|
96
516
|
loginStrategy = true;
|
|
517
|
+
} else if (loginArg === false || loginArg === "false") {
|
|
518
|
+
loginStrategy = false;
|
|
97
519
|
}
|
|
98
|
-
|
|
520
|
+
const i18nArg = argv.i ?? argv.i18n;
|
|
521
|
+
if (i18nArg === true || i18nArg === "true") {
|
|
99
522
|
i18n = true;
|
|
523
|
+
} else if (i18nArg === false || i18nArg === "false") {
|
|
524
|
+
i18n = false;
|
|
100
525
|
}
|
|
101
526
|
try {
|
|
102
527
|
if (!projectName) {
|
|
103
528
|
const inputProjectName = await text({
|
|
104
|
-
message: `\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0${
|
|
529
|
+
message: `\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0${green3("[\u9879\u76EE\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u77ED\u6A2A\u7EBF\uFF0C\u5343\u4E07\u522B\u5199\u4E2D\u6587]")}`,
|
|
105
530
|
initialValue: "",
|
|
106
531
|
validate: (value) => {
|
|
107
532
|
if (!value.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
@@ -110,15 +535,15 @@ async function promptUser(projectName, argv = {}) {
|
|
|
110
535
|
return;
|
|
111
536
|
}
|
|
112
537
|
});
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
538
|
+
if (isCancel2(inputProjectName)) {
|
|
539
|
+
cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
540
|
+
process3.exit(0);
|
|
116
541
|
}
|
|
117
542
|
projectName = inputProjectName;
|
|
118
543
|
}
|
|
119
544
|
if (!platforms) {
|
|
120
|
-
const selectedPlatforms = await
|
|
121
|
-
message: `\u8BF7\u9009\u62E9\u9700\u8981\u652F\u6301\u7684\u5E73\u53F0\uFF08\u591A\u9009\uFF09${
|
|
545
|
+
const selectedPlatforms = await multiselect2({
|
|
546
|
+
message: `\u8BF7\u9009\u62E9\u9700\u8981\u652F\u6301\u7684\u5E73\u53F0\uFF08\u591A\u9009\uFF09${green3("[\u811A\u624B\u67B6\u5C06\u6839\u636E\u6240\u9009\u5E73\u53F0\u751F\u6210\u5BF9\u5E94\u7684\u5E73\u53F0\u4EE3\u7801\uFF0C\u8BF7\u6839\u636E\u5B9E\u9645\u60C5\u51B5\u9009\u62E9]")}`,
|
|
122
547
|
options: [
|
|
123
548
|
{ value: "h5", label: "H5" },
|
|
124
549
|
{ value: "mp-weixin", label: "\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F" },
|
|
@@ -130,9 +555,9 @@ async function promptUser(projectName, argv = {}) {
|
|
|
130
555
|
// 默认选择 H5
|
|
131
556
|
required: true
|
|
132
557
|
});
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
558
|
+
if (isCancel2(selectedPlatforms)) {
|
|
559
|
+
cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
560
|
+
process3.exit(0);
|
|
136
561
|
}
|
|
137
562
|
platforms = selectedPlatforms;
|
|
138
563
|
}
|
|
@@ -149,20 +574,20 @@ async function promptUser(projectName, argv = {}) {
|
|
|
149
574
|
],
|
|
150
575
|
initialValue: "none"
|
|
151
576
|
});
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
|
|
577
|
+
if (isCancel2(selectedUiLibrary)) {
|
|
578
|
+
cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
579
|
+
process3.exit(0);
|
|
155
580
|
}
|
|
156
581
|
uiLibrary = selectedUiLibrary;
|
|
157
582
|
}
|
|
158
583
|
if (loginStrategy === void 0) {
|
|
159
584
|
const selectedLoginStrategy = await confirm({
|
|
160
|
-
message: `\u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09\uFF1F${
|
|
585
|
+
message: `\u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09\uFF1F${green3("[\u6682\u4E0D\u77E5\u9053\u7684\uFF0C\u9009No\u5373\u53EF\uFF0C\u9879\u76EE\u751F\u6210\u540E\u4E5F\u53EF\u4EE5\u52A0\u8BE5\u7B56\u7565]")}`,
|
|
161
586
|
initialValue: false
|
|
162
587
|
});
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
|
|
588
|
+
if (isCancel2(selectedLoginStrategy)) {
|
|
589
|
+
cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
590
|
+
process3.exit(0);
|
|
166
591
|
}
|
|
167
592
|
loginStrategy = selectedLoginStrategy;
|
|
168
593
|
}
|
|
@@ -171,9 +596,9 @@ async function promptUser(projectName, argv = {}) {
|
|
|
171
596
|
message: "\u662F\u5426\u9700\u8981\u591A\u8BED\u8A00i18n\uFF1F",
|
|
172
597
|
initialValue: false
|
|
173
598
|
});
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
599
|
+
if (isCancel2(selectedI18n)) {
|
|
600
|
+
cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
601
|
+
process3.exit(0);
|
|
177
602
|
}
|
|
178
603
|
i18n = selectedI18n;
|
|
179
604
|
}
|
|
@@ -189,73 +614,25 @@ async function promptUser(projectName, argv = {}) {
|
|
|
189
614
|
};
|
|
190
615
|
} catch (error) {
|
|
191
616
|
logger.error(`\u8BE2\u95EE\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
|
|
192
|
-
|
|
617
|
+
process3.exit(1);
|
|
193
618
|
}
|
|
194
619
|
}
|
|
195
620
|
|
|
196
621
|
// src/commands/create/generate.ts
|
|
197
|
-
import
|
|
198
|
-
import { log } from "@clack/prompts";
|
|
622
|
+
import process5 from "process";
|
|
623
|
+
import { log as log2 } from "@clack/prompts";
|
|
199
624
|
|
|
200
625
|
// src/utils/cloneRepo.ts
|
|
201
626
|
import { exec } from "child_process";
|
|
202
|
-
import { promises as
|
|
203
|
-
import { join as join3 } from "path";
|
|
204
|
-
import
|
|
627
|
+
import { promises as fsPromises } from "fs";
|
|
628
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
629
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
630
|
+
import process4 from "process";
|
|
205
631
|
import { red as red3 } from "kolorist";
|
|
206
632
|
|
|
207
633
|
// src/utils/replacePackageJson.ts
|
|
208
634
|
import { readFileSync, writeFileSync } from "fs";
|
|
209
635
|
import { join as join2 } from "path";
|
|
210
|
-
|
|
211
|
-
// package.json
|
|
212
|
-
var version = "3.3.0";
|
|
213
|
-
var package_default = {
|
|
214
|
-
name: "create-unibest",
|
|
215
|
-
type: "module",
|
|
216
|
-
version,
|
|
217
|
-
updateTime: "2026-01-19",
|
|
218
|
-
packageManager: "pnpm@9.0.0",
|
|
219
|
-
description: "\u5FEB\u901F\u521B\u5EFAunibest\u9879\u76EE\u7684\u811A\u624B\u67B6\u5DE5\u5177",
|
|
220
|
-
author: "",
|
|
221
|
-
license: "ISC",
|
|
222
|
-
keywords: [],
|
|
223
|
-
main: "dist/index.js",
|
|
224
|
-
bin: {
|
|
225
|
-
best: "bin/index.js",
|
|
226
|
-
"create-unibest": "bin/index.js"
|
|
227
|
-
},
|
|
228
|
-
files: [
|
|
229
|
-
"bin",
|
|
230
|
-
"dist"
|
|
231
|
-
],
|
|
232
|
-
scripts: {
|
|
233
|
-
dev: "cross-env NODE_ENV=development tsup --watch",
|
|
234
|
-
build: "cross-env NODE_ENV=production tsup",
|
|
235
|
-
prepare: "cross-env NODE_ENV=production npm run build",
|
|
236
|
-
start: "cross-env NODE_ENV=development node bin/index.js"
|
|
237
|
-
},
|
|
238
|
-
dependencies: {
|
|
239
|
-
"@clack/prompts": "^0.11.0",
|
|
240
|
-
dayjs: "^1.11.18",
|
|
241
|
-
ejs: "^3.1.10",
|
|
242
|
-
"fs-extra": "^11.3.0",
|
|
243
|
-
kolorist: "^1.8.0",
|
|
244
|
-
minimist: "^1.2.8",
|
|
245
|
-
"node-fetch": "^3.3.2"
|
|
246
|
-
},
|
|
247
|
-
devDependencies: {
|
|
248
|
-
"@types/ejs": "^3.1.5",
|
|
249
|
-
"@types/fs-extra": "^11.0.4",
|
|
250
|
-
"@types/minimist": "^1.2.5",
|
|
251
|
-
"@types/node": "^24.5.0",
|
|
252
|
-
"cross-env": "^7.0.3",
|
|
253
|
-
tsup: "^8.5.0",
|
|
254
|
-
typescript: "^5.9.0"
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
// src/utils/replacePackageJson.ts
|
|
259
636
|
import dayjs from "dayjs";
|
|
260
637
|
function replaceContent(filePath, projectName, version2, options) {
|
|
261
638
|
const fileContent = JSON.parse(readFileSync(filePath, "utf8"));
|
|
@@ -267,6 +644,21 @@ function replaceContent(filePath, projectName, version2, options) {
|
|
|
267
644
|
delete fileContent.name;
|
|
268
645
|
delete fileContent.version;
|
|
269
646
|
const { projectName: _, ...restOptions } = options;
|
|
647
|
+
const selectedFeatures = getSelectedFeatures(options);
|
|
648
|
+
const featureDeps = {};
|
|
649
|
+
for (const feature of selectedFeatures) {
|
|
650
|
+
if (feature.dependencies) {
|
|
651
|
+
Object.assign(featureDeps, feature.dependencies);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (!fileContent.dependencies) {
|
|
655
|
+
fileContent.dependencies = {};
|
|
656
|
+
}
|
|
657
|
+
for (const [pkg, ver] of Object.entries(featureDeps)) {
|
|
658
|
+
if (!fileContent.dependencies[pkg]) {
|
|
659
|
+
fileContent.dependencies[pkg] = ver;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
270
662
|
const newContent = {
|
|
271
663
|
name: projectName,
|
|
272
664
|
type: fileContent.type,
|
|
@@ -291,9 +683,28 @@ function replacePackageJson(root2, name, version2, options) {
|
|
|
291
683
|
}
|
|
292
684
|
|
|
293
685
|
// src/utils/cloneRepo.ts
|
|
686
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
687
|
+
var __dirname3 = dirname2(__filename3);
|
|
688
|
+
var USE_LOCAL_TEMPLATE = process4.env.LOCAL_TEMPLATE === "true";
|
|
689
|
+
var TEMPLATE_BASE_PATH = null;
|
|
690
|
+
async function getTemplateBasePath() {
|
|
691
|
+
if (TEMPLATE_BASE_PATH) return TEMPLATE_BASE_PATH;
|
|
692
|
+
const candidates = [
|
|
693
|
+
join3(__dirname3, "..", "..", "..", "packages", "template-base"),
|
|
694
|
+
join3(__dirname3, "..", "..", "packages", "template-base")
|
|
695
|
+
];
|
|
696
|
+
const { existsSync: existsSync3 } = await import("fs");
|
|
697
|
+
for (const candidate of candidates) {
|
|
698
|
+
if (existsSync3(candidate)) {
|
|
699
|
+
TEMPLATE_BASE_PATH = candidate;
|
|
700
|
+
return candidate;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
throw new Error("\u65E0\u6CD5\u627E\u5230 template-base \u76EE\u5F55");
|
|
704
|
+
}
|
|
294
705
|
async function removeGitFolder(localPath) {
|
|
295
706
|
const gitFolderPath = join3(localPath, ".git");
|
|
296
|
-
await
|
|
707
|
+
await fsPromises.rm(gitFolderPath, { recursive: true, force: true });
|
|
297
708
|
}
|
|
298
709
|
var REPO_URL = "https://gitee.com/feige996/unibest.git";
|
|
299
710
|
async function cloneRepo(projectName, branch) {
|
|
@@ -320,12 +731,33 @@ async function cloneRepo(projectName, branch) {
|
|
|
320
731
|
throw new Error("cloneRepo error");
|
|
321
732
|
}
|
|
322
733
|
}
|
|
734
|
+
async function copyLocalTemplate(projectName) {
|
|
735
|
+
const projectPath = join3(process4.cwd(), projectName);
|
|
736
|
+
const sourcePath = await getTemplateBasePath();
|
|
737
|
+
await new Promise((resolve, reject) => {
|
|
738
|
+
const execStr = `cp -r "${sourcePath}/." "${projectPath}/"`;
|
|
739
|
+
exec(execStr, (error) => {
|
|
740
|
+
if (error) {
|
|
741
|
+
reject(error);
|
|
742
|
+
} else {
|
|
743
|
+
resolve();
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
return projectPath;
|
|
748
|
+
}
|
|
323
749
|
async function cloneRepoByBranch(root2, name, branch, options) {
|
|
324
750
|
try {
|
|
325
|
-
|
|
751
|
+
if (USE_LOCAL_TEMPLATE) {
|
|
752
|
+
console.log("\u4F7F\u7528\u672C\u5730\u6A21\u677F\u6D4B\u8BD5...");
|
|
753
|
+
await copyLocalTemplate(name);
|
|
754
|
+
} else {
|
|
755
|
+
console.log("\u4ECE Git \u514B\u9686\u57FA\u7840\u6A21\u677F...");
|
|
756
|
+
await cloneRepo(name, "base");
|
|
757
|
+
}
|
|
326
758
|
} catch (error) {
|
|
327
|
-
console.error(`${red3(`\u6A21\u677F\
|
|
328
|
-
|
|
759
|
+
console.error(`${red3(`\u6A21\u677F\u4E0B\u8F7D\u5931\u8D25\uFF01`)} ${error}`);
|
|
760
|
+
process4.exit(1);
|
|
329
761
|
}
|
|
330
762
|
const projectPath = join3(root2, name);
|
|
331
763
|
replacePackageJson(projectPath, name, "1.0.0", options);
|
|
@@ -687,25 +1119,36 @@ function debug(...args) {
|
|
|
687
1119
|
}
|
|
688
1120
|
|
|
689
1121
|
// src/commands/create/generate.ts
|
|
690
|
-
import
|
|
691
|
-
var root =
|
|
1122
|
+
import path4 from "path";
|
|
1123
|
+
var root = process5.cwd();
|
|
692
1124
|
async function generateProject(options) {
|
|
693
1125
|
debug("generateProject options", options);
|
|
694
1126
|
const { projectName, platforms, uiLibrary, loginStrategy, i18n } = options;
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
debug("\
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1127
|
+
const projectPath = path4.join(root, projectName);
|
|
1128
|
+
debug("\u62C9\u53D6 base \u5206\u652F");
|
|
1129
|
+
await cloneRepoByBranch(root, projectName, "base", options);
|
|
1130
|
+
if (i18n) {
|
|
1131
|
+
debug("\u6CE8\u5165 i18n feature");
|
|
1132
|
+
const results = await injectI18n(projectPath);
|
|
1133
|
+
for (const result of results) {
|
|
1134
|
+
if (result.success) {
|
|
1135
|
+
debug(result.message);
|
|
1136
|
+
} else {
|
|
1137
|
+
logger.warn(result.message);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
if (loginStrategy) {
|
|
1142
|
+
debug("\u6CE8\u5165 login feature");
|
|
1143
|
+
const results = await injectLogin(projectPath);
|
|
1144
|
+
for (const result of results) {
|
|
1145
|
+
if (result.success) {
|
|
1146
|
+
debug(result.message);
|
|
1147
|
+
} else {
|
|
1148
|
+
logger.warn(result.message);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
709
1152
|
if (uiLibrary === "none") {
|
|
710
1153
|
debug("\u4E0D\u5F15\u5165\u4EFB\u4F55UI\u5E93");
|
|
711
1154
|
} else {
|
|
@@ -718,8 +1161,18 @@ async function generateProject(options) {
|
|
|
718
1161
|
logger.info("\u60A8\u53EF\u4EE5\u5728\u9879\u76EE\u521B\u5EFA\u540E\u624B\u52A8\u914D\u7F6E UI \u5E93");
|
|
719
1162
|
}
|
|
720
1163
|
}
|
|
1164
|
+
const selectedFeatures = getSelectedFeatures(options);
|
|
1165
|
+
const allDeps = {};
|
|
1166
|
+
for (const feature of selectedFeatures) {
|
|
1167
|
+
if (feature.dependencies) {
|
|
1168
|
+
Object.assign(allDeps, feature.dependencies);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (Object.keys(allDeps).length > 0) {
|
|
1172
|
+
logger.info(`Feature \u4F9D\u8D56: ${Object.keys(allDeps).join(", ")}`);
|
|
1173
|
+
}
|
|
721
1174
|
try {
|
|
722
|
-
|
|
1175
|
+
log2.success(`\u9879\u76EE${projectName}\u521B\u5EFA\u6210\u529F\uFF01`);
|
|
723
1176
|
logger.info("\u4E0B\u4E00\u6B65:");
|
|
724
1177
|
logger.info(` cd ${projectName}`);
|
|
725
1178
|
logger.info(" pnpm i");
|
|
@@ -733,8 +1186,8 @@ async function generateProject(options) {
|
|
|
733
1186
|
}
|
|
734
1187
|
|
|
735
1188
|
// src/commands/create.ts
|
|
736
|
-
import { intro, log as
|
|
737
|
-
import { bold as
|
|
1189
|
+
import { intro as intro2, log as log3 } from "@clack/prompts";
|
|
1190
|
+
import { bold as bold3, yellow as yellow3, green as green4 } from "kolorist";
|
|
738
1191
|
|
|
739
1192
|
// src/utils/unibestVersion.ts
|
|
740
1193
|
import fetch from "node-fetch";
|
|
@@ -811,11 +1264,11 @@ function generateDeviceIdentifier() {
|
|
|
811
1264
|
async function createCommand(args) {
|
|
812
1265
|
const projectName = args._[1] || args._[0];
|
|
813
1266
|
const versionUnibest = await getUnibestVersionFromGitee() || "4.0.0";
|
|
814
|
-
|
|
1267
|
+
intro2(bold3(green4(`create-unibest@v${version} \u5FEB\u901F\u521B\u5EFA ${yellow3(`unibest@v${versionUnibest}`)} \u9879\u76EE`)));
|
|
815
1268
|
if (projectName) {
|
|
816
1269
|
const errorMessage = checkProjectNameExistAndValidate(projectName);
|
|
817
1270
|
if (errorMessage) {
|
|
818
|
-
|
|
1271
|
+
log3.error(errorMessage);
|
|
819
1272
|
process.exit(1);
|
|
820
1273
|
}
|
|
821
1274
|
}
|
|
@@ -824,16 +1277,16 @@ async function createCommand(args) {
|
|
|
824
1277
|
await generateProject(projectOptions);
|
|
825
1278
|
beacon(projectOptions);
|
|
826
1279
|
} catch (error) {
|
|
827
|
-
|
|
1280
|
+
log3.error(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${error.message}`);
|
|
828
1281
|
process.exit(1);
|
|
829
1282
|
}
|
|
830
1283
|
}
|
|
831
1284
|
|
|
832
1285
|
// src/utils/color.ts
|
|
833
|
-
import { blue, green as
|
|
1286
|
+
import { blue, green as green5, magenta as magenta2, red as red4, yellow as yellow4 } from "kolorist";
|
|
834
1287
|
var color = {
|
|
835
1288
|
blue,
|
|
836
|
-
green:
|
|
1289
|
+
green: green5,
|
|
837
1290
|
magenta: magenta2,
|
|
838
1291
|
red: red4,
|
|
839
1292
|
yellow: yellow4
|
|
@@ -846,33 +1299,54 @@ function printHelp() {
|
|
|
846
1299
|
console.log(color.blue("\u5FEB\u901F\u4F7F\u7528:"));
|
|
847
1300
|
console.log(color.green(" pnpm create unibest <command> [options]"));
|
|
848
1301
|
console.log(color.green(" pnpm create unibest my-project \u521B\u5EFA\u65B0\u7684unibest\u9879\u76EE"));
|
|
1302
|
+
console.log(color.green(" pnpm create unibest add i18n \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0i18n\u7279\u6027"));
|
|
1303
|
+
console.log(color.green(" pnpm create unibest add login \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0login\u7279\u6027"));
|
|
849
1304
|
console.log(color.green(" pnpm create unibest -v \u67E5\u770B\u7248\u672C\u4FE1\u606F"));
|
|
850
1305
|
console.log(color.green(" pnpm create unibest -h \u67E5\u770B\u5E2E\u52A9\u4FE1\u606F"));
|
|
851
1306
|
console.log("");
|
|
852
|
-
console.log(color.blue("\
|
|
1307
|
+
console.log(color.blue("\u53EF\u7528\u547D\u4EE4:"));
|
|
1308
|
+
console.log(" <projectName> \u521B\u5EFA\u9879\u76EE\uFF08\u4E0D\u7528 new \u5173\u952E\u5B57\uFF09");
|
|
1309
|
+
console.log(" create <projectName> \u521B\u5EFA\u9879\u76EE");
|
|
1310
|
+
console.log(" add <feature> \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0 Feature");
|
|
1311
|
+
console.log("");
|
|
1312
|
+
console.log(color.blue("\u521B\u5EFA\u9879\u76EE\u9009\u9879:"));
|
|
853
1313
|
console.log(" -p, --platform <type> \u6307\u5B9A\u5E73\u53F0 (h5, mp-weixin, app, mp-alipay, mp-toutiao)");
|
|
854
1314
|
console.log(" \u652F\u6301\u591A\u9009: -p h5,mp-weixin \u6216 -p h5 -p mp-weixin");
|
|
855
1315
|
console.log(" -u, --ui <library> \u6307\u5B9AUI\u5E93 (wot-ui, uview-pro, sard-uniapp, uv-ui, uview-plus, none)");
|
|
856
1316
|
console.log(" -l, --login \u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565");
|
|
857
1317
|
console.log(" -i, --i18n \u662F\u5426\u9700\u8981\u591A\u8BED\u8A00");
|
|
858
1318
|
console.log("");
|
|
1319
|
+
console.log(color.blue("\u6DFB\u52A0Feature\u9009\u9879:"));
|
|
1320
|
+
console.log(" <feature> \u8981\u6DFB\u52A0\u7684 Feature (i18n, login)");
|
|
1321
|
+
console.log(" --path <path> \u9879\u76EE\u8DEF\u5F84 (\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55)");
|
|
1322
|
+
console.log(" --force \u5F3A\u5236\u91CD\u65B0\u6CE8\u5165\uFF08\u8986\u76D6\u5DF2\u6709\u914D\u7F6E\uFF09");
|
|
1323
|
+
console.log("");
|
|
1324
|
+
console.log(color.blue("\u53EF\u7528Feature:"));
|
|
1325
|
+
console.log(" i18n \u591A\u8BED\u8A00\u652F\u6301");
|
|
1326
|
+
console.log(" login \u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09");
|
|
1327
|
+
console.log("");
|
|
859
1328
|
console.log(color.blue("\u793A\u4F8B:"));
|
|
1329
|
+
console.log(" # \u521B\u5EFA\u9879\u76EE");
|
|
860
1330
|
console.log(" pnpm create unibest my-project -u wot-ui -p h5,mp-weixin");
|
|
861
1331
|
console.log(" pnpm create unibest my-project -u uview-plus -l -i");
|
|
862
1332
|
console.log(" pnpm create unibest my-project -u none -p h5,app,mp-weixin");
|
|
863
1333
|
console.log("");
|
|
864
|
-
console.log(
|
|
865
|
-
console.log(
|
|
866
|
-
console.log(
|
|
867
|
-
console.log(
|
|
1334
|
+
console.log(" # \u6DFB\u52A0 Feature");
|
|
1335
|
+
console.log(" cd my-project && pnpm create unibest add i18n");
|
|
1336
|
+
console.log(" pnpm create unibest add login --path /path/to/project");
|
|
1337
|
+
console.log(" pnpm create unibest add i18n login");
|
|
1338
|
+
console.log(" pnpm create unibest add i18n --force # \u91CD\u65B0\u6CE8\u5165");
|
|
1339
|
+
console.log("");
|
|
1340
|
+
console.log(" # \u5168\u5C40\u5B89\u88C5");
|
|
1341
|
+
console.log(" npm i -g create-unibest");
|
|
1342
|
+
console.log(" best my-project");
|
|
1343
|
+
console.log(" best add i18n");
|
|
868
1344
|
console.log("");
|
|
869
1345
|
}
|
|
870
1346
|
|
|
871
1347
|
// src/index.ts
|
|
872
|
-
import { green as green5 } from "kolorist";
|
|
873
|
-
import { yellow as yellow5 } from "kolorist";
|
|
874
1348
|
function main() {
|
|
875
|
-
const args = minimist(
|
|
1349
|
+
const args = minimist(process6.argv.slice(2));
|
|
876
1350
|
const command = args._[0];
|
|
877
1351
|
debug("command:", command);
|
|
878
1352
|
debug("args:", args);
|
|
@@ -889,6 +1363,9 @@ function main() {
|
|
|
889
1363
|
case "new":
|
|
890
1364
|
createCommand(args);
|
|
891
1365
|
break;
|
|
1366
|
+
case "add":
|
|
1367
|
+
addCommand(args);
|
|
1368
|
+
break;
|
|
892
1369
|
case "-h":
|
|
893
1370
|
case "--help":
|
|
894
1371
|
printHelp();
|
|
@@ -906,8 +1383,8 @@ async function printVersion() {
|
|
|
906
1383
|
const cliVersion = version;
|
|
907
1384
|
const latestVersion = await getUnibestVersionFromGitee();
|
|
908
1385
|
if (latestVersion && latestVersion !== cliVersion) {
|
|
909
|
-
console.log(`unibest-cli ${cliVersion} ${yellow5(`->`)} ${
|
|
910
|
-
console.log(`\u4F7F\u7528 ${
|
|
1386
|
+
console.log(`unibest-cli ${cliVersion} ${yellow5(`->`)} ${green6(`\u6700\u65B0\u7248\u672C: ${latestVersion}`)}`);
|
|
1387
|
+
console.log(`\u4F7F\u7528 ${green6(`npm update -g create-unibest`)} \u6216 ${green6(`pnpm add -g create-unibest`)} \u66F4\u65B0`);
|
|
911
1388
|
console.log();
|
|
912
1389
|
} else {
|
|
913
1390
|
console.log(`unibest-cli ${cliVersion}`);
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-unibest",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"keywords": [],
|
|
11
|
-
"main": "dist/index.js",
|
|
4
|
+
"version": "4.0.1",
|
|
5
|
+
"packageManager": "pnpm@10.10.0",
|
|
6
|
+
"description": "快速创建 unibest 项目的脚手架工具",
|
|
7
|
+
"author": "feige996",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "https://unibest.tech",
|
|
12
10
|
"bin": {
|
|
13
11
|
"best": "bin/index.js",
|
|
14
|
-
"create-unibest": "bin/index.js"
|
|
12
|
+
"create-unibest": "bin/index.js",
|
|
13
|
+
"unibest": "bin/index.js"
|
|
15
14
|
},
|
|
16
15
|
"files": [
|
|
17
16
|
"bin",
|
|
18
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"features"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
21
|
"dev": "cross-env NODE_ENV=development tsup --watch",
|
|
22
22
|
"build": "cross-env NODE_ENV=production tsup",
|
|
23
|
-
"prepare": "
|
|
23
|
+
"prepare": "pnpm build",
|
|
24
24
|
"start": "cross-env NODE_ENV=development node bin/index.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
package/dist/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|