create-unibest 3.2.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,43 +1,79 @@
1
- <h1 align="center">✨create unibest✨</h1>
1
+ # create-unibest
2
2
 
3
- <p align="center">
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
- <h2 align="center">
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
- `create-unibest` 是一个用于快速创建 `unibest` 项目的轻量脚手架工具,它可以帮助你快速创建一个基于 `vite` + `vue3` + `TS` 的 `uni-app` 项目,同时提供了一些模板供你选择。
12
+ ## 使用方式
15
13
 
16
- ## 🚤 快速使用
14
+ ### 安装
17
15
 
18
- ### 全局安装
16
+ ```bash
17
+ # 全局安装(可选)
18
+ npm i -g create-unibest
19
19
 
20
- ```shell
21
- npm i -g create-unibest # 全局安装,得到 best 命令
22
- npm update -g create-unibest # 更新 create-unibest 包
20
+ # 或直接使用
21
+ pnpm create unibest
23
22
  ```
24
23
 
25
- 安装后可使用的命令:
24
+ ### 创建项目
26
25
 
27
- ```shell
28
- best <command> [options] # 基本命令格式
29
- best my-project # 创建新的unibest项目
30
- best new my-project # 创建新的unibest项目
31
- best -v # 查看版本信息
32
- best -h # 查看帮助信息
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
33
36
  ```
34
37
 
35
- ### 临时使用
38
+ ### 添加 Feature
39
+
40
+ ```bash
41
+ cd my-project
42
+
43
+ # 添加多语言
44
+ pnpm create unibest add i18n
45
+
46
+ # 添加登录策略
47
+ pnpm create unibest add login
36
48
 
37
- ```shell
38
- pnpm create unibest <command> [options] # 基本命令格式
39
- pnpm create unibest my-project # 创建新的unibest项目
40
- pnpm create unibest new my-project # 创建新的unibest项目
41
- pnpm create unibest -v # 查看版本信息
42
- pnpm create unibest -h # 查看帮助信息
49
+ # 强制重新注入(覆盖已有配置)
50
+ pnpm create unibest add i18n --force
43
51
  ```
