neo-cmp-cli 1.5.1 → 1.5.2

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 (68) hide show
  1. package/README.md +52 -15
  2. package/package.json +1 -1
  3. package/src/cmpUtils/createCmpByTemplate.js +52 -0
  4. package/src/cmpUtils/createCommonModulesCode.js +15 -15
  5. package/src/cmpUtils/{getCmpModelRegister.js → getCmpModelRegisterCode.js} +2 -2
  6. package/src/cmpUtils/{getCmpPreview.js → getCmpPreviewCode.js} +2 -2
  7. package/src/cmpUtils/{getCmpRegister.js → getCmpRegisterCode.js} +2 -2
  8. package/src/cmpUtils/getCmpTypeByDir.js +41 -0
  9. package/src/cmpUtils/hasCmpTypeByDir.js +11 -0
  10. package/src/{module → cmpUtils}/previewCmp.js +2 -2
  11. package/src/cmpUtils/{publishCmp.js → pushCmp.js} +54 -42
  12. package/src/config/default.config.js +14 -2
  13. package/src/module/index.js +144 -21
  14. package/src/module/main.js +17 -13
  15. package/src/module/neoInit.js +3 -0
  16. package/src/module/neoInitByCopy.js +3 -0
  17. package/src/neo/NeoUMDContent.js +29 -0
  18. package/src/neo/neoRequire.js +7 -7
  19. package/src/neo/neoService.js +174 -72
  20. package/src/neo/wrapperContent.js +2 -1
  21. package/src/oss/publish2oss.js +1 -1
  22. package/src/plugins/AddNeoRequirePlugin.js +5 -2
  23. package/src/projectUtils/createCmpProjectByTemplate.js +49 -0
  24. package/src/{cmpUtils → projectUtils}/getEntriesWithAutoRegister.js +4 -4
  25. package/src/template/antd-custom-cmp-template/README.md +2 -2
  26. package/src/template/antd-custom-cmp-template/neo.config.js +22 -14
  27. package/src/template/antd-custom-cmp-template/package.json +3 -3
  28. package/src/template/develop/neo-custom-cmp-template/neo.config.js +1 -1
  29. package/src/template/echarts-custom-cmp-template/README.md +2 -2
  30. package/src/template/echarts-custom-cmp-template/neo.config.js +19 -13
  31. package/src/template/echarts-custom-cmp-template/package.json +3 -3
  32. package/src/template/empty-cmp/index.tsx +51 -0
  33. package/src/template/empty-cmp/model.ts +77 -0
  34. package/src/template/empty-cmp/style.scss +72 -0
  35. package/src/template/empty-custom-cmp-template/.prettierrc.js +12 -0
  36. package/src/template/empty-custom-cmp-template/README.md +45 -0
  37. package/src/template/empty-custom-cmp-template/commitlint.config.js +59 -0
  38. package/src/template/empty-custom-cmp-template/neo.config.js +126 -0
  39. package/src/template/empty-custom-cmp-template/package.json +57 -0
  40. package/src/template/empty-custom-cmp-template/public/css/base.css +283 -0
  41. package/src/template/empty-custom-cmp-template/public/scripts/app/bluebird.js +6679 -0
  42. package/src/template/empty-custom-cmp-template/public/template.html +13 -0
  43. package/src/template/empty-custom-cmp-template/src/assets/css/common.scss +127 -0
  44. package/src/template/empty-custom-cmp-template/src/assets/css/mixin.scss +47 -0
  45. package/src/template/empty-custom-cmp-template/src/assets/img/NeoCRM.jpg +0 -0
  46. package/src/template/empty-custom-cmp-template/src/assets/img/custom-widget.svg +1 -0
  47. package/src/template/empty-custom-cmp-template/src/assets/img/favicon.png +0 -0
  48. package/src/template/empty-custom-cmp-template/src/assets/img/map.svg +1 -0
  49. package/src/template/empty-custom-cmp-template/src/components/README.md +3 -0
  50. package/src/template/empty-custom-cmp-template/tsconfig.json +68 -0
  51. package/src/template/neo-custom-cmp-template/README.md +2 -2
  52. package/src/template/neo-custom-cmp-template/neo.config.js +6 -26
  53. package/src/template/neo-custom-cmp-template/package.json +3 -4
  54. package/src/template/react-custom-cmp-template/README.md +2 -2
  55. package/src/template/react-custom-cmp-template/neo.config.js +20 -15
  56. package/src/template/react-custom-cmp-template/package.json +3 -3
  57. package/src/template/react-ts-custom-cmp-template/README.md +2 -2
  58. package/src/template/react-ts-custom-cmp-template/neo.config.js +19 -14
  59. package/src/template/react-ts-custom-cmp-template/package.json +3 -3
  60. package/src/template/vue2-custom-cmp-template/README.md +2 -2
  61. package/src/template/vue2-custom-cmp-template/neo.config.js +20 -15
  62. package/src/template/vue2-custom-cmp-template/package.json +3 -3
  63. package/src/utils/autoEntryRootDir.js +75 -0
  64. package/src/utils/replaceInFilesByMap.js +54 -0
  65. package/test/demo.js +2 -2
  66. package/src/template/neo-custom-cmp-template/auth.config.js +0 -12
  67. /package/src/{cmpUtils → projectUtils}/getEntries.js +0 -0
  68. /package/src/{cmpUtils → projectUtils}/updatePublishLog.js +0 -0
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  ## Neo 自定义组件开发工具
2
- neo-cmp-cli 是 Neo 自定义组件开发工具,基于 [AKFun](https://github.com/wibetter/akfun) 的工程能力,提供 初始化、编译构建、预览调试、热更新、多技术栈支持和一键发布等功能。
2
+ neo-cmp-cli 是 Neo 自定义组件开发工具,基于 [AKFun](https://github.com/wibetter/akfun) 的工程能力,提供 初始化、编译构建、预览调试、热更新、多技术栈支持和发布等功能。
3
3
 
4
4
  ### 主要特性
5
5
  - **零配置**: 内置默认配置,开箱可用;
6
6
  - **多技术栈**: 支持 Vue2、React、React+TypeScript 自定义组件的调试、构建与发布;
7
- - **多构建场景**: 本地预览(含热更新/代理)、外链调试、库构建(UMD/ESM);
7
+ - **多构建场景**: 本地预览(含热更新/代理)、外链调试、库构建(UMD/ESM)、部署&发布;
8
8
  - **灵活可配**: 支持 构建入口、别名、代理、SASS 注入、ESLint/StyleLint、Babel/Loader/Plugin 扩展等配置;
9
9
  - **样式与规范**: 内置 Autoprefixer、Sass、PostCSS、ESLint、StyleLint;
10
- - **参数替换**: 支持基于 [params-replace-loader](https://www.npmjs.com/package/params-replace-loader) 的环境变量批量替换;
11
- - **一键发布**: 内置发布到 OSS 的能力,并支持自定义对象存储配置。
10
+ - **发布至 CDN**: 内置发布到对象存储(OSS)的能力,支持自定义对象存储配置;
11
+ - **发布至 NeoCRM 平台**: 支持一键发布到NeoCRM 平台的能力,需自行补充授权配置;
12
12
 
13
13
  ### 内置的自定义组件模板
14
14
  创建自定义组件时(执行初始化命令 neo init)可选用。
@@ -40,8 +40,8 @@ neo preview
40
40
  # 外链调试(在平台线上预览与调试)
41
41
  neo linkDebug
42
42
 
43
- # 构建并发布到 OSS(确保 package.json 的 name 唯一、version 不重复)
44
- neo publish2oss
43
+ # 构建并发布到 NeoCRM(需自行添加授权配置,并确保 package.json 的 name 唯一、version 不重复)
44
+ neo pushCmp
45
45
  ```
46
46
 
47
47
  ### 方法二:在现有业务项目中使用自定义组件开发工具
@@ -58,7 +58,7 @@ npm i neo-cmp-cli --save-dev
58
58
  ```bash
59
59
  "preview": "neo preview",
60
60
  "linkDebug": "neo linkDebug",
61
- "publish2oss": "neo publish2oss"
61
+ "pushCmp": "neo pushCmp"
62
62
  ```
63
63
  ##### 3) 初始化配置文件
64
64
  ```bash
@@ -68,7 +68,7 @@ neo config init
68
68
  ```bash
69
69
  npm run preview
70
70
  npm run linkDebug
71
- npm run publish2oss
71
+ npm run pushCmp
72
72
  ```
73
73
 
74
74
  ## 常用命令说明
@@ -76,10 +76,11 @@ npm run publish2oss
76
76
  - **neo preview**: 本地预览自定义组件内容,默认支持热更新与接口代理。
77
77
  - **neo linkDebug**: 外链调试模式,在平台端页面设计器中调试自定义组件。
78
78
  - **neo publish2oss**: 构建并上传到对象存储(可自定义配置对象存储)。
79
+ - **neo pushCmp**: 构建并发布到NeoCRM平台(需自行添加授权配置)。
79
80
 
80
81
  ## 开发须知
81
82
  #### 1)默认自动识别自定义组件
82
- - **自动生成入口配置**: 当 `entry` 未配置时,自动从 `src/components` 目录下扫描并识别自定义组件,`src/components` 下的子目录名称作为自定义组件的 cmpType,并以其目录下的 `index.ts/.tsx/.js/.jsx` 文件作为组件内容文件,model.[tj]s 作为模型内容文件;
83
+ - **自动生成入口配置**: 当 `entry` 未配置时,自动从 `src/components` 目录下扫描并识别自定义组件,`src/components` 下的子目录名称作为自定义组件的名称,并以其目录下的 `index.ts/.tsx/.js/.jsx` 文件作为组件内容文件,model.[tj]s 作为模型内容文件;
83
84
  - **自动注册自定义组件**: 当 `entry` 未配置时,自动生成自定义组件注册文件和模型注册文件,并注入到构建脚本中,无需用户手动编写注册文件([neo-register](https://www.npmjs.com/package/neo-register))。
84
85
 
85
86
  #### 2)设置自定义组件属性配置项
@@ -128,16 +129,49 @@ neo linkDebug
128
129
  ##### 3. 页面设计器开启 debug 模式后,左侧会展示 外部链接 管理面板
129
130
  将第 1 步生成的「外链脚本地址」添加进来,即可在此页面设计器 / 组件物料面板中看到对应自定义组件。
130
131
 
131
- #### 6)发布自定义组件
132
- 执行 `neo publish2oss` 即可构建对应自定义组件,并自动将构建后资源上传到对象存储(OSS)中。
132
+ #### 6)发布自定义组件至 NeoCRM
133
+ 执行 `neo pushCmp` 即可构建并发布自定义组件至 NeoCRM 平台,其构建后资源也会上传到 NeoCRM 平台端提供的 CDN 中。
133
134
 
134
135
  ##### 发布前请确保
135
136
  - **package.json 的 name 唯一**
136
137
  - **version 不重复**
137
- - 已按需配置对象存储参数(支持自定义)
138
+
139
+ ##### 需自行添加授权配置
140
+ ```javascript
141
+ module.exports = {
142
+ pushCmp: {
143
+ neoBaseURL: 'https://crm-cd.xiaoshouyi.com', // 平台根地址(默认:https://crm.xiaoshouyi.com)
144
+ tokenAPI: 'https://login-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
145
+ // NeoCRM 授权配置
146
+ authConfig: {
147
+ /**
148
+ * 客户端 ID 和 客户端秘钥 需通过 创建连接器 获取,
149
+ * 详细见:https://doc.xiaoshouyi.com / 创建连接器。
150
+ */
151
+ client_id: 'xx', // 客户端 ID,从创建连接器的客户端信息中获取(Client_Id)
152
+ client_secret: 'xxx', // 客户端秘钥,从创建连接器的客户端信息中获取(Client_Secret)
153
+ username: 'xx', // 用户在销售易系统中的用户名
154
+ /**
155
+ * password 为 用户在销售易系统中的账号密码加上 8 位安全令牌。
156
+ * 例如,用户密码为 123456,安全令牌为 ABCDEFGH,则 password 的值应为 123456ABCDEFGH。
157
+ * 如何获取 安全令牌请见:https://doc.xiaoshouyi.com / OAuth安全认证 / 密码模式 / 获取令牌。
158
+ */
159
+ password: 'xx xx' // 用户账户密码 + 8 位安全令牌
160
+ },
161
+ },
162
+ }
163
+ ```
138
164
 
139
165
  ##### 支持发布指定自定义组件
140
- 执行 `neo publish2oss --cmpType=xxCmp`
166
+ 执行 `neo pushCmp --name=xxCmp`
167
+
168
+ #### 7)发布自定义组件至CDN
169
+ 执行 `neo publish2oss` 即可构建对应自定义组件,并自动将构建后资源上传到对象存储(OSS)中。
170
+
171
+ ##### 发布前请确保
172
+ - **package.json 的 name 唯一**
173
+ - **version 不重复**
174
+ - 可按需配置对象存储参数(支持自定义),默认使用内置对象存储配置。
141
175
 
142
176
  ##### 支持自定义对象存储配置
143
177
  ```javascript
@@ -159,6 +193,9 @@ module.exports = {
159
193
  }
160
194
  ```
161
195
 
196
+ ##### 支持发布指定自定义组件
197
+ 执行 `neo publish2oss --name=xxCmp`
198
+
162
199
  ## 项目工程配置说明(neo.config.js)
163
200
  neo-cmp-cli 默认提供完整配置;
164
201
  如需自定义,使用 `neo config init` 生成 `neo.config.js` 并按需修改。
@@ -327,8 +364,8 @@ module.exports = {
327
364
  ```javascript
328
365
  module.exports = {
329
366
  neoCommonModule: {
330
- remotes: ['neo-custom-cmpA'], // 远程自定义组件,表示当前自定义组件 B 会用到的自定义组件
331
- neoExternals: ['xxModule_A'], // 自定义组件中需要剔除的模块(远程自定义组件中分享出来的模块),仅支持数组写法,需要和 remotes 配合使用
367
+ remoteDeps: ['neo-custom-cmpA'], // 远程自定义组件,表示当前自定义组件 B 会用到的自定义组件
368
+ neoExternals: ['xxModule_A'], // 自定义组件中需要剔除的模块(远程自定义组件中分享出来的模块),仅支持数组写法,需要和 remoteDeps 配合使用
332
369
  },
333
370
  }
334
371
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-cmp-cli",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "前端脚手架:自定义组件开发工具,支持react 和 vue2.0技术栈。",
5
5
  "keywords": [
6
6
  "neo-cli",
@@ -0,0 +1,52 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const _ = require('lodash');
4
+ const { consoleTag } = require('../utils/neoParams'); // 输出标记
5
+ const replaceInFilesByMap = require('../utils/replaceInFilesByMap');
6
+ const hasCmpTypeByDir = require('./hasCmpTypeByDir');
7
+
8
+ // 自定义组件内容模板信息
9
+ const curCmpTemplate = {
10
+ // 需要替换掉的字段信息(模板中的字段)
11
+ widgetInfo: {
12
+ cmpName: 'CustomCmp',
13
+ modelName: 'CmpModel',
14
+ cmpClassName: 'custom-cmp-container',
15
+ cmpType: 'xx-custom-cmp',
16
+ cmpLabel: 'xx组件',
17
+ },
18
+ dir: path.resolve(__dirname, '../template/empty-cmp')
19
+ };
20
+
21
+ /**
22
+ * 创建自定义组件
23
+ * @param {*} cmpName 自定义组件名称
24
+ */
25
+ module.exports = function (cmpName, componentBaseDir = './src/components') {
26
+ const currentTemplateDir = curCmpTemplate.dir;
27
+ const finalCmpName = cmpName || 'neoCustomCmp';
28
+ const finalCmpPath = path.resolve(process.cwd(), componentBaseDir, finalCmpName);
29
+
30
+ if (hasCmpTypeByDir(finalCmpName)) {
31
+ console.error(`${consoleTag}创建自定义组件失败,当前已经存在${finalCmpName}自定义组件。`);
32
+ process.exit(1);
33
+ }
34
+
35
+ fs.copy(currentTemplateDir, finalCmpPath)
36
+ .then(() => {
37
+ const curCmpName = _.camelCase(finalCmpName);
38
+ const cmpType = _.kebabCase(finalCmpName);
39
+
40
+ // 替换文件中的内容
41
+ replaceInFilesByMap(finalCmpPath, {
42
+ [curCmpTemplate.widgetInfo.modelName]: `${curCmpName}Model`,
43
+ [curCmpTemplate.widgetInfo.cmpName]: curCmpName,
44
+ [curCmpTemplate.widgetInfo.cmpClassName]: `${cmpType}-container`,
45
+ [curCmpTemplate.widgetInfo.cmpType]: cmpType,
46
+ [curCmpTemplate.widgetInfo.cmpLabel]: `${cmpType}组件`,
47
+ });
48
+
49
+ console.log(`${consoleTag}已创建自定义组件(${finalCmpName})!`);
50
+ })
51
+ .catch((err) => console.error(`${consoleTag}自定义组件创建失败(${finalCmpName}):`, err));
52
+ };
@@ -9,15 +9,15 @@ const { isPlainObject } = require('lodash');
9
9
  * @returns 组件预览代码
10
10
  */
11
11
  const createCommonModulesCode = (neoCommonModule, cmpTypes) => {
12
- const {neoExports, remotes} = neoCommonModule;
12
+ const {neoExports, remoteDeps} = neoCommonModule;
13
13
 
14
- if (!neoExports && !remotes) {
14
+ if (!neoExports && !remoteDeps) {
15
15
  return '';
16
16
  }
17
17
  // 记录当前自定义组件共享出去的模块
18
18
  const CustomCmpCommonModules = {};
19
- // 记录当前自定义组件需要的远程组件
20
- const CustomCmpRemotes = {};
19
+ // 记录当前自定义组件需要的远程依赖组件
20
+ const CustomCmpRemoteDeps = {};
21
21
 
22
22
  // 根据 neoExports 获取共享的依赖模块
23
23
  if (Array.isArray(neoExports) && neoExports.length > 0) {
@@ -35,10 +35,10 @@ const createCommonModulesCode = (neoCommonModule, cmpTypes) => {
35
35
  process.exit(1);
36
36
  }
37
37
 
38
- // 根据 cmpTypes 和 remotes 设置远程组件信息
39
- if (Array.isArray(remotes) && remotes.length > 0) {
38
+ // 根据 cmpTypes 和 remoteDeps 设置远程依赖组件信息
39
+ if (Array.isArray(remoteDeps) && remoteDeps.length > 0) {
40
40
  cmpTypes.forEach((cmpType) => {
41
- CustomCmpRemotes[cmpType] = remotes;
41
+ CustomCmpRemoteDeps[cmpType] = remoteDeps;
42
42
  });
43
43
  }
44
44
 
@@ -58,7 +58,7 @@ const createCommonModulesCode = (neoCommonModule, cmpTypes) => {
58
58
  */
59
59
  import { isPlainObject } from 'lodash';
60
60
  const CustomCmpCommonModules = ${customCmpCommonModulesCode};
61
- const CustomCmpRemotes = ${JSON.stringify(CustomCmpRemotes)};
61
+ const CustomCmpRemoteDeps = ${JSON.stringify(CustomCmpRemoteDeps)};
62
62
 
63
63
  // 用于添加共享的依赖模块
64
64
  const addNeoCommonModules = (modules) => {
@@ -88,21 +88,21 @@ const addNeoCommonModules = (modules) => {
88
88
  }
89
89
  }
90
90
 
91
- // 用于添加自定义组件的远程组件(关联使用)
92
- const addNeoRemotes = (remotes) => {
91
+ // 用于添加自定义组件的远程依赖组件(关联使用)
92
+ const addNeoRemoteDeps = (remoteDeps) => {
93
93
  if (!window.__NeoCommonModules) {
94
94
  window.__NeoCommonModules = {}
95
95
  }
96
- if (!window.__NeoCommonModules.__neoRemotes) {
97
- window.__NeoCommonModules.__neoRemotes = {}
96
+ if (!window.__NeoCommonModules.__neoRemoteDeps) {
97
+ window.__NeoCommonModules.__neoRemoteDeps = {}
98
98
  }
99
- if (isPlainObject(remotes)) {
100
- window.__NeoCommonModules.__neoRemotes = Object.assign(window.__NeoCommonModules.__neoRemotes, remotes)
99
+ if (isPlainObject(remoteDeps)) {
100
+ window.__NeoCommonModules.__neoRemoteDeps = Object.assign(window.__NeoCommonModules.__neoRemoteDeps, remoteDeps)
101
101
  }
102
102
  }
103
103
 
104
104
  addNeoCommonModules(CustomCmpCommonModules);
105
- addNeoRemotes(CustomCmpRemotes);
105
+ addNeoRemoteDeps(CustomCmpRemoteDeps);
106
106
  `;
107
107
 
108
108
  // 创建存放 cli 的临时目录
@@ -7,7 +7,7 @@ const { resolveToCurrentRoot } = require('../utils/pathUtils');
7
7
  * @param {*} cmpName 自定义组件名称
8
8
  * @returns 组件注册文件内容
9
9
  */
10
- const getCmpModelRegister = (cmpsDir, cmpName) => {
10
+ const getCmpModelRegisterCode = (cmpsDir, cmpName) => {
11
11
  const cpmModelDir = resolveToCurrentRoot(`${cmpsDir}/${cmpName}/model`);
12
12
 
13
13
  /*
@@ -28,4 +28,4 @@ registerNeoEditorModel(CustomCmpModel, '${cmpName}');
28
28
  `;
29
29
  };
30
30
 
31
- module.exports = getCmpModelRegister;
31
+ module.exports = getCmpModelRegisterCode;
@@ -7,7 +7,7 @@ const { resolveToCurrentRoot } = require('../utils/pathUtils');
7
7
  * @param {*} cmpName 自定义组件名称
8
8
  * @returns 组件预览代码
9
9
  */
10
- const getCmpPreview = (cmpsDir, cmpName) => {
10
+ const getCmpPreviewCode = (cmpsDir, cmpName) => {
11
11
  const cpmDir = resolveToCurrentRoot(`${cmpsDir}/${cmpName}`);
12
12
  const cpmModelDir = resolveToCurrentRoot(`${cmpsDir}/${cmpName}/model`);
13
13
 
@@ -37,4 +37,4 @@ ReactDOM.render(
37
37
  `;
38
38
  };
39
39
 
40
- module.exports = getCmpPreview;
40
+ module.exports = getCmpPreviewCode;
@@ -7,7 +7,7 @@ const { resolveToCurrentRoot } = require('../utils/pathUtils');
7
7
  * @param {*} cmpName 自定义组件名称
8
8
  * @returns 组件注册文件内容
9
9
  */
10
- const getCmpRegister = (cmpsDir, cmpName) => {
10
+ const getCmpRegisterCode = (cmpsDir, cmpName) => {
11
11
  const cpmIndexDir = resolveToCurrentRoot(`${cmpsDir}/${cmpName}/index`);
12
12
 
13
13
  /*
@@ -28,4 +28,4 @@ registerNeoCmp(CustomCmp, '${cmpName}');
28
28
  `;
29
29
  };
30
30
 
31
- module.exports = getCmpRegister;
31
+ module.exports = getCmpRegisterCode;
@@ -0,0 +1,41 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { resolveToCurrentRoot } = require('../utils/pathUtils');
4
+ /**
5
+ * 根据当前组件目录,获取所有组件类型
6
+ * @param {*} componentsBaseDir 自定义组件目录
7
+ * @returns 组件类型列表
8
+ */
9
+ const getCmpTypeByDir = (componentsBaseDir = './src/components') => {
10
+ const componentsDir = resolveToCurrentRoot(componentsBaseDir);
11
+ if (!fs.existsSync(componentsDir)) {
12
+ console.error(`未找到自定义组件目录,请检查 ${componentsDir} 目录是否存在。`);
13
+ // 退出进程
14
+ process.exit(1);
15
+ }
16
+
17
+ try {
18
+ // 读取组件目录下的所有子目录
19
+ const dirs = fs.readdirSync(componentsDir);
20
+ const cmpTypes = [];
21
+
22
+ // 遍历所有目录,过滤出有效的组件类型
23
+ dirs.forEach((dir) => {
24
+ const dirPath = path.join(componentsDir, dir);
25
+ const stat = fs.statSync(dirPath);
26
+
27
+ // 只处理目录,过滤掉隐藏目录和 node_modules
28
+ if (stat.isDirectory() && !dir.startsWith('.') && dir !== 'node_modules') {
29
+ cmpTypes.push(dir);
30
+ }
31
+ });
32
+
33
+ return cmpTypes;
34
+ } catch (error) {
35
+ console.error('获取组件类型失败(getCmpTypeByDir):', error);
36
+ // 退出进程
37
+ process.exit(1);
38
+ }
39
+ };
40
+
41
+ module.exports = getCmpTypeByDir;
@@ -0,0 +1,11 @@
1
+ const getCmpTypeByDir = require('./getCmpTypeByDir');
2
+ /**
3
+ * 判断当前组件目录是否已经存在该组件类型
4
+ * @param {*} componentsBaseDir 自定义组件目录
5
+ * @param {*} cmpType 组件类型
6
+ * @returns Boolean
7
+ */
8
+ module.exports = (cmpType) => {
9
+ const cmpTypes = getCmpTypeByDir();
10
+ return cmpTypes.includes(cmpType);
11
+ };;
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const akfun = require('akfun');
3
3
  const { consoleTag } = require('../utils/neoParams'); // 输出标记
4
4
  const { resolveToCurrentRoot } = require('../utils/pathUtils');
5
- const getCmpPreview = require('../cmpUtils/getCmpPreview');
5
+ const getCmpPreviewCode = require('../cmpUtils/getCmpPreviewCode'); // 获取自定义组件预览代码
6
6
 
7
7
  /**
8
8
  * 用于预览指定自定义组件的脚本
@@ -35,7 +35,7 @@ module.exports = (config, cmpName, defaultComponentsDir = './src/components') =>
35
35
  fs.mkdirSync(cmpTempDir);
36
36
  }
37
37
 
38
- const cmpPreviewContent = getCmpPreview(cmpsDir, cmpName);
38
+ const cmpPreviewContent = getCmpPreviewCode(cmpsDir, cmpName);
39
39
  fs.writeFileSync(`${cmpTempDir}/preview.jsx`, cmpPreviewContent);
40
40
 
41
41
  // 将临时预览文件添加到预览配置中
@@ -2,10 +2,11 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const AdmZip = require('adm-zip');
4
4
  const _ = require('lodash');
5
- const { catchCurPackageJson, resolveToCurrentRoot } = require('../utils/pathUtils');
5
+ const { catchCurPackageJson } = require('../utils/pathUtils');
6
6
  const getConfigObj = require('../utils/getConfigObj');
7
7
  const ora = require('ora');
8
8
  const NeoService = require('../neo/neoService');
9
+ const { consoleTag } = require('../utils/neoParams');
9
10
 
10
11
  // 获取当前项目的package文件
11
12
  const currentPackageJsonDir = catchCurPackageJson();
@@ -47,7 +48,7 @@ const createZipPackage = async (assetsRoot) => {
47
48
  * 目的:兼容用户非标准写法
48
49
  * 0: React, 1: vue2, 2: jQuery, 3: vue3
49
50
  */
50
- export function getFramework(_framework) {
51
+ function getFramework(_framework) {
51
52
  let defaultFramework = '0'; // 默认 React 技术栈
52
53
  if (!_framework) {
53
54
  return defaultFramework;
@@ -82,9 +83,9 @@ export function getFramework(_framework) {
82
83
  * 构建组件数据映射
83
84
  * @param {string} assetsRoot 构建产物的目录
84
85
  * @param {object} cmpInfo 自定义组件信息
85
- * @returns {object} 自定义组件数据(含自定义组件模型信息)
86
+ * @returns {Promise<object|null>} 自定义组件数据(含自定义组件模型信息)
86
87
  */
87
- const buildComponentData = (assetsRoot, cmpInfo) => {
88
+ const buildComponentData = async (assetsRoot, cmpInfo) => {
88
89
  if (!cmpInfo || !cmpInfo.cmpType) {
89
90
  console.error('自定义组件信息或组件名称不能为空');
90
91
  return null;
@@ -93,64 +94,68 @@ const buildComponentData = (assetsRoot, cmpInfo) => {
93
94
  const { cmpType } = cmpInfo;
94
95
 
95
96
  if (!assetsRoot || !fs.existsSync(assetsRoot)) {
96
- console.error(`未找到自定义组件资源目录: ${assetsRoot}`);
97
+ console.error(`未找到自定义组件目录: ${assetsRoot}`);
97
98
  return null;
98
99
  }
99
- const widgetName = _.kebabCase(cmpType);
100
+ const widgetName = _.camelCase(cmpType);
100
101
  const modelFile = path.join(assetsRoot, `${widgetName}Model.js`);
101
-
102
- let ModelClass = null;
102
+
103
+ // Node.js 环境设置全局 window 对象(模型文件可能需要)
104
+ // 使用 globalThis 以确保在 Node.js 和浏览器环境中都能工作
105
+ const originalWindow = globalThis.window;
106
+ if (!globalThis.window) {
107
+ globalThis.window = {
108
+ console: console,
109
+ neoRequire: () => {},
110
+ postMessage: () => {},
111
+ // 可以添加其他常用的 window 属性
112
+ };
113
+ }
103
114
 
104
115
  try {
105
116
  // 加载自定义组件模型资源文件
106
117
  if (fs.existsSync(modelFile)) {
107
- // 清除 require 缓存,确保每次都加载最新内容
108
- const resolvedPath = require.resolve(modelFile);
109
- if (require.cache[resolvedPath]) {
110
- delete require.cache[resolvedPath];
111
- }
112
- const modelModule = require(modelFile);
118
+ // 加载自定义组件模型资源文件
119
+ let modelModule = require(modelFile);
113
120
  // 获取导出的模型类(可能是 default 导出或命名导出)
114
- ModelClass = modelModule.default || modelModule;
115
- // 如果是命名导出,尝试查找类名(例如 EntityCardListModel)
116
- if (typeof ModelClass !== 'function' && typeof modelModule === 'object') {
117
- // 查找所有导出的类
118
- const exportedClasses = Object.values(modelModule).filter(
119
- (item) => typeof item === 'function'
120
- );
121
- if (exportedClasses.length > 0) {
122
- ModelClass = exportedClasses[0];
123
- }
124
- }
121
+ // const CatchCustomCmpModelClass = modelModule.default || modelModule;
125
122
  }
126
- // 如果资源文件不存在,报错
127
123
  else {
128
- console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`);
124
+ console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`, modelFile);
129
125
  return null;
130
126
  }
131
-
132
- // 如果 ModelClass 是函数(类),则实例化
133
- if (typeof ModelClass !== 'function') {
134
- console.error(`模型文件 ${modelFile} 未导出有效的模型类`);
127
+ if (!window.NEOEditorCustomModels) {
128
+ console.error(`模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `);
135
129
  return null;
136
130
  }
137
131
 
132
+ const ModelClass = window.NEOEditorCustomModels[cmpType];
133
+ if (!ModelClass) {
134
+ console.error(`未找到自定义组件模型类(${cmpType}),模型文件地址: ${modelFile} `);
135
+ return null;
136
+ }
138
137
  // 实例化模型类
139
138
  const modelInstance = new ModelClass();
140
139
 
140
+ if (!modelInstance) {
141
+ console.error(`未找到自定义组件模型信息(${cmpType}),模型文件地址: ${modelFile} `);
142
+ return null;
143
+ }
144
+
141
145
  // 构建组件数据,合并模型实例的信息
142
146
  const curCmpInfo = {
143
147
  ...cmpInfo,
148
+ plugin: cmpInfo.modelAsset,
144
149
  version: currentPackageJson.version || '1.0.0',
145
150
  framework: currentPackageJson.framework ? getFramework(currentPackageJson.framework) : '0', // 0: React, 1: vue2, 2: jQuery, 3: vue3
146
151
  // 从模型实例中提取并设置组件信息
147
152
  label: modelInstance.label || cmpType,
148
153
  description: modelInstance.description || '',
149
- componentCategory: modelInstance.tags || [],
154
+ componentCategory: (modelInstance.tags || []).join(','),
150
155
  icon: modelInstance.iconSrc,
151
- defaultProps: modelInstance.defaultComProps || {},
152
- previewProps: modelInstance.previewComProps || {},
153
- propsSchema: modelInstance.propsSchema || [],
156
+ defaultProps: JSON.stringify(modelInstance.defaultComProps || {}),
157
+ previewProps: JSON.stringify(modelInstance.previewComProps || {}),
158
+ propsSchema: JSON.stringify(modelInstance.propsSchema || []),
154
159
  events: modelInstance.events || [],
155
160
  actions: modelInstance.actions || [],
156
161
  // 如果模型实例中有其他属性,也可以添加
@@ -159,11 +164,19 @@ const buildComponentData = (assetsRoot, cmpInfo) => {
159
164
  enableDuplicate: modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
160
165
  };
161
166
 
167
+ console.log(`自定义组件模型信息(${cmpType}):`, curCmpInfo);
162
168
  return curCmpInfo;
163
169
  } catch (error) {
164
170
  console.error(`自定义组件模型文件解析失败 (${modelFile || '未知路径'}):`, error.message);
165
171
  console.error(error.stack);
166
172
  return null;
173
+ } finally {
174
+ // 恢复原始的 window 对象(如果之前存在)
175
+ if (originalWindow === undefined) {
176
+ delete globalThis.window;
177
+ } else {
178
+ globalThis.window = originalWindow;
179
+ }
167
180
  }
168
181
  };
169
182
 
@@ -172,13 +185,13 @@ const buildComponentData = (assetsRoot, cmpInfo) => {
172
185
  * @param {object} config 配置信息
173
186
  * @param {string} assetsRoot 构建产物的目录
174
187
  */
175
- const publishCmp = async (config, cmpType) => {
188
+ const pushCmp = async (config, cmpType) => {
176
189
  const {
177
- authorization: credentials
190
+ authConfig: credentials
178
191
  } = config;
179
192
 
180
193
  if (!credentials) {
181
- console.error('未找到 NeoCRM 平台授权配置(neo.config.js / publishCmpConfig / credentials)。');
194
+ console.error('未找到 NeoCRM 平台授权配置(neo.config.js / pushCmp / authConfig)。');
182
195
  return;
183
196
  }
184
197
 
@@ -201,9 +214,9 @@ const publishCmp = async (config, cmpType) => {
201
214
 
202
215
  // 步骤 4: 构建组件数据
203
216
  spinner.text = '发布自定义组件:构建组件数据...';
204
- const componentInfo = buildComponentData(config.assetsRoot, cmpInfo);
217
+ const componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
205
218
  if (!componentInfo) {
206
- throw new Error('构建组件数据失败,无法继续发布');
219
+ throw new Error(`构建组件数据失败,未获取到自定义组件模型信息。(${cmpType})`);
207
220
  }
208
221
 
209
222
  // 步骤 5: 保存组件信息
@@ -217,5 +230,4 @@ const publishCmp = async (config, cmpType) => {
217
230
  }
218
231
  };
219
232
 
220
- module.exports = publishCmp;
221
-
233
+ module.exports = pushCmp;
@@ -34,8 +34,8 @@ const defaultNEOConfig = {
34
34
  template: resolveByDirname('../initData/defaultTemplate.html'), // 默认使用neo-widget提供的页面模板(会启动页面设计器)
35
35
  sassResources: [],
36
36
  babelPlugins: [
37
- ['import', { libraryName: 'antd', style: 'css' }], // 配置 antd 的样式按需引入
38
- ],
37
+ ['import', { libraryName: 'antd', style: 'css' }] // 配置 antd 的样式按需引入
38
+ ]
39
39
  },
40
40
  envParams: {
41
41
  // 项目系统环境变量
@@ -132,6 +132,18 @@ const defaultNEOConfig = {
132
132
  bucket: 'neo-widgets' // 存储桶名称
133
133
  },
134
134
  assetsRoot: resolve('dist') // 上传指定目录下的脚本文件
135
+ },
136
+ pushCmp: {
137
+ output: {
138
+ filename: '[name].js',
139
+ library: {
140
+ type: 'var', // webpack 5 中生成 IIFE 格式的 type 配置
141
+ export: 'default'
142
+ },
143
+ globalObject: 'this' // 定义全局变量,兼容node和浏览器运行,避免出现"window is not defined"的情况
144
+ },
145
+ cssExtract: false, // 不额外提取css文件
146
+ assetsRoot: resolve('dist') // 上传指定目录下的脚本文件
135
147
  }
136
148
  };
137
149