neo-cmp-cli 1.5.6 → 1.6.0-beta.3

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.
Files changed (48) hide show
  1. package/README.md +62 -47
  2. package/package.json +1 -1
  3. package/src/module/index.js +74 -19
  4. package/src/module/main.js +167 -267
  5. package/src/module/neoInit.js +1 -0
  6. package/src/neo/NeoUMDContent.js +6 -5
  7. package/src/neo/neoService.js +150 -43
  8. package/src/oss/publish2oss.js +174 -71
  9. package/src/template/antd-custom-cmp-template/README.md +26 -2
  10. package/src/template/antd-custom-cmp-template/neo.config.js +7 -4
  11. package/src/template/antd-custom-cmp-template/package.json +1 -0
  12. package/src/template/echarts-custom-cmp-template/README.md +26 -2
  13. package/src/template/echarts-custom-cmp-template/neo.config.js +9 -5
  14. package/src/template/echarts-custom-cmp-template/package.json +1 -0
  15. package/src/template/empty-custom-cmp-template/README.md +26 -0
  16. package/src/template/empty-custom-cmp-template/neo.config.js +7 -4
  17. package/src/template/empty-custom-cmp-template/package.json +1 -0
  18. package/src/template/neo-custom-cmp-template/README.md +26 -2
  19. package/src/template/neo-custom-cmp-template/neo.config.js +12 -9
  20. package/src/template/neo-custom-cmp-template/package.json +2 -1
  21. package/src/template/react-custom-cmp-template/README.md +26 -2
  22. package/src/template/react-custom-cmp-template/neo.config.js +7 -4
  23. package/src/template/react-custom-cmp-template/package.json +1 -0
  24. package/src/template/react-ts-custom-cmp-template/README.md +26 -2
  25. package/src/template/react-ts-custom-cmp-template/neo.config.js +7 -4
  26. package/src/template/react-ts-custom-cmp-template/package.json +1 -0
  27. package/src/template/vue2-custom-cmp-template/README.md +26 -2
  28. package/src/template/vue2-custom-cmp-template/neo.config.js +7 -4
  29. package/src/template/vue2-custom-cmp-template/package.json +1 -0
  30. package/src/{cmpUtils → utils/cmpUtils}/createCmpByTemplate.js +8 -6
  31. package/src/utils/cmpUtils/createCmpByZip.js +90 -0
  32. package/src/{cmpUtils → utils/cmpUtils}/createCommonModulesCode.js +2 -2
  33. package/src/{cmpUtils → utils/cmpUtils}/getCmpModelRegisterCode.js +1 -1
  34. package/src/{cmpUtils → utils/cmpUtils}/getCmpPreviewCode.js +1 -1
  35. package/src/{cmpUtils → utils/cmpUtils}/getCmpRegisterCode.js +1 -1
  36. package/src/{cmpUtils → utils/cmpUtils}/getCmpTypeByDir.js +2 -2
  37. package/src/{cmpUtils → utils/cmpUtils}/hasCmpTypeByDir.js +1 -1
  38. package/src/{cmpUtils → utils/cmpUtils}/previewCmp.js +3 -3
  39. package/src/utils/cmpUtils/pullCmp.js +96 -0
  40. package/src/{cmpUtils → utils/cmpUtils}/pushCmp.js +82 -71
  41. package/src/utils/common.js +48 -0
  42. package/src/utils/generateEntries.js +73 -0
  43. package/src/{projectUtils → utils/projectUtils}/createCmpProjectByTemplate.js +10 -6
  44. package/src/{projectUtils → utils/projectUtils}/createCmpProjectZip.js +18 -20
  45. package/src/{projectUtils → utils/projectUtils}/getEntries.js +2 -2
  46. package/src/{projectUtils → utils/projectUtils}/getEntriesWithAutoRegister.js +2 -2
  47. package/src/{projectUtils → utils/projectUtils}/hasNeoProject.js +2 -2
  48. package/src/{projectUtils → utils/projectUtils}/updatePublishLog.js +1 -1