52
+
53
+ ## 参数说明
54
+
55
+ ### 创建项目参数
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` | 启用多语言 |
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
@@ -6,7 +6,6 @@ import { fileURLToPath } from 'node:url'
6
6
  const __filename = fileURLToPath(import.meta.url)
7
7
  const __dirname = dirname(__filename)
8
8
 
9
- // 导入主程序
10
9
  import('../dist/index.js').catch((err) => {
11
10
  console.error('Failed to load CLI:', err)
12
11
  process.exit(1)
package/dist/index.js CHANGED
@@ -1,11 +1,254 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import process4 from "process";
4
+ import process6 from "process";
5
+ import { green as green6, yellow as yellow5 } from "kolorist";
5
6
  import minimist from "minimist";
6
7
 
7
- // src/commands/create/prompts.ts
8
- import { text, multiselect, select, confirm, cancel, isCancel } from "@clack/prompts";
8
+ // package.json
9
+ var version = "4.0.0";
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
+ ],
28
+ scripts: {
29
+ dev: "cross-env NODE_ENV=development tsup --watch",
30
+ build: "cross-env NODE_ENV=production tsup",
31
+ prepare: "pnpm build",
32
+ start: "cross-env NODE_ENV=development node bin/index.js"
33
+ },
34
+ dependencies: {
35
+ "@clack/prompts": "^0.11.0",
36
+ dayjs: "^1.11.18",
37
+ ejs: "^3.1.10",
38
+ "fs-extra": "^11.3.0",
39
+ kolorist: "^1.8.0",
40
+ minimist: "^1.2.8",
41
+ "node-fetch": "^3.3.2"
42
+ },
43
+ devDependencies: {
44
+ "@types/ejs": "^3.1.5",
45
+ "@types/fs-extra": "^11.0.4",
46
+ "@types/minimist": "^1.2.5",
47
+ "@types/node": "^24.5.0",
48
+ "cross-env": "^7.0.3",
49
+ tsup: "^8.5.0",
50
+ typescript: "^5.9.0"
51
+ }
52
+ };
53
+
54
+ // src/commands/add.ts
55
+ import fs4 from "fs";
56
+ import path3 from "path";
57
+ import process2 from "process";
58
+ import { cancel, intro, isCancel, log, multiselect } from "@clack/prompts";
59
+ import { bold as bold2, green as green2 } from "kolorist";
60
+
61
+ // src/features/interface.ts
62
+ var AVAILABLE_FEATURES = [
63
+ {
64
+ name: "i18n",
65
+ description: "\u591A\u8BED\u8A00\u652F\u6301",
66
+ dependencies: {
67
+ "vue-i18n": "^9.0.0",
68
+ "dayjs": "^1.11.0"
69
+ }
70
+ },
71
+ {
72
+ name: "login",
73
+ description: "\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09",
74
+ dependencies: {}
75
+ }
76
+ ];
77
+ function getFeatureByName(name) {
78
+ return AVAILABLE_FEATURES.find((f) => f.name === name);
79
+ }
80
+ function getSelectedFeatures(options) {
81
+ const features = [];
82
+ if (options.i18n) {
83
+ const feature = getFeatureByName("i18n");
84
+ if (feature) features.push(feature);
85
+ }
86
+ if (options.loginStrategy) {
87
+ const feature = getFeatureByName("login");
88
+ if (feature) features.push(feature);
89
+ }
90
+ return features;
91
+ }
92
+
93
+ // src/features/loader.ts
94
+ import fs from "fs";
95
+ import path from "path";
96
+ var FEATURES_DIR = path.resolve(process.cwd(), "../../features");
97
+ async function loadFeatureHooks(featureName) {
98
+ const hooksPath = path.join(FEATURES_DIR, featureName, "hooks.ts");
99
+ if (!fs.existsSync(hooksPath)) {
100
+ return null;
101
+ }
102
+ const module = await import(hooksPath);
103
+ return module;
104
+ }
105
+ function getAvailableFeatureNames() {
106
+ if (!fs.existsSync(FEATURES_DIR)) {
107
+ return [];
108
+ }
109
+ const entries = fs.readdirSync(FEATURES_DIR, { withFileTypes: true });
110
+ return entries.filter((e) => e.isDirectory() && fs.existsSync(path.join(FEATURES_DIR, e.name, "files"))).map((e) => e.name);
111
+ }
112
+
113
+ // src/utils/injector.ts
114
+ import fs2 from "fs";
115
+ import path2 from "path";
116
+ import { dirname } from "path";
117
+ import { fileURLToPath } from "url";
118
+ var __filename = fileURLToPath(import.meta.url);
119
+ var __dirname = dirname(__filename);
120
+ var FEATURES_PATH = path2.join(__dirname, "..", "..", "..", "features");
121
+ var FeatureInjector = class {
122
+ constructor(projectPath) {
123
+ this.projectPath = projectPath;
124
+ }
125
+ injectFile(targetPath, featureCode, placeholder) {
126
+ const fullPath = path2.join(this.projectPath, targetPath);
127
+ if (!fs2.existsSync(fullPath)) {
128
+ return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` };
129
+ }
130
+ const content = fs2.readFileSync(fullPath, "utf-8");
131
+ if (!content.includes(placeholder)) {
132
+ return { success: false, message: `\u5360\u4F4D\u7B26\u4E0D\u5B58\u5728: ${placeholder}` };
133
+ }
134
+ const newContent = content.replace(placeholder, featureCode);
135
+ fs2.writeFileSync(fullPath, newContent);
136
+ return { success: true, message: `\u6CE8\u5165\u6210\u529F: ${targetPath}` };
137
+ }
138
+ replaceFile(targetPath, featureFilePath) {
139
+ const targetFullPath = path2.join(this.projectPath, targetPath);
140
+ const featureFullPath = path2.join(FEATURES_PATH, featureFilePath);
141
+ if (!fs2.existsSync(featureFullPath)) {
142
+ return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` };
143
+ }
144
+ const featureContent = fs2.readFileSync(featureFullPath, "utf-8");
145
+ fs2.writeFileSync(targetFullPath, featureContent);
146
+ return { success: true, message: `\u66FF\u6362\u6210\u529F: ${targetPath}` };
147
+ }
148
+ createFile(relativePath, featureFilePath) {
149
+ const targetFullPath = path2.join(this.projectPath, relativePath);
150
+ const featureFullPath = path2.join(FEATURES_PATH, featureFilePath);
151
+ if (!fs2.existsSync(featureFullPath)) {
152
+ return { success: false, message: `Feature \u6587\u4EF6\u4E0D\u5B58\u5728: ${featureFilePath}` };
153
+ }
154
+ const dir = path2.dirname(targetFullPath);
155
+ if (!fs2.existsSync(dir)) {
156
+ fs2.mkdirSync(dir, { recursive: true });
157
+ }
158
+ const featureContent = fs2.readFileSync(featureFullPath, "utf-8");
159
+ fs2.writeFileSync(targetFullPath, featureContent);
160
+ return { success: true, message: `\u521B\u5EFA\u6210\u529F: ${relativePath}` };
161
+ }
162
+ appendAfter(targetPath, marker, code) {
163
+ const fullPath = path2.join(this.projectPath, targetPath);
164
+ if (!fs2.existsSync(fullPath)) {
165
+ return { success: false, message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${targetPath}` };
166
+ }
167
+ const content = fs2.readFileSync(fullPath, "utf-8");
168
+ if (!content.includes(marker)) {
169
+ return { success: false, message: `\u6807\u8BB0\u4E0D\u5B58\u5728: ${marker}` };
170
+ }
171
+ const newContent = content.replace(marker, `${marker}
172
+ ${code}`);
173
+ fs2.writeFileSync(fullPath, newContent);
174
+ return { success: true, message: `\u8FFD\u52A0\u6210\u529F: ${targetPath}` };
175
+ }
176
+ };
177
+ async function injectI18n(projectPath) {
178
+ const results = [];
179
+ const injector = new FeatureInjector(projectPath);
180
+ results.push(injector.appendAfter(
181
+ "src/main.ts",
182
+ `import 'virtual:uno.css'`,
183
+ `import i18n from './locale/index'`
184
+ ));
185
+ results.push(injector.appendAfter(
186
+ "src/main.ts",
187
+ ` app.use(requestInterceptor)`,
188
+ ` app.use(i18n)`
189
+ ));
190
+ results.push(injector.replaceFile(
191
+ "src/tabbar/config.ts",
192
+ "i18n/files/src/tabbar/config.ts"
193
+ ));
194
+ results.push(injector.replaceFile(
195
+ "src/tabbar/index.vue",
196
+ "i18n/files/src/tabbar/index.vue"
197
+ ));
198
+ results.push(injector.replaceFile(
199
+ "src/tabbar/TabbarItem.vue",
200
+ "i18n/files/src/tabbar/TabbarItem.vue"
201
+ ));
202
+ results.push(injector.replaceFile(
203
+ "src/utils/index.ts",
204
+ "i18n/files/src/utils/index.ts"
205
+ ));
206
+ results.push(injector.replaceFile(
207
+ "src/store/token.ts",
208
+ "i18n/files/src/store/token.ts"
209
+ ));
210
+ const i18nFiles = [
211
+ "src/locale/index.ts",
212
+ "src/locale/en.json",
213
+ "src/locale/zh-Hans.json",
214
+ "src/locale/README.md",
215
+ "src/utils/i18n.ts",
216
+ "src/types/i18n.d.ts",
217
+ "src/tabbar/i18n.ts",
218
+ "src/pages/i18n/index.vue"
219
+ ];
220
+ for (const file of i18nFiles) {
221
+ const featurePath = `i18n/files/${file}`;
222
+ results.push(injector.createFile(file, featurePath));
223
+ }
224
+ return results;
225
+ }
226
+ async function injectLogin(projectPath) {
227
+ const results = [];
228
+ const injector = new FeatureInjector(projectPath);
229
+ results.push(injector.replaceFile(
230
+ "src/router/interceptor.ts",
231
+ "login/files/src/router/interceptor.ts"
232
+ ));
233
+ results.push(injector.replaceFile(
234
+ "src/router/config.ts",
235
+ "login/files/src/router/config.ts"
236
+ ));
237
+ results.push(injector.replaceFile(
238
+ "src/pages/me/me.vue",
239
+ "login/files/src/pages/me.vue"
240
+ ));
241
+ const loginFiles = [
242
+ "src/pages/auth/login.vue",
243
+ "src/pages/auth/register.vue",
244
+ "src/pages/auth/README.md"
245
+ ];
246
+ for (const file of loginFiles) {
247
+ const featurePath = `login/files/${file}`;
248
+ results.push(injector.createFile(file, featurePath));
249
+ }
250
+ return results;
251
+ }
9
252
 
10
253
  // src/utils/logger.ts
11
254
  import { bold, green, red, yellow, cyan } from "kolorist";
@@ -32,6 +275,178 @@ var logger = {
32
275
  }
33
276
  };
34
277
 