@@ -0,0 +1,90 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const axios = require('axios');
4
+ const ora = require('ora');
5
+ const AdmZip = require('adm-zip');
6
+ const { consoleTag } = require('../neoParams'); // 输出标记
7
+ const hasCmpTypeByDir = require('./hasCmpTypeByDir');
8
+ const hasNeoProject = require('../projectUtils/hasNeoProject');
9
+
10
+ /**
11
+ * 从 zip 包中创建自定义组件
12
+ * @param {*} cmpZipUrl 自定义组件源码文件地址(zip包地址)
13
+ * @param {*} cmpName 自定义组件名称
14
+ * @param {*} componentBaseDir 自定义组件目录
15
+ */
16
+ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/components') {
17
+ const finalCmpName = cmpName || 'neoCustomCmp';
18
+
19
+ if (!hasNeoProject()) {
20
+ console.error(
21
+ `${consoleTag}当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo createProject)。`
22
+ );
23
+ process.exit(1);
24
+ }
25
+
26
+ if (hasCmpTypeByDir(finalCmpName)) {
27
+ console.error(`${consoleTag}当前项目已经存在${finalCmpName}自定义组件。`);
28
+ process.exit(1);
29
+ }
30
+
31
+ // 创建临时目录
32
+ const tempDir = path.join(process.cwd(), '.neo-cli', 'zip-source');
33
+
34
+ // 下载源码文件并解析到 src/components 目录下
35
+ try {
36
+ await fs.ensureDir(tempDir); // 如果目录不存在,会自动创建(包括所有必要的父目录)
37
+
38
+ // 下载 zip 文件
39
+ const spinner = ora(`${consoleTag}正在下载组件源码...`).start();
40
+ const zipFilePath = path.join(tempDir, `${finalCmpName}.zip`);
41
+
42
+ const response = await axios({
43
+ url: cmpZipUrl,
44
+ method: 'GET',
45
+ responseType: 'arraybuffer'
46
+ });
47
+
48
+ // 保存 zip 文件到临时目录
49
+ await fs.writeFile(zipFilePath, response.data);
50
+
51
+ // 解压 zip 文件
52
+ spinner.text(`${consoleTag}正在解压组件源码...`);
53
+ const zip = new AdmZip(zipFilePath);
54
+ const extractPath = path.join(tempDir, finalCmpName);
55
+ zip.extractAllTo(extractPath, true);
56
+
57
+ // 查找解压后的 src/components 目录
58
+ const cmpSourcePath = path.join(extractPath, componentBaseDir, finalCmpName);
59
+
60
+ if (!fs.existsSync(cmpSourcePath)) {
61
+ spinner.stopAndFail(`${consoleTag}解压后的 zip 包中未找到 ${finalCmpName} 组件源码目录。`);
62
+ await fs.remove(tempDir);
63
+ process.exit(1);
64
+ }
65
+
66
+ // 确保目标目录存在
67
+ const targetComponentsDir = path.resolve(process.cwd(), componentBaseDir, finalCmpName);
68
+ await fs.ensureDir(targetComponentsDir);
69
+
70
+ // 复制 src/components 目录下的所有内容到目标目录
71
+ await fs
72
+ .copy(cmpSourcePath, targetComponentsDir)
73
+ .catch((err) => spinner.stopAndFail(`${consoleTag}自定义组件模板下载失败:`, err));
74
+
75
+ // 清理临时目录
76
+ await fs.remove(tempDir);
77
+ spinner.succeed(`${consoleTag}已成功从 zip 包解析自定义组件(${finalCmpName})!`);
78
+
79
+ return true;
80
+ } catch (error) {
81
+ spinner.stopAndFail(
82
+ `${consoleTag}从 zip 包创建自定义组件失败(${finalCmpName}):`,
83
+ error.message
84
+ );
85
+ // 清理临时目录
86
+ await fs.remove(tempDir);
87
+
88
+ return false;
89
+ }
90
+ };
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs');
2
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
2
+ const { resolveToCurrentRoot } = require('../pathUtils');
3
3
  const { isPlainObject } = require('lodash');
4
4
 
5
5
  /**
@@ -9,7 +9,7 @@ const { isPlainObject } = require('lodash');
9
9
  * @returns 组件预览代码
10
10
  */
11
11
  const createCommonModulesCode = (neoCommonModule, cmpTypes) => {
12
- const {neoExports, remoteDeps} = neoCommonModule;
12
+ const { neoExports, remoteDeps } = neoCommonModule;
13
13
 
14
14
  if (!neoExports && !remoteDeps) {
15
15
  return '';
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs');
2
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
2
+ const { resolveToCurrentRoot } = require('../pathUtils');
3
3
 
4
4
  /**
5
5
  * 获取组件注册文件内容
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs');
2
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
2
+ const { resolveToCurrentRoot } = require('../pathUtils');
3
3
 
4
4
  /**
5
5
  * 获取组件预览代码
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs');
2
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
2
+ const { resolveToCurrentRoot } = require('../pathUtils');
3
3
 
4
4
  /**
5
5
  * 获取组件注册文件内容
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
3
+ const { resolveToCurrentRoot } = require('../pathUtils');
4
4
  /**
5
5
  * 根据当前组件目录,获取所有组件类型
6
6
  * @param {*} componentsBaseDir 自定义组件目录
@@ -23,7 +23,7 @@ const getCmpTypeByDir = (componentsBaseDir = './src/components') => {
23
23
  dirs.forEach((dir) => {
24
24
  const dirPath = path.join(componentsDir, dir);
25
25
  const stat = fs.statSync(dirPath);
26
-
26
+
27
27
  // 只处理目录,过滤掉隐藏目录和 node_modules
28
28
  if (stat.isDirectory() && !dir.startsWith('.') && dir !== 'node_modules') {
29
29
  cmpTypes.push(dir);
@@ -8,4 +8,4 @@ const getCmpTypeByDir = require('./getCmpTypeByDir');
8
8
  module.exports = (cmpType) => {
9
9
  const cmpTypes = getCmpTypeByDir();
10
10
  return cmpTypes.includes(cmpType);
11
- };;
11
+ };
@@ -1,8 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const akfun = require('akfun');
3
- const { consoleTag } = require('../utils/neoParams'); // 输出标记
4
- const { resolveToCurrentRoot } = require('../utils/pathUtils');
5
- const getCmpPreviewCode = require('../cmpUtils/getCmpPreviewCode'); // 获取自定义组件预览代码
3
+ const { consoleTag } = require('../neoParams'); // 输出标记
4
+ const { resolveToCurrentRoot } = require('../pathUtils');
5
+ const getCmpPreviewCode = require('./getCmpPreviewCode'); // 获取自定义组件预览代码
6
6
 
7
7
  /**
8
8
  * 用于预览指定自定义组件的脚本
@@ -0,0 +1,96 @@
1
+ const _ = require('lodash');
2
+ const { catchCurPackageJson } = require('../pathUtils');
3
+ const getConfigObj = require('../getConfigObj');
4
+ const ora = require('ora');
5
+ const NeoService = require('../neo/neoService');
6
+ const { getFramework } = require('../common');
7
+ const getCmpTypeByDir = require('../getCmpTypeByDir.js');
8
+ const createCmpByZip = require('../createCmpByZip.js');
9
+
10
+ // 获取当前项目的package文件
11
+ const currentPackageJsonDir = catchCurPackageJson();
12
+ const currentPackageJson = getConfigObj(currentPackageJsonDir);
13
+ const framework = getFramework(currentPackageJson.framework);
14
+
15
+ /**
16
+ * 从 NeoCRM 拉取自定义组件
17
+ * @param {string} cmpType 自定义组件类型
18
+ * @param {object} authConfig 授权配置
19
+ */
20
+ const pullCmp = async (cmpType, authConfig, _neoService) => {
21
+ if (!authConfig) {
22
+ console.error('未找到 NeoCRM 平台授权配置(neo.config.js / authConfig)。');
23
+ return;
24
+ }
25
+
26
+ const cmpTypes = getCmpTypeByDir(); // 获取当前项目目录中已存在的自定义组件类型
27
+ if (cmpTypes.indexOf(cmpType) > -1) {
28
+ console.error(`当前项目目录中已存在${cmpType}自定义组件。(./src/components 目录下)`);
29
+ process.exit(1);
30
+ }
31
+
32
+ const spinner = ora('正在拉取组件...').start();
33
+
34
+ try {
35
+ let neoService = _neoService;
36
+ let cmpList = [],
37
+ cmpInfoMap = {};
38
+ let cmpInfo = null;
39
+
40
+ if (_neoService) {
41
+ // 使用传入的 neoService 实例
42
+ cmpList = _neoService.cmpList || [];
43
+ cmpInfoMap = _neoService.cmpInfoMap || {};
44
+ } else {
45
+ // 创建新的 neoService 实例
46
+ neoService = new NeoService(authConfig);
47
+
48
+ // 获取自定义组件列表
49
+ spinner.text('正在获取自定义组件列表...');
50
+ cmpList = await neoService.getCustomCmpList();
51
+ cmpInfoMap = neoService.cmpInfoMap || {};
52
+ }
53
+
54
+ if (cmpList.length === 0) {
55
+ spinner.stopAndFail('拉取失败,当前租户暂无任何自定义组件。');
56
+ process.exit(1);
57
+ }
58
+
59
+ // 获取自定义组件信息
60
+ spinner.text(`正在查找 ${cmpType} 组件信息...`);
61
+ cmpInfo = neoService.getCmpInfoByCmpType(cmpType);
62
+ if (!cmpInfo) {
63
+ spinner.stopAndFail(`拉取失败,当前租户不存在${cmpType}自定义组件。`);
64
+ process.exit(1);
65
+ }
66
+
67
+ // 判断拉取的组件和当前项目是否为同一技术栈
68
+ if (cmpInfo.framework !== framework) {
69
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件与当前项目技术栈不一致。`);
70
+ process.exit(1);
71
+ }
72
+
73
+ // 获取当前源码
74
+ if (!cmpInfo.codeLib) {
75
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件未记录对应的源码文件。`);
76
+ process.exit(1);
77
+ }
78
+
79
+ // 下载源码文件并解析到 src/components 目录下
80
+ const codeLib = cmpInfo.codeLib; // 源码文件地址(zip包地址)
81
+
82
+ // 将zip 包里面的自定义组件源码解析到 src/components 目录下
83
+ const cmpResult = await createCmpByZip(codeLib, cmpType, './src/components');
84
+ if (!cmpResult) {
85
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件源码解析失败,请检查源码文件是否正确。`);
86
+ process.exit(1);
87
+ }
88
+
89
+ spinner.succeed(`已成功拉取${cmpType}自定义组件!\n`);
90
+ } catch (error) {
91
+ spinner.fail(`拉取自定义组件失败: ${error.message}`);
92
+ throw error;
93
+ }
94
+ };
95
+
96
+ module.exports = pullCmp;
@@ -1,53 +1,17 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const _ = require('lodash');
4
- const { catchCurPackageJson } = require('../utils/pathUtils');
5
- const getConfigObj = require('../utils/getConfigObj');
4
+ const { catchCurPackageJson } = require('../pathUtils');
5
+ const getConfigObj = require('../getConfigObj');
6
6
  const ora = require('ora');
7
7
  const NeoService = require('../neo/neoService');
8
- const { consoleTag } = require('../utils/neoParams');
8
+ const { getFramework } = require('../common');
9
9
  const createCmpProjectZip = require('../projectUtils/createCmpProjectZip');
10
10
 
11
11
  // 获取当前项目的package文件
12
12
  const currentPackageJsonDir = catchCurPackageJson();
13
13
  const currentPackageJson = getConfigObj(currentPackageJsonDir);
14
14
 
15
- /**
16
- * 获取技术栈标识
17
- * 目的:兼容用户非标准写法
18
- * 0: React, 1: vue2, 2: jQuery, 3: vue3
19
- */
20
- function getFramework(_framework) {
21
- let defaultFramework = '0'; // 默认 React 技术栈
22
- if (!_framework) {
23
- return defaultFramework;
24
- }
25
- let curFramework = _framework.toLowerCase().trim();
26
- switch (curFramework) {
27
- case 'jquery':
28
- case 'jq':
29
- curFramework = '2';
30
- break;
31
- case 'vue2':
32
- case 'vue 2':
33
- case 'vue2.0':
34
- case 'vue 2.0':
35
- curFramework = '1';
36
- break;
37
- case 'vue':
38
- case 'vue3':
39
- case 'vue 3':
40
- case 'vue3.0':
41
- case 'vue 3.0':
42
- curFramework = '3';
43
- console.error(`${consoleTag} 暂不支持 vue3.0 技术栈。`);
44
- break;
45
- default:
46
- curFramework = '0';
47
- }
48
- return curFramework;
49
- }
50
-
51
15
  /**
52
16
  * 构建组件数据映射
53
17
  * @param {string} assetsRoot 构建产物的目录
@@ -61,7 +25,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
61
25
  }
62
26
 
63
27
  const { cmpType } = cmpInfo;
64
-
28
+
65
29
  if (!assetsRoot || !fs.existsSync(assetsRoot)) {
66
30
  console.error(`未找到自定义组件目录: ${assetsRoot}`);
67
31
  return null;
@@ -76,7 +40,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
76
40
  globalThis.window = {
77
41
  console: console,
78
42
  neoRequire: () => {},
79
- postMessage: () => {},
43
+ postMessage: () => {}
80
44
  // 可以添加其他常用的 window 属性
81
45
  };
82
46
  }
@@ -88,17 +52,18 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
88
52
  let modelModule = require(modelFile);
89
53
  // 获取导出的模型类(可能是 default 导出或命名导出)
90
54
  // const CatchCustomCmpModelClass = modelModule.default || modelModule;
91
- }
92
- else {
55
+ } else {
93
56
  console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`, modelFile);
94
57
  return null;
95
58
  }
96
- if (!window.NEOEditorCustomModels) {
97
- console.error(`模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `);
59
+ if (!globalThis.window || !globalThis.window.NEOEditorCustomModels) {
60
+ console.error(
61
+ `模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `
62
+ );
98
63
  return null;
99
64
  }
100
65
 
101
- const ModelClass = window.NEOEditorCustomModels[cmpType];
66
+ const ModelClass = globalThis.window.NEOEditorCustomModels[cmpType];
102
67
  if (!ModelClass) {
103
68
  console.error(`未找到自定义组件模型类(${cmpType}),模型文件地址: ${modelFile} `);
104
69
  return null;
@@ -116,6 +81,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
116
81
  ...cmpInfo,
117
82
  plugin: cmpInfo.modelAsset,
118
83
  version: currentPackageJson.version || '1.0.0',
84
+ // 技术栈标识: 从 package.json / framework 字段获取,没有则默认 为 react ts 技术栈
119
85
  framework: currentPackageJson.framework ? getFramework(currentPackageJson.framework) : '0', // 0: React, 1: vue2, 2: jQuery, 3: vue3
120
86
  // 从模型实例中提取并设置组件信息
121
87
  label: modelInstance.label || cmpType,
@@ -128,9 +94,11 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
128
94
  events: modelInstance.events || [],
129
95
  actions: modelInstance.actions || [],
130
96
  // 如果模型实例中有其他属性,也可以添加
131
- exposedToDesigner: modelInstance.exposedToDesigner !== undefined ? modelInstance.exposedToDesigner : true,
97
+ exposedToDesigner:
98
+ modelInstance.exposedToDesigner !== undefined ? modelInstance.exposedToDesigner : true,
132
99
  namespace: modelInstance.namespace || 'neo-cmp-cli',
133
- enableDuplicate: modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
100
+ enableDuplicate:
101
+ modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
134
102
  };
135
103
 
136
104
  console.log(`自定义组件模型信息(${cmpType}):`, curCmpInfo);
@@ -152,15 +120,13 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
152
120
  /**
153
121
  * 发布组件到 NeoCRM
154
122
  * @param {object} config 配置信息
155
- * @param {string} assetsRoot 构建产物的目录
123
+ * @param {string} cmpType 自定义组件类型
156
124
  */
157
125
  const pushCmp = async (config, cmpType) => {
158
- const {
159
- authConfig: credentials
160
- } = config;
126
+ const { auth: credentials } = config;
161
127
 
162
128
  if (!credentials) {
163
- console.error('未找到 NeoCRM 平台授权配置(neo.config.js / pushCmp / authConfig)。');
129
+ console.error('未找到 NeoCRM 平台授权配置(neo.config.js / neoConfig)');
164
130
  return;
165
131
  }
166
132
 
@@ -168,33 +134,78 @@ const pushCmp = async (config, cmpType) => {
168
134
 
169
135
  try {
170
136
  // 步骤 1: 初始化 NeoService
171
- spinner.text = '发布自定义组件:初始化 NeoService...';
172
- const neoService = new NeoService(config);
137
+ let neoService = new NeoService(config);
138
+ // 获取 token
139
+ await neoService.ensureValidToken();
173
140
 
174
141
  // 步骤 2: 打包源码文件(打包单个自定义组件源码)
175
- spinner.text = '发布自定义组件:打包源码文件(含单个自定义组件源码)...';
176
- createCmpProjectZip(cmpType, process.cwd(), config.assetsRoot);
142
+ spinner.start(`[1/4] 打包源码文件(含单个自定义组件源码)...`);
143
+ let zipPath;
144
+ try {
145
+ zipPath = createCmpProjectZip(cmpType, process.cwd(), config.assetsRoot);
146
+ if (!zipPath) {
147
+ spinner.fail('[1/4] 源码文件打包失败,未返回 zip 文件路径。');
148
+ } else {
149
+ spinner.succeed(`[1/4] 源码文件打包完成: ${path.basename(zipPath)}。`);
150
+ }
151
+ } catch (error) {
152
+ spinner.fail(`[1/4] 源码文件打包失败。`);
153
+ }
177
154
 
178
155
  // 步骤 3: 上传构建后资源文件
179
- spinner.text = '发布自定义组件:上传自定义组件构建产物到 OSS...';
180
- const cmpInfo = await neoService.publish2oss(cmpType);
181
-
182
- // 步骤 5: 构建组件数据
183
- spinner.text = '发布自定义组件:构建组件数据...';
184
- const componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
185
- if (!componentInfo) {
186
- throw new Error(`构建组件数据失败,未获取到自定义组件模型信息。(${cmpType})`);
156
+ spinner.start(`[2/4] 上传自定义组件构建产物到 OSS...`);
157
+ let cmpInfo;
158
+ try {
159
+ cmpInfo = await neoService.publish2oss(cmpType);
160
+ if (!cmpInfo || !cmpInfo.cmpType) {
161
+ spinner.fail('[2/4] 上传构建产物失败,未获取到组件信息。');
162
+ } else {
163
+ spinner.succeed(`[2/4] 构建产物上传完成。`);
164
+ }
165
+ } catch (error) {
166
+ spinner.fail(`[2/4] 构建产物上传失败。`);
187
167
  }
188
168
 
189
- // 步骤 6: 保存组件信息
190
- spinner.text = '发布自定义组件:保存组件信息...';
191
- await neoService.updateCustomComponent(componentInfo);
169
+ // 步骤 4: 构建组件数据
170
+ spinner.start(`[3/4] 构建组件数据...`);
171
+ let componentInfo;
172
+ try {
173
+ componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
174
+ if (!componentInfo) {
175
+ spinner.fail(`[3/4] 未获取到自定义组件模型信息(${cmpType})。`);
176
+ } else {
177
+ spinner.succeed(`[3/4] 组件数据构建完成。`);
178
+ }
179
+ } catch (error) {
180
+ spinner.fail(`[3/4] 组件数据构建失败: `, error.message);
181
+ }
192
182
 
193
- spinner.succeed('自定义组件发布成功!\n', componentInfo);
183
+ // 步骤 5: 保存组件信息
184
+ spinner.start(`[4/4] 保存组件信息到 NeoCRM 平台...`);
185
+ try {
186
+ await neoService.updateCustomComponent(componentInfo);
187
+ spinner.succeed(`[4/4] 组件信息保存成功`);
188
+ } catch (error) {
189
+ spinner.fail(`[4/4] 组件信息保存失败`);
190
+ }
191
+
192
+ // 最终成功提示
193
+ console.log('\n✅ 自定义组件发布成功!');
194
+ console.log('\n组件信息:', componentInfo);
194
195
  } catch (error) {
195
- spinner.fail(`自定义组件发布失败: ${error.message}`);
196
+ // 内层 catch 已经处理了步骤错误并显示了 spinner 失败状态
197
+ // 这里处理未预期的错误(如果 spinner 还在运行)
198
+ try {
199
+ // ora 的 spinner 对象可能没有 isSpinning 属性,使用 try-catch 安全访问
200
+ if (spinner && spinner.isSpinning) {
201
+ spinner.fail(`❌ 自定义组件发布失败: ${error.message}`);
202
+ }
203
+ } catch {
204
+ // 如果访问失败或 spinner 已停止,直接输出错误信息
205
+ console.error(`\n❌ 自定义组件发布失败: ${error.message}`);
206
+ }
196
207
  throw error;
197
208
  }
198
209
  };
199
210
 
200
- module.exports = pushCmp;
211
+ module.exports = pushCmp;
@@ -0,0 +1,48 @@
1
+ const { consoleTag } = require('./neoParams');
2
+ /**
3
+ * 获取技术栈标识
4
+ * 目的:兼容用户非标准写法
5
+ * 0: React, 1: vue2, 2: jQuery, 3: vue3
6
+ */
7
+ function getFramework(_framework) {
8
+ let defaultFramework = '0'; // 默认 React 技术栈
9
+ if (!_framework) {
10
+ return defaultFramework;
11
+ }
12
+ let curFramework = _framework.toLowerCase().trim();
13
+ switch (curFramework) {
14
+ case 'jquery':
15
+ case 'jq':
16
+ curFramework = '2';
17
+ break;
18
+ case 'vue2':
19
+ case 'vue 2':
20
+ case 'vue2.0':
21
+ case 'vue 2.0':
22
+ curFramework = '1';
23
+ break;
24
+ case 'vue':
25
+ case 'vue3':
26
+ case 'vue 3':
27
+ case 'vue3.0':
28
+ case 'vue 3.0':
29
+ curFramework = '3';
30
+ console.error(`${consoleTag} 暂不支持 vue3.0 技术栈。`);
31
+ break;
32
+ case 'react-js':
33
+ console.error(`${consoleTag} 暂不支持 react-js 技术栈。`);
34
+ curFramework = '0';
35
+ break;
36
+ case 'react':
37
+ case 'react-ts':
38
+ curFramework = '0';
39
+ break;
40
+ default:
41
+ curFramework = '0';
42
+ }
43
+ return curFramework;
44
+ }
45
+
46
+ module.exports = {
47
+ getFramework
48
+ };
@@ -0,0 +1,73 @@
1
+ const getEntries = require('./projectUtils/getEntries');
2
+ const getEntriesWithAutoRegister = require('./projectUtils/getEntriesWithAutoRegister');
3
+
4
+ /**
5
+ * 生成 entry 配置
6
+ * @param {object} options 配置选项
7
+ * @param {object} options.configEntry 当前配置中的 entry(如果已存在则直接返回)
8
+ * @param {boolean} options.disableAutoRegister 是否禁用自动注册
9
+ * @param {string} options.componentsDir 组件目录路径
10
+ * @param {string} options.entryType entry 类型:'widget' | 'linkDebug',默认为 'widget'
11
+ * @param {string} [options.cmpType] 可选的组件类型,如果指定则只生成该组件的 entry
12
+ * @param {boolean} [options.forceGetCmpTypes] 即使 entry 已存在,也强制获取 cmpTypes,默认为 false
13
+ * @returns {object} { entries: object, cmpTypes: array } 如果 configEntry 已存在且 forceGetCmpTypes 为 false,则返回 { entries: configEntry, cmpTypes: [] }
14
+ */
15
+ function generateEntries({
16
+ configEntry,
17
+ disableAutoRegister,
18
+ componentsDir,
19
+ entryType = 'widget',
20
+ cmpType,
21
+ forceGetCmpTypes = false
22
+ }) {
23
+ // 如果已配置 entry 且不需要强制获取 cmpTypes,直接返回
24
+ if (configEntry && Object.keys(configEntry).length > 0 && !forceGetCmpTypes) {
25
+ return {
26
+ entries: configEntry,
27
+ cmpTypes: []
28
+ };
29
+ }
30
+
31
+ // 根据 disableAutoRegister 选择不同的生成方法
32
+ let entriesResult;
33
+ if (disableAutoRegister) {
34
+ // disableAutoRegister 为 true 时,仅自动生成入口文件(不自动注册)
35
+ entriesResult = getEntries(componentsDir, cmpType);
36
+ } else {
37
+ // 自动生成入口文件(并自动创建对应的注册文件)
38
+ entriesResult = getEntriesWithAutoRegister(componentsDir, cmpType);
39
+ }
40
+
41
+ // 根据 entryType 选择对应的 entries
42
+ let entries;
43
+ if (entryType === 'linkDebug') {
44
+ entries = entriesResult.linkDebugEntries || {};
45
+ } else {
46
+ entries = entriesResult.widgetEntries || {};
47
+ }
48
+
49
+ const cmpTypes = entriesResult.cmpTypes || [];
50
+
51
+ // 如果 entry 已存在但需要获取 cmpTypes,使用已存在的 entry
52
+ if (configEntry && Object.keys(configEntry).length > 0 && forceGetCmpTypes) {
53
+ entries = configEntry;
54
+ }
55
+
56
+ // 验证 entries 是否有效(仅在需要生成新 entry 时验证)
57
+ if (
58
+ (!configEntry || Object.keys(configEntry).length === 0) &&
59
+ (!entries || Object.keys(entries).length === 0)
60
+ ) {
61
+ const defaultComponentsDir = componentsDir || './src/components';
62
+ throw new Error(
63
+ `未识别到自定义组件,请检查 ${defaultComponentsDir} 目录下是否存在自定义组件。`
64
+ );
65
+ }
66
+
67
+ return {
68
+ entries: entries || configEntry || {},
69
+ cmpTypes
70
+ };
71
+ }
72
+
73
+ module.exports = generateEntries;
@@ -1,9 +1,9 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
- const { consoleTag } = require('../utils/neoParams'); // 输出标记
4
- const { replaceInPackage } = require('../utils/replaceInPackage');
5
- const { resetPackageVersion } = require('../utils/resetPackageVersion');
6
- const autoEntryRootDir = require('../utils/autoEntryRootDir');
3
+ const { consoleTag } = require('../neoParams'); // 输出标记
4
+ const { replaceInPackage } = require('../replaceInPackage');
5
+ const { resetPackageVersion } = require('../resetPackageVersion');
6
+ const autoEntryRootDir = require('../autoEntryRootDir');
7
7
  const hasNeoProject = require('./hasNeoProject');
8
8
 
9
9
  const cmpTemplateList = {
@@ -22,12 +22,16 @@ module.exports = function (projectName, type = 'react-ts') {
22
22
  const finalProjectPath = path.resolve(process.cwd(), projectName);
23
23
 
24
24
  if (hasNeoProject()) {
25
- console.error(`${consoleTag}创建自定义组件项目失败,当前目录(${process.cwd()})已经是一个自定义组件项目,请勿重复创建。`);
25
+ console.error(
26
+ `${consoleTag}创建自定义组件项目失败,当前目录(${process.cwd()})已经是一个自定义组件项目,请勿重复创建。`
27
+ );
26
28
  process.exit(1);
27
29
  }
28
30
 
29
31
  if (fs.existsSync(finalProjectPath)) {
30
- console.error(`${consoleTag}创建自定义组件项目失败,当前已存在(${projectName})项目,请勿创建重名项目。`);
32
+ console.error(
33
+ `${consoleTag}创建自定义组件项目失败,当前已存在(${projectName})项目,请勿创建重名项目。`
34
+ );
31
35
  process.exit(1);
32
36
  }
33
37