278
+ // src/utils/readPackageJson.ts
279
+ import fs3 from "fs";
280
+ function readPackageJson(pkgPath) {
281
+ if (!fs3.existsSync(pkgPath)) {
282
+ throw new Error(`package.json not found: ${pkgPath}`);
283
+ }
284
+ const content = fs3.readFileSync(pkgPath, "utf-8");
285
+ return JSON.parse(content);
286
+ }
287
+ function writePackageJson(pkgPath, pkg) {
288
+ fs3.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
289
+ `);
290
+ }
291
+
292
+ // src/commands/add.ts
293
+ function getFeatureStatusFromPackageJson(pkgPath) {
294
+ try {
295
+ const pkg = readPackageJson(pkgPath);
296
+ return {
297
+ i18n: pkg.unibest?.i18n === true,
298
+ login: pkg.unibest?.loginStrategy === true
299
+ };
300
+ } catch {
301
+ return { i18n: false, login: false };
302
+ }
303
+ }
304
+ function updatePackageJsonForFeature(pkgPath, featureName) {
305
+ const pkg = readPackageJson(pkgPath);
306
+ if (!pkg.unibest) {
307
+ pkg.unibest = {};
308
+ }
309
+ switch (featureName) {
310
+ case "i18n":
311
+ pkg.unibest.i18n = true;
312
+ break;
313
+ case "login":
314
+ pkg.unibest.loginStrategy = true;
315
+ break;
316
+ }
317
+ writePackageJson(pkgPath, pkg);
318
+ }
319
+ async function checkFeatureStatus(projectPath) {
320
+ const pkgPath = path3.join(projectPath, "package.json");
321
+ const statusFromPkg = getFeatureStatusFromPackageJson(pkgPath);
322
+ return [
323
+ { name: "i18n", enabled: statusFromPkg.i18n },
324
+ { name: "login", enabled: statusFromPkg.login }
325
+ ];
326
+ }
327
+ async function addFeature(featureName, projectPath, options = {}) {
328
+ const feature = getFeatureByName(featureName);
329
+ if (!feature) {
330
+ logger.error(`\u672A\u77E5\u7684 Feature: ${featureName}`);
331
+ return false;
332
+ }
333
+ const pkgPath = path3.join(projectPath, "package.json");
334
+ const pkg = readPackageJson(pkgPath);
335
+ let alreadyAdded = false;
336
+ if (featureName === "i18n" && pkg.unibest?.i18n === true) {
337
+ alreadyAdded = true;
338
+ } else if (featureName === "login" && pkg.unibest?.loginStrategy === true) {
339
+ alreadyAdded = true;
340
+ }
341
+ if (alreadyAdded && !options.force) {
342
+ logger.warn(`Feature ${featureName} \u5DF2\u6DFB\u52A0\u8FC7\uFF0C\u5982\u9700\u91CD\u65B0\u6CE8\u5165\u8BF7\u4F7F\u7528 --force \u53C2\u6570`);
343
+ return true;
344
+ }
345
+ log.info(`\u6B63\u5728\u6DFB\u52A0 Feature: ${green2(featureName)} - ${feature.description}`);
346
+ try {
347
+ let results;
348
+ switch (featureName) {
349
+ case "i18n":
350
+ results = await injectI18n(projectPath);
351
+ break;
352
+ case "login":
353
+ results = await injectLogin(projectPath);
354
+ break;
355
+ default:
356
+ logger.error(`\u4E0D\u652F\u6301\u7684 Feature: ${featureName}`);
357
+ return false;
358
+ }
359
+ for (const result of results) {
360
+ if (result.success) {
361
+ logger.success(result.message);
362
+ } else {
363
+ logger.warn(result.message);
364
+ }
365
+ }
366
+ const hooks = await loadFeatureHooks(featureName);
367
+ if (hooks?.postApply) {
368
+ await hooks.postApply({
369
+ options: { projectName: "", platforms: [], uiLibrary: "none", i18n: true, loginStrategy: true },
370
+ projectPath,
371
+ featureName
372
+ });
373
+ }
374
+ updatePackageJsonForFeature(pkgPath, featureName);
375
+ logger.success(`\u5DF2\u66F4\u65B0 package.json \u7684 unibest \u914D\u7F6E`);
376
+ if (feature.dependencies && Object.keys(feature.dependencies).length > 0) {
377
+ logger.info(`\u5B89\u88C5\u4F9D\u8D56: ${Object.keys(feature.dependencies).join(", ")}`);
378
+ }
379
+ logger.success(`Feature ${featureName} \u6DFB\u52A0\u6210\u529F\uFF01`);
380
+ return true;
381
+ } catch (error) {
382
+ logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`);
383
+ return false;
384
+ }
385
+ }
386
+ async function addCommand(args) {
387
+ const options = {
388
+ path: args.path || args.p || ".",
389
+ feature: args._[1] || args.feature || args.f,
390
+ force: args.force || args.f
391
+ };
392
+ intro(bold2(green2(`create-unibest@v${version} \u6DFB\u52A0 Feature`)));
393
+ const projectPath = path3.isAbsolute(options.path) ? options.path : path3.join(process2.cwd(), options.path);
394
+ const pkgPath = path3.join(projectPath, "package.json");
395
+ if (!fs4.existsSync(pkgPath)) {
396
+ logger.error(`\u9879\u76EE\u4E0D\u5B58\u5728: ${projectPath}`);
397
+ process2.exit(1);
398
+ }
399
+ const pkg = readPackageJson(pkgPath);
400
+ if (pkg.name !== "unibest") {
401
+ logger.warn(`\u5F53\u524D\u9879\u76EE\u53EF\u80FD\u4E0D\u662F unibest \u9879\u76EE: ${pkg.name}`);
402
+ }
403
+ const availableFeatures = getAvailableFeatureNames();
404
+ try {
405
+ if (!options.feature) {
406
+ const detected = await checkFeatureStatus(projectPath);
407
+ const available = availableFeatures.filter((f) => !detected.find((d) => d.name === f && d.enabled));
408
+ if (available.length === 0) {
409
+ logger.info("\u6240\u6709\u53EF\u7528 Feature \u5DF2\u542F\u7528");
410
+ return;
411
+ }
412
+ const selectedFeatures = await multiselect({
413
+ message: `\u8BF7\u9009\u62E9\u8981\u6DFB\u52A0\u7684 Feature`,
414
+ options: available.map((name) => {
415
+ const feature = getFeatureByName(name);
416
+ return {
417
+ value: name,
418
+ label: feature?.name || name,
419
+ hint: feature?.description || ""
420
+ };
421
+ }),
422
+ required: false
423
+ });
424
+ if (isCancel(selectedFeatures)) {
425
+ cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
426
+ process2.exit(0);
427
+ }
428
+ if (!Array.isArray(selectedFeatures) || selectedFeatures.length === 0) {
429
+ logger.info("\u672A\u9009\u62E9\u4EFB\u4F55 Feature");
430
+ return;
431
+ }
432
+ for (const featureName of selectedFeatures) {
433
+ await addFeature(featureName, projectPath, options);
434
+ }
435
+ } else {
436
+ const features = Array.isArray(options.feature) ? options.feature : [options.feature];
437
+ for (const featureName of features) {
438
+ await addFeature(featureName, projectPath, options);
439
+ }
440
+ }
441
+ } catch (error) {
442
+ logger.error(`\u6DFB\u52A0 Feature \u5931\u8D25: ${error.message}`);
443
+ process2.exit(1);
444
+ }
445
+ }
446
+
447
+ // src/commands/create/prompts.ts
448
+ import { text, multiselect as multiselect2, select, confirm, cancel as cancel2, isCancel as isCancel2 } from "@clack/prompts";
449
+
35
450
  // src/utils/validate.ts
36
451
  import { existsSync } from "fs";
37
452
  import { yellow as yellow2 } from "kolorist";
@@ -58,12 +473,56 @@ function checkProjectNameExistAndValidate(_projectName) {
58
473
  }
59
474
 
60
475
  // src/commands/create/prompts.ts
61
- import { green as green2 } from "kolorist";
476
+ import { green as green3, red as red2 } from "kolorist";
477
+ import process3 from "process";
478
+ var VALID_PLATFORMS = ["h5", "mp-weixin", "app", "mp-alipay", "mp-toutiao"];
479
+ var VALID_UI_LIBRARIES = ["none", "wot-ui", "uview-pro", "sard-uniapp", "uv-ui", "uview-plus"];
62
480
  async function promptUser(projectName, argv = {}) {
481
+ let platforms;
482
+ let uiLibrary;
483
+ let loginStrategy;
484
+ let i18n;
485
+ const platformArg = argv.p || argv.platform;
486
+ if (platformArg) {
487
+ let parsedPlatforms = [];
488
+ if (Array.isArray(platformArg)) {
489
+ parsedPlatforms = platformArg;
490
+ } else if (typeof platformArg === "string") {
491
+ parsedPlatforms = platformArg.split(",");
492
+ }
493
+ const invalidPlatforms = parsedPlatforms.filter((p) => !VALID_PLATFORMS.includes(p));
494
+ if (invalidPlatforms.length > 0) {
495
+ console.error(red2(`\u65E0\u6548\u7684\u5E73\u53F0\u53C2\u6570: ${invalidPlatforms.join(", ")}`));
496
+ console.error(red2(`\u53EF\u9009\u503C: ${VALID_PLATFORMS.join(", ")}`));
497
+ process3.exit(1);
498
+ }
499
+ platforms = parsedPlatforms;
500
+ }
501
+ const uiArg = argv.u || argv.ui;
502
+ if (uiArg) {
503
+ if (!VALID_UI_LIBRARIES.includes(uiArg)) {
504
+ console.error(red2(`\u65E0\u6548\u7684UI\u5E93\u53C2\u6570: ${uiArg}`));
505
+ console.error(red2(`\u53EF\u9009\u503C: ${VALID_UI_LIBRARIES.join(", ")}`));
506
+ process3.exit(1);
507
+ }
508
+ uiLibrary = uiArg;
509
+ }
510
+ const loginArg = argv.l ?? argv.login;
511
+ if (loginArg === true || loginArg === "true") {
512
+ loginStrategy = true;
513
+ } else if (loginArg === false || loginArg === "false") {
514
+ loginStrategy = false;
515
+ }
516
+ const i18nArg = argv.i ?? argv.i18n;
517
+ if (i18nArg === true || i18nArg === "true") {
518
+ i18n = true;
519
+ } else if (i18nArg === false || i18nArg === "false") {
520
+ i18n = false;
521
+ }
63
522
  try {
64
523
  if (!projectName) {
65
524
  const inputProjectName = await text({
66
- message: `\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0${green2("[\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]")}`,
525
+ 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]")}`,
67
526
  initialValue: "",
68
527
  validate: (value) => {
69
528
  if (!value.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
@@ -72,60 +531,72 @@ async function promptUser(projectName, argv = {}) {
72
531
  return;
73
532
  }
74
533
  });
75
- if (isCancel(inputProjectName)) {
76
- cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
77
- process.exit(0);
534
+ if (isCancel2(inputProjectName)) {
535
+ cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
536
+ process3.exit(0);
78
537
  }
79
538
  projectName = inputProjectName;
80
539
  }
81
- const platforms = await multiselect({
82
- message: `\u8BF7\u9009\u62E9\u9700\u8981\u652F\u6301\u7684\u5E73\u53F0\uFF08\u591A\u9009\uFF09${green2("[\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]")}`,
83
- options: [
84
- { value: "h5", label: "H5" },
85
- { value: "mp-weixin", label: "\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F" },
86
- { value: "app", label: "APP" },
87
- { value: "mp-alipay", label: "\u652F\u4ED8\u5B9D\u5C0F\u7A0B\u5E8F\uFF08\u5305\u542B\u9489\u9489\uFF09" },
88
- { value: "mp-toutiao", label: "\u6296\u97F3\u5C0F\u7A0B\u5E8F" }
89
- ],
90
- initialValues: ["h5"],
91
- // 默认选择 H5
92
- required: true
93
- });
94
- if (isCancel(platforms)) {
95
- cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
96
- process.exit(0);
97
- }
98
- const uiLibrary = await select({
99
- message: "\u8BF7\u9009\u62E9UI\u5E93",
100
- options: [
101
- { value: "none", label: "\u65E0UI\u5E93" },
102
- { value: "wot-ui", label: "wot-ui" },
103
- { value: "uview-pro", label: "uview-pro" },
104
- { value: "sard-uniapp", label: "sard-uniapp" },
105
- { value: "uv-ui", label: "uv-ui" },
106
- { value: "uview-plus", label: "uview-plus" }
107
- ],
108
- initialValue: "none"
109
- });
110
- if (isCancel(uiLibrary)) {
111
- cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
112
- process.exit(0);
540
+ if (!platforms) {
541
+ const selectedPlatforms = await multiselect2({
542
+ 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]")}`,
543
+ options: [
544
+ { value: "h5", label: "H5" },
545
+ { value: "mp-weixin", label: "\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F" },
546
+ { value: "app", label: "APP" },
547
+ { value: "mp-alipay", label: "\u652F\u4ED8\u5B9D\u5C0F\u7A0B\u5E8F\uFF08\u5305\u542B\u9489\u9489\uFF09" },
548
+ { value: "mp-toutiao", label: "\u6296\u97F3\u5C0F\u7A0B\u5E8F" }
549
+ ],
550
+ initialValues: ["h5"],
551
+ // 默认选择 H5
552
+ required: true
553
+ });
554
+ if (isCancel2(selectedPlatforms)) {
555
+ cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
556
+ process3.exit(0);
557
+ }
558
+ platforms = selectedPlatforms;
113
559
  }
114
- const loginStrategy = await confirm({
115
- message: `\u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09\uFF1F${green2("[\u6682\u4E0D\u77E5\u9053\u7684\uFF0C\u9009No\u5373\u53EF\uFF0C\u9879\u76EE\u751F\u6210\u540E\u4E5F\u53EF\u4EE5\u52A0\u8BE5\u7B56\u7565]")}`,
116
- initialValue: false
117
- });
118
- if (isCancel(loginStrategy)) {
119
- cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
120
- process.exit(0);
560
+ if (!uiLibrary) {
561
+ const selectedUiLibrary = await select({
562
+ message: "\u8BF7\u9009\u62E9UI\u5E93",
563
+ options: [
564
+ { value: "none", label: "\u65E0UI\u5E93" },
565
+ { value: "wot-ui", label: "wot-ui" },
566
+ { value: "uview-pro", label: "uview-pro" },
567
+ { value: "sard-uniapp", label: "sard-uniapp" },
568
+ { value: "uv-ui", label: "uv-ui" },
569
+ { value: "uview-plus", label: "uview-plus" }
570
+ ],
571
+ initialValue: "none"
572
+ });
573
+ if (isCancel2(selectedUiLibrary)) {
574
+ cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
575
+ process3.exit(0);
576
+ }
577
+ uiLibrary = selectedUiLibrary;
121
578
  }
122
- const i18n = await confirm({
123
- message: "\u662F\u5426\u9700\u8981\u591A\u8BED\u8A00i18n\uFF1F",
124
- initialValue: false
125
- });
126
- if (isCancel(i18n)) {
127
- cancel("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
128
- process.exit(0);
579
+ if (loginStrategy === void 0) {
580
+ const selectedLoginStrategy = await confirm({
581
+ 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]")}`,
582
+ initialValue: false
583
+ });
584
+ if (isCancel2(selectedLoginStrategy)) {
585
+ cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
586
+ process3.exit(0);
587
+ }
588
+ loginStrategy = selectedLoginStrategy;
589
+ }
590
+ if (i18n === void 0) {
591
+ const selectedI18n = await confirm({
592
+ message: "\u662F\u5426\u9700\u8981\u591A\u8BED\u8A00i18n\uFF1F",
593
+ initialValue: false
594
+ });
595
+ if (isCancel2(selectedI18n)) {
596
+ cancel2("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
597
+ process3.exit(0);
598
+ }
599
+ i18n = selectedI18n;
129
600
  }
130
601
  return {
131
602
  projectName,
@@ -139,49 +610,106 @@ async function promptUser(projectName, argv = {}) {
139
610
  };
140
611
  } catch (error) {
141
612
  logger.error(`\u8BE2\u95EE\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
142
- process.exit(1);
613
+ process3.exit(1);
143
614
  }
144
615
  }
145
616
 
146
617
  // src/commands/create/generate.ts
147
- import process3 from "process";
148
- import { log } from "@clack/prompts";
618
+ import process5 from "process";
619
+ import { log as log2 } from "@clack/prompts";
149
620
 
150
621
  // src/utils/cloneRepo.ts
151
622
  import { exec } from "child_process";
152
- import { promises as fs } from "fs";
153
- import { join as join3 } from "path";
154
- import process2 from "process";
155
- import { red as red2 } from "kolorist";
623
+ import { promises as fsPromises } from "fs";
624
+ import { join as join3, dirname as dirname2 } from "path";
625
+ import { fileURLToPath as fileURLToPath2 } from "url";
626
+ import process4 from "process";
627
+ import { red as red3 } from "kolorist";
156
628
 
157
629
  // src/utils/replacePackageJson.ts
158
630
  import { readFileSync, writeFileSync } from "fs";
159
631
  import { join as join2 } from "path";
160
- function replaceContent(filePath, projectName, version2) {
632
+ import dayjs from "dayjs";
633
+ function replaceContent(filePath, projectName, version2, options) {
161
634
  const fileContent = JSON.parse(readFileSync(filePath, "utf8"));
162
- fileContent.name = projectName;
163
- fileContent.version = version2;
164
- writeFileSync(filePath, JSON.stringify(fileContent, null, 2));
635
+ const unibestVersion = fileContent["unibest-version"];
636
+ const unibestUpdateTime = fileContent["unibest-update-time"];
637
+ delete fileContent["unibest-version"];
638
+ delete fileContent["unibest-update-time"];
639
+ delete fileContent.metadata;
640
+ delete fileContent.name;
641
+ delete fileContent.version;
642
+ const { projectName: _, ...restOptions } = options;
643
+ const selectedFeatures = getSelectedFeatures(options);
644
+ const featureDeps = {};
645
+ for (const feature of selectedFeatures) {
646
+ if (feature.dependencies) {
647
+ Object.assign(featureDeps, feature.dependencies);
648
+ }
649
+ }
650
+ if (!fileContent.dependencies) {
651
+ fileContent.dependencies = {};
652
+ }
653
+ for (const [pkg, ver] of Object.entries(featureDeps)) {
654
+ if (!fileContent.dependencies[pkg]) {
655
+ fileContent.dependencies[pkg] = ver;
656
+ }
657
+ }
658
+ const newContent = {
659
+ name: projectName,
660
+ type: fileContent.type,
661
+ // 保持 type 在前(如果存在)
662
+ version: version2,
663
+ unibest: {
664
+ ...restOptions,
665
+ cliVersion: version,
666
+ unibestVersion,
667
+ unibestUpdateTime,
668
+ createdAt: dayjs().format("YYYY-MM-DD HH:mm:ss")
669
+ },
670
+ ...fileContent
671
+ // 剩余字段
672
+ };
673
+ writeFileSync(filePath, JSON.stringify(newContent, null, 2));
165
674
  }
166
- function replacePackageJson(root2, name, version2) {
675
+ function replacePackageJson(root2, name, version2, options) {
167
676
  const projectName = name.toLocaleLowerCase().replace(/\s/g, "-");
168
677
  const pkgPath = join2(root2, "package.json");
169
- replaceContent(pkgPath, projectName, version2);
678
+ replaceContent(pkgPath, projectName, version2, options);
170
679
  }
171
680
 
172
681
  // src/utils/cloneRepo.ts
682
+ var __filename2 = fileURLToPath2(import.meta.url);
683
+ var __dirname2 = dirname2(__filename2);
684
+ var USE_LOCAL_TEMPLATE = process4.env.LOCAL_TEMPLATE === "true";
685
+ var TEMPLATE_BASE_PATH = null;
686
+ async function getTemplateBasePath() {
687
+ if (TEMPLATE_BASE_PATH) return TEMPLATE_BASE_PATH;
688
+ const candidates = [
689
+ join3(__dirname2, "..", "..", "..", "packages", "template-base"),
690
+ join3(__dirname2, "..", "..", "packages", "template-base")
691
+ ];
692
+ const { existsSync: existsSync3 } = await import("fs");
693
+ for (const candidate of candidates) {
694
+ if (existsSync3(candidate)) {
695
+ TEMPLATE_BASE_PATH = candidate;
696
+ return candidate;
697
+ }
698
+ }
699
+ throw new Error("\u65E0\u6CD5\u627E\u5230 template-base \u76EE\u5F55");
700
+ }
173
701
  async function removeGitFolder(localPath) {
174
702
  const gitFolderPath = join3(localPath, ".git");
175
- await fs.rm(gitFolderPath, { recursive: true, force: true });
703
+ await fsPromises.rm(gitFolderPath, { recursive: true, force: true });
176
704
  }
177
- var REPO_URL = "https://github.com/unibest-tech/unibest.git";
705
+ var REPO_URL = "https://gitee.com/feige996/unibest.git";
178
706
  async function cloneRepo(projectName, branch) {
179
707
  try {
180
708
  await new Promise((resolve, reject) => {
181
709
  const execStr = `git clone --depth=1 -b ${branch} ${REPO_URL} "${projectName}"`;
182
710
  exec(execStr, async (error) => {
183
711
  if (error) {
184
- console.error(`${red2("exec error:")} ${error}`);
712
+ console.error(`${red3("exec error:")} ${error}`);
185
713
  reject(error);
186
714
  return;
187
715
  }
@@ -195,19 +723,40 @@ async function cloneRepo(projectName, branch) {
195
723
  });
196
724
  return;
197
725
  } catch (error) {
198
- console.error(`${red2("cloneRepo error:")} ${error}`);
726
+ console.error(`${red3("cloneRepo error:")} ${error}`);
199
727
  throw new Error("cloneRepo error");
200
728
  }
201
729
  }
202
- async function cloneRepoByBranch(root2, name, branch) {
730
+ async function copyLocalTemplate(projectName) {
731
+ const projectPath = join3(process4.cwd(), projectName);
732
+ const sourcePath = await getTemplateBasePath();
733
+ await new Promise((resolve, reject) => {
734
+ const execStr = `cp -r "${sourcePath}/." "${projectPath}/"`;
735
+ exec(execStr, (error) => {
736
+ if (error) {
737
+ reject(error);
738
+ } else {
739
+ resolve();
740
+ }
741
+ });
742
+ });
743
+ return projectPath;
744
+ }
745
+ async function cloneRepoByBranch(root2, name, branch, options) {
203
746
  try {
204
- await cloneRepo(name, branch);
747
+ if (USE_LOCAL_TEMPLATE) {
748
+ console.log("\u4F7F\u7528\u672C\u5730\u6A21\u677F\u6D4B\u8BD5...");
749
+ await copyLocalTemplate(name);
750
+ } else {
751
+ console.log("\u4ECE Git \u514B\u9686\u57FA\u7840\u6A21\u677F...");
752
+ await cloneRepo(name, "base");
753
+ }
205
754
  } catch (error) {
206
- console.error(`${red2(`\u6A21\u677F\u7C7B\u578B${branch}\u4E0B\u8F7D\u5931\u8D25\uFF01`)} ${error}`);
207
- process2.exit(1);
755
+ console.error(`${red3(`\u6A21\u677F\u4E0B\u8F7D\u5931\u8D25\uFF01`)} ${error}`);
756
+ process4.exit(1);
208
757
  }
209
758
  const projectPath = join3(root2, name);
210
- replacePackageJson(projectPath, name, "1.0.0");
759
+ replacePackageJson(projectPath, name, "1.0.0", options);
211
760
  }
212
761
 
213
762
  // src/utils/uiLibrary.ts
@@ -566,25 +1115,36 @@ function debug(...args) {
566
1115
  }
567
1116
 
568
1117
  // src/commands/create/generate.ts
569
- import path from "path";
570
- var root = process3.cwd();
1118
+ import path4 from "path";
1119
+ var root = process5.cwd();
571
1120
  async function generateProject(options) {
572
1121
  debug("generateProject options", options);
573
1122
  const { projectName, platforms, uiLibrary, loginStrategy, i18n } = options;
574
- if (!loginStrategy && !i18n) {
575
- debug("\u62C9\u53D6 base \u5206\u652F");
576
- await cloneRepoByBranch(root, projectName, "base");
577
- } else if (!loginStrategy && i18n) {
578
- debug("\u62C9\u53D6 base-i18n \u5206\u652F");
579
- await cloneRepoByBranch(root, projectName, "base-i18n");
580
- } else if (loginStrategy && !i18n) {
581
- debug("\u62C9\u53D6 base-login \u5206\u652F");
582
- await cloneRepoByBranch(root, projectName, "base-login");
583
- } else if (loginStrategy && i18n) {
584
- debug("\u62C9\u53D6 base-login-i18n \u5206\u652F");
585
- await cloneRepoByBranch(root, projectName, "base-login-i18n");
586
- }
587
- const projectPath = path.join(root, projectName);
1123
+ const projectPath = path4.join(root, projectName);
1124
+ debug("\u62C9\u53D6 base \u5206\u652F");
1125
+ await cloneRepoByBranch(root, projectName, "base", options);
1126
+ if (i18n) {
1127
+ debug("\u6CE8\u5165 i18n feature");
1128
+ const results = await injectI18n(projectPath);
1129
+ for (const result of results) {
1130
+ if (result.success) {
1131
+ debug(result.message);
1132
+ } else {
1133
+ logger.warn(result.message);
1134
+ }
1135
+ }
1136
+ }
1137
+ if (loginStrategy) {
1138
+ debug("\u6CE8\u5165 login feature");
1139
+ const results = await injectLogin(projectPath);
1140
+ for (const result of results) {
1141
+ if (result.success) {
1142
+ debug(result.message);
1143
+ } else {
1144
+ logger.warn(result.message);
1145
+ }
1146
+ }
1147
+ }
588
1148
  if (uiLibrary === "none") {
589
1149
  debug("\u4E0D\u5F15\u5165\u4EFB\u4F55UI\u5E93");
590
1150
  } else {
@@ -597,8 +1157,18 @@ async function generateProject(options) {
597
1157
  logger.info("\u60A8\u53EF\u4EE5\u5728\u9879\u76EE\u521B\u5EFA\u540E\u624B\u52A8\u914D\u7F6E UI \u5E93");
598
1158
  }
599
1159
  }
1160
+ const selectedFeatures = getSelectedFeatures(options);
1161
+ const allDeps = {};
1162
+ for (const feature of selectedFeatures) {
1163
+ if (feature.dependencies) {
1164
+ Object.assign(allDeps, feature.dependencies);
1165
+ }
1166
+ }
1167
+ if (Object.keys(allDeps).length > 0) {
1168
+ logger.info(`Feature \u4F9D\u8D56: ${Object.keys(allDeps).join(", ")}`);
1169
+ }
600
1170
  try {
601
- log.success(`\u9879\u76EE${projectName}\u521B\u5EFA\u6210\u529F\uFF01`);
1171
+ log2.success(`\u9879\u76EE${projectName}\u521B\u5EFA\u6210\u529F\uFF01`);
602
1172
  logger.info("\u4E0B\u4E00\u6B65:");
603
1173
  logger.info(` cd ${projectName}`);
604
1174
  logger.info(" pnpm i");
@@ -611,67 +1181,19 @@ async function generateProject(options) {
611
1181
  }
612
1182
  }
613
1183
 
614
- // package.json
615
- var version = "3.2.1";
616
- var package_default = {
617
- name: "create-unibest",
618
- type: "module",
619
- version,
620
- packageManager: "pnpm@9.0.0",
621
- description: "\u5FEB\u901F\u521B\u5EFAunibest\u9879\u76EE\u7684\u811A\u624B\u67B6\u5DE5\u5177",
622
- author: "",
623
- license: "ISC",
624
- keywords: [],
625
- main: "dist/index.js",
626
- bin: {
627
- best: "bin/index.js",
628
- "create-unibest": "bin/index.js"
629
- },
630
- files: [
631
- "bin",
632
- "dist"
633
- ],
634
- scripts: {
635
- dev: "cross-env NODE_ENV=development tsup --watch",
636
- build: "cross-env NODE_ENV=production tsup",
637
- prepare: "cross-env NODE_ENV=production npm run build",
638
- start: "cross-env NODE_ENV=development node bin/index.js"
639
- },
640
- dependencies: {
641
- "@clack/prompts": "^0.11.0",
642
- dayjs: "^1.11.18",
643
- ejs: "^3.1.10",
644
- "fs-extra": "^11.3.0",
645
- kolorist: "^1.8.0",
646
- minimist: "^1.2.8",
647
- "node-fetch": "^3.3.2"
648
- },
649
- devDependencies: {
650
- "@types/ejs": "^3.1.5",
651
- "@types/fs-extra": "^11.0.4",
652
- "@types/minimist": "^1.2.5",
653
- "@types/node": "^24.5.0",
654
- "cross-env": "^7.0.3",
655
- tsup: "^8.5.0",
656
- typescript: "^5.9.0"
657
- }
658
- };
659
-
660
1184
  // src/commands/create.ts
661
- import { intro, log as log2 } from "@clack/prompts";
662
- import { bold as bold3, yellow as yellow3, green as green3 } from "kolorist";
1185
+ import { intro as intro2, log as log3 } from "@clack/prompts";
1186
+ import { bold as bold3, yellow as yellow3, green as green4 } from "kolorist";
663
1187
 
664
1188
  // src/utils/unibestVersion.ts
665
1189
  import fetch from "node-fetch";
666
- async function getUnibestVersionFromGithub() {
1190
+ async function getUnibestVersionFromGitee() {
667
1191
  try {
668
- const apiUrl = `https://api.github.com/repos/feige996/unibest/contents/package.json?ref=main`;
1192
+ const apiUrl = `https://gitee.com/api/v5/repos/feige996/unibest/contents/package.json?ref=main`;
669
1193
  const response = await fetch(apiUrl, {
670
1194
  method: "GET",
671
1195
  headers: {
672
- "Content-Type": "application/json",
673
- // GitHub API 要求 User-Agent 头
674
- "User-Agent": "unibest-cli"
1196
+ "Content-Type": "application/json"
675
1197
  }
676
1198
  });
677
1199
  if (response.ok) {
@@ -694,12 +1216,12 @@ async function getUnibestVersionFromGithub() {
694
1216
 
695
1217
  // src/utils/beacon.ts
696
1218
  import fetch2 from "node-fetch";
697
- import dayjs from "dayjs";
1219
+ import dayjs2 from "dayjs";
698
1220
  import os from "os";
699
1221
  import crypto from "crypto";
700
1222
  async function beacon(options) {
701
1223
  try {
702
- const unibestVersion = await getUnibestVersionFromGithub();
1224
+ const unibestVersion = await getUnibestVersionFromGitee();
703
1225
  const deviceIdentifier = generateDeviceIdentifier();
704
1226
  await fetch2("https://ukw0y1.laf.run/create-unibest-v3/beacon", {
705
1227
  method: "POST",
@@ -710,7 +1232,7 @@ async function beacon(options) {
710
1232
  ...options,
711
1233
  version: unibestVersion,
712
1234
  cbVersion: package_default.version,
713
- createAt: dayjs().format("YYYY-MM-DD HH:mm:ss"),
1235
+ createAt: dayjs2().format("YYYY-MM-DD HH:mm:ss"),
714
1236
  nodeVersion: process.version,
715
1237
  osPlatform: process.platform,
716
1238
  cpuModel: os.cpus()[0]?.model || "unknown",
@@ -737,12 +1259,12 @@ function generateDeviceIdentifier() {
737
1259
  // src/commands/create.ts
738
1260
  async function createCommand(args) {
739
1261
  const projectName = args._[1] || args._[0];
740
- const versionUnibest = await getUnibestVersionFromGithub() || "4.0.0";
741
- intro(bold3(green3(`create-unibest@v${version} \u5FEB\u901F\u521B\u5EFA ${yellow3(`unibest@v${versionUnibest}`)} \u9879\u76EE`)));
1262
+ const versionUnibest = await getUnibestVersionFromGitee() || "4.0.0";
1263
+ intro2(bold3(green4(`create-unibest@v${version} \u5FEB\u901F\u521B\u5EFA ${yellow3(`unibest@v${versionUnibest}`)} \u9879\u76EE`)));
742
1264
  if (projectName) {
743
1265
  const errorMessage = checkProjectNameExistAndValidate(projectName);
744
1266
  if (errorMessage) {
745
- log2.error(errorMessage);
1267
+ log3.error(errorMessage);
746
1268
  process.exit(1);
747
1269
  }
748
1270
  }
@@ -751,18 +1273,18 @@ async function createCommand(args) {
751
1273
  await generateProject(projectOptions);
752
1274
  beacon(projectOptions);
753
1275
  } catch (error) {
754
- log2.error(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${error.message}`);
1276
+ log3.error(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${error.message}`);
755
1277
  process.exit(1);
756
1278
  }
757
1279
  }
758
1280
 
759
1281
  // src/utils/color.ts
760
- import { blue, green as green4, magenta as magenta2, red as red3, yellow as yellow4 } from "kolorist";
1282
+ import { blue, green as green5, magenta as magenta2, red as red4, yellow as yellow4 } from "kolorist";
761
1283
  var color = {
762
1284
  blue,
763
- green: green4,
1285
+ green: green5,
764
1286
  magenta: magenta2,
765
- red: red3,
1287
+ red: red4,
766
1288
  yellow: yellow4
767
1289
  };
768
1290
 
@@ -770,29 +1292,57 @@ var color = {
770
1292
  function printHelp() {
771
1293
  console.log(color.green("\ncreate-unibest - \u8DE8\u5E73\u53F0\u5F00\u53D1\u6846\u67B6\u811A\u624B\u67B6"));
772
1294
  console.log("");
773
- console.log(color.blue("\u5168\u5C40\u5B89\u88C5:"));
774
- console.log(color.green(" npm i -g create-unibest \u5168\u5C40\u5B89\u88C5\uFF0C\u5F97\u5230 best \u547D\u4EE4"));
775
- console.log(color.green(" npm update -g create-unibest \u66F4\u65B0 create-unibest \u5305"));
776
- console.log("");
777
- console.log(color.green(" best <command> [options]"));
778
- console.log(color.green(" best new my-project \u521B\u5EFA\u65B0\u7684unibest\u9879\u76EE"));
779
- console.log(color.green(" best -v \u67E5\u770B\u7248\u672C\u4FE1\u606F"));
780
- console.log(color.green(" best -h \u67E5\u770B\u5E2E\u52A9\u4FE1\u606F"));
781
- console.log("");
782
- console.log("");
783
- console.log(color.blue("\u4E34\u65F6\u4F7F\u7528:"));
1295
+ console.log(color.blue("\u5FEB\u901F\u4F7F\u7528:"));
784
1296
  console.log(color.green(" pnpm create unibest <command> [options]"));
785
- console.log(color.green(" pnpm create unibest new my-project \u521B\u5EFA\u65B0\u7684unibest\u9879\u76EE"));
1297
+ console.log(color.green(" pnpm create unibest my-project \u521B\u5EFA\u65B0\u7684unibest\u9879\u76EE"));
1298
+ console.log(color.green(" pnpm create unibest add i18n \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0i18n\u7279\u6027"));
1299
+ console.log(color.green(" pnpm create unibest add login \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0login\u7279\u6027"));
786
1300
  console.log(color.green(" pnpm create unibest -v \u67E5\u770B\u7248\u672C\u4FE1\u606F"));
787
1301
  console.log(color.green(" pnpm create unibest -h \u67E5\u770B\u5E2E\u52A9\u4FE1\u606F"));
788
1302
  console.log("");
1303
+ console.log(color.blue("\u53EF\u7528\u547D\u4EE4:"));
1304
+ console.log(" <projectName> \u521B\u5EFA\u9879\u76EE\uFF08\u4E0D\u7528 new \u5173\u952E\u5B57\uFF09");
1305
+ console.log(" create <projectName> \u521B\u5EFA\u9879\u76EE");
1306
+ console.log(" add <feature> \u4E3A\u5DF2\u6709\u9879\u76EE\u6DFB\u52A0 Feature");
1307
+ console.log("");
1308
+ console.log(color.blue("\u521B\u5EFA\u9879\u76EE\u9009\u9879:"));
1309
+ console.log(" -p, --platform <type> \u6307\u5B9A\u5E73\u53F0 (h5, mp-weixin, app, mp-alipay, mp-toutiao)");
1310
+ console.log(" \u652F\u6301\u591A\u9009: -p h5,mp-weixin \u6216 -p h5 -p mp-weixin");
1311
+ console.log(" -u, --ui <library> \u6307\u5B9AUI\u5E93 (wot-ui, uview-pro, sard-uniapp, uv-ui, uview-plus, none)");
1312
+ console.log(" -l, --login \u662F\u5426\u9700\u8981\u767B\u5F55\u7B56\u7565");
1313
+ console.log(" -i, --i18n \u662F\u5426\u9700\u8981\u591A\u8BED\u8A00");
1314
+ console.log("");
1315
+ console.log(color.blue("\u6DFB\u52A0Feature\u9009\u9879:"));
1316
+ console.log(" <feature> \u8981\u6DFB\u52A0\u7684 Feature (i18n, login)");
1317
+ console.log(" --path <path> \u9879\u76EE\u8DEF\u5F84 (\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55)");
1318
+ console.log(" --force \u5F3A\u5236\u91CD\u65B0\u6CE8\u5165\uFF08\u8986\u76D6\u5DF2\u6709\u914D\u7F6E\uFF09");
1319
+ console.log("");
1320
+ console.log(color.blue("\u53EF\u7528Feature:"));
1321
+ console.log(" i18n \u591A\u8BED\u8A00\u652F\u6301");
1322
+ console.log(" login \u767B\u5F55\u7B56\u7565\uFF08\u9ED1\u767D\u540D\u5355\u3001\u767B\u5F55\u62E6\u622A\u7B49\uFF09");
1323
+ console.log("");
1324
+ console.log(color.blue("\u793A\u4F8B:"));
1325
+ console.log(" # \u521B\u5EFA\u9879\u76EE");
1326
+ console.log(" pnpm create unibest my-project -u wot-ui -p h5,mp-weixin");
1327
+ console.log(" pnpm create unibest my-project -u uview-plus -l -i");
1328
+ console.log(" pnpm create unibest my-project -u none -p h5,app,mp-weixin");
1329
+ console.log("");
1330
+ console.log(" # \u6DFB\u52A0 Feature");
1331
+ console.log(" cd my-project && pnpm create unibest add i18n");
1332
+ console.log(" pnpm create unibest add login --path /path/to/project");
1333
+ console.log(" pnpm create unibest add i18n login");
1334
+ console.log(" pnpm create unibest add i18n --force # \u91CD\u65B0\u6CE8\u5165");
1335
+ console.log("");
1336
+ console.log(" # \u5168\u5C40\u5B89\u88C5");
1337
+ console.log(" npm i -g create-unibest");
1338
+ console.log(" best my-project");
1339
+ console.log(" best add i18n");
1340
+ console.log("");
789
1341
  }
790
1342
 
791
1343
  // src/index.ts
792
- import { green as green5 } from "kolorist";
793
- import { yellow as yellow5 } from "kolorist";
794
1344
  function main() {
795
- const args = minimist(process4.argv.slice(2));
1345
+ const args = minimist(process6.argv.slice(2));
796
1346
  const command = args._[0];
797
1347
  debug("command:", command);
798
1348
  debug("args:", args);
@@ -809,6 +1359,9 @@ function main() {
809
1359
  case "new":
810
1360
  createCommand(args);
811
1361
  break;
1362
+ case "add":
1363
+ addCommand(args);
1364
+ break;
812
1365
  case "-h":
813
1366
  case "--help":
814
1367
  printHelp();
@@ -824,10 +1377,10 @@ function main() {
824
1377
  }
825
1378
  async function printVersion() {
826
1379
  const cliVersion = version;
827
- const latestVersion = await getUnibestVersionFromGithub();
1380
+ const latestVersion = await getUnibestVersionFromGitee();
828
1381
  if (latestVersion && latestVersion !== cliVersion) {
829
- console.log(`unibest-cli ${cliVersion} ${yellow5(`->`)} ${green5(`\u6700\u65B0\u7248\u672C: ${latestVersion}`)}`);
830
- console.log(`\u4F7F\u7528 ${green5(`npm update -g create-unibest`)} \u6216 ${green5(`pnpm add -g create-unibest`)} \u66F4\u65B0`);
1382
+ console.log(`unibest-cli ${cliVersion} ${yellow5(`->`)} ${green6(`\u6700\u65B0\u7248\u672C: ${latestVersion}`)}`);
1383
+ console.log(`\u4F7F\u7528 ${green6(`npm update -g create-unibest`)} \u6216 ${green6(`pnpm add -g create-unibest`)} \u66F4\u65B0`);
831
1384
  console.log();
832
1385
  } else {
833
1386
  console.log(`unibest-cli ${cliVersion}`);
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "create-unibest",
3
3
  "type": "module",
4
- "version": "3.2.1",
5
- "packageManager": "pnpm@9.0.0",
6
- "description": "快速创建unibest项目的脚手架工具",
7
- "author": "",
8
- "license": "ISC",
9
- "keywords": [],
10
- "main": "dist/index.js",
4
+ "version": "4.0.0",
5
+ "packageManager": "pnpm@10.10.0",
6
+ "description": "快速创建 unibest 项目的脚手架工具",
7
+ "author": "feige996",
8
+ "license": "MIT",
9
+ "homepage": "https://unibest.tech",
11
10
  "bin": {
12
11
  "best": "bin/index.js",
13
- "create-unibest": "bin/index.js"
12
+ "create-unibest": "bin/index.js",
13
+ "unibest": "bin/index.js"
14
14
  },
15
15
  "files": [
16
16
  "bin",
@@ -19,7 +19,7 @@
19
19
  "scripts": {
20
20
  "dev": "cross-env NODE_ENV=development tsup --watch",
21
21
  "build": "cross-env NODE_ENV=production tsup",
22
- "prepare": "cross-env NODE_ENV=production npm run build",
22
+ "prepare": "pnpm build",
23
23
  "start": "cross-env NODE_ENV=development node bin/index.js"
24
24
  },
25
25
  "dependencies": {
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- #!/usr/bin/env node