neo-cmp-cli 1.5.6 → 1.6.0-beta.10
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 +62 -47
- package/package.json +1 -1
- package/src/module/index.js +74 -19
- package/src/module/main.js +167 -267
- package/src/module/neoInit.js +1 -0
- package/src/neo/NeoUMDContent.js +6 -5
- package/src/neo/neoService.js +154 -43
- package/src/oss/publish2oss.js +174 -71
- package/src/template/antd-custom-cmp-template/README.md +26 -2
- package/src/template/antd-custom-cmp-template/neo.config.js +7 -4
- package/src/template/antd-custom-cmp-template/package.json +1 -0
- package/src/template/echarts-custom-cmp-template/README.md +26 -2
- package/src/template/echarts-custom-cmp-template/neo.config.js +9 -5
- package/src/template/echarts-custom-cmp-template/package.json +1 -0
- package/src/template/empty-custom-cmp-template/README.md +26 -0
- package/src/template/empty-custom-cmp-template/neo.config.js +7 -4
- package/src/template/empty-custom-cmp-template/package.json +1 -0
- package/src/template/neo-custom-cmp-template/README.md +26 -2
- package/src/template/neo-custom-cmp-template/neo.config.js +12 -9
- package/src/template/neo-custom-cmp-template/package.json +2 -1
- package/src/template/react-custom-cmp-template/README.md +26 -2
- package/src/template/react-custom-cmp-template/neo.config.js +7 -4
- package/src/template/react-custom-cmp-template/package.json +1 -0
- package/src/template/react-ts-custom-cmp-template/README.md +26 -2
- package/src/template/react-ts-custom-cmp-template/neo.config.js +7 -4
- package/src/template/react-ts-custom-cmp-template/package.json +1 -0
- package/src/template/vue2-custom-cmp-template/README.md +26 -2
- package/src/template/vue2-custom-cmp-template/neo.config.js +7 -4
- package/src/template/vue2-custom-cmp-template/package.json +1 -0
- package/src/{cmpUtils → utils/cmpUtils}/createCmpByTemplate.js +9 -7
- package/src/utils/cmpUtils/createCmpByZip.js +87 -0
- package/src/{cmpUtils → utils/cmpUtils}/createCommonModulesCode.js +2 -2
- package/src/{cmpUtils → utils/cmpUtils}/getCmpModelRegisterCode.js +1 -1
- package/src/{cmpUtils → utils/cmpUtils}/getCmpPreviewCode.js +1 -1
- package/src/{cmpUtils → utils/cmpUtils}/getCmpRegisterCode.js +1 -1
- package/src/{cmpUtils → utils/cmpUtils}/getCmpTypeByDir.js +2 -2
- package/src/{cmpUtils → utils/cmpUtils}/hasCmpTypeByDir.js +1 -1
- package/src/{cmpUtils → utils/cmpUtils}/previewCmp.js +3 -3
- package/src/utils/cmpUtils/pullCmp.js +95 -0
- package/src/{cmpUtils → utils/cmpUtils}/pushCmp.js +83 -73
- package/src/utils/common.js +48 -0
- package/src/utils/generateEntries.js +73 -0
- package/src/{projectUtils → utils/projectUtils}/createCmpProjectByTemplate.js +11 -7
- package/src/{projectUtils → utils/projectUtils}/createCmpProjectZip.js +18 -20
- package/src/{projectUtils → utils/projectUtils}/getEntries.js +2 -2
- package/src/{projectUtils → utils/projectUtils}/getEntriesWithAutoRegister.js +2 -2
- package/src/{projectUtils → utils/projectUtils}/hasNeoProject.js +2 -2
- package/src/{projectUtils → utils/projectUtils}/updatePublishLog.js +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
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.fail(`${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.fail(`${consoleTag}自定义组件模板下载失败:${err.message || err}`));
|
|
74
|
+
|
|
75
|
+
// 清理临时目录
|
|
76
|
+
await fs.remove(tempDir);
|
|
77
|
+
spinner.succeed(`${consoleTag}已成功从 zip 包解析自定义组件(${finalCmpName})!`);
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
spinner.fail(`${consoleTag}从 zip 包创建自定义组件失败(${finalCmpName}):`, error.message);
|
|
82
|
+
// 清理临时目录
|
|
83
|
+
await fs.remove(tempDir);
|
|
84
|
+
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const { resolveToCurrentRoot } = require('../
|
|
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,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { resolveToCurrentRoot } = require('../
|
|
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);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const akfun = require('akfun');
|
|
3
|
-
const { consoleTag } = require('../
|
|
4
|
-
const { resolveToCurrentRoot } = require('../
|
|
5
|
-
const getCmpPreviewCode = require('
|
|
3
|
+
const { consoleTag } = require('../neoParams'); // 输出标记
|
|
4
|
+
const { resolveToCurrentRoot } = require('../pathUtils');
|
|
5
|
+
const getCmpPreviewCode = require('./getCmpPreviewCode'); // 获取自定义组件预览代码
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 用于预览指定自定义组件的脚本
|
|
@@ -0,0 +1,95 @@
|
|
|
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.info('正在获取自定义组件列表...');
|
|
50
|
+
cmpList = await neoService.getCustomCmpList();
|
|
51
|
+
cmpInfoMap = neoService.cmpInfoMap || {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (cmpList.length === 0) {
|
|
55
|
+
spinner.fail('拉取失败,当前租户暂无任何自定义组件。');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 获取自定义组件信息
|
|
60
|
+
cmpInfo = neoService.getCmpInfoByCmpType(cmpType);
|
|
61
|
+
if (!cmpInfo) {
|
|
62
|
+
spinner.fail(`拉取失败,当前租户不存在${cmpType}自定义组件。`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 判断拉取的组件和当前项目是否为同一技术栈
|
|
67
|
+
if (cmpInfo.framework !== framework) {
|
|
68
|
+
spinner.fail(`拉取失败,${cmpType}自定义组件与当前项目技术栈不一致。`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 获取当前源码
|
|
73
|
+
if (!cmpInfo.codeLib) {
|
|
74
|
+
spinner.fail(`拉取失败,${cmpType}自定义组件未记录对应的源码文件。`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 下载源码文件并解析到 src/components 目录下
|
|
79
|
+
const codeLib = cmpInfo.codeLib; // 源码文件地址(zip包地址)
|
|
80
|
+
|
|
81
|
+
// 将zip 包里面的自定义组件源码解析到 src/components 目录下
|
|
82
|
+
const cmpResult = await createCmpByZip(codeLib, cmpType, './src/components');
|
|
83
|
+
if (!cmpResult) {
|
|
84
|
+
spinner.fail(`拉取失败,${cmpType}自定义组件源码解析失败,请检查源码文件是否正确。`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
spinner.succeed(`已成功拉取${cmpType}自定义组件!\n`);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
spinner.fail(`拉取自定义组件失败: ${error.message}`);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
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('../
|
|
5
|
-
const getConfigObj = require('../
|
|
4
|
+
const { catchCurPackageJson } = require('../pathUtils');
|
|
5
|
+
const getConfigObj = require('../getConfigObj');
|
|
6
6
|
const ora = require('ora');
|
|
7
|
-
const NeoService = require('
|
|
8
|
-
const {
|
|
7
|
+
const NeoService = require('../../neo/neoService');
|
|
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(
|
|
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,7 +81,8 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
|
116
81
|
...cmpInfo,
|
|
117
82
|
plugin: cmpInfo.modelAsset,
|
|
118
83
|
version: currentPackageJson.version || '1.0.0',
|
|
119
|
-
|
|
84
|
+
// 技术栈标识: 从 package.json / framework 字段获取,没有则默认 为 react ts 技术栈
|
|
85
|
+
framework: currentPackageJson.framework ? getFramework(currentPackageJson.framework) : 0, // 0: React, 1: vue2, 2: jQuery, 3: vue3
|
|
120
86
|
// 从模型实例中提取并设置组件信息
|
|
121
87
|
label: modelInstance.label || cmpType,
|
|
122
88
|
description: modelInstance.description || '',
|
|
@@ -128,9 +94,11 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
|
128
94
|
events: modelInstance.events || [],
|
|
129
95
|
actions: modelInstance.actions || [],
|
|
130
96
|
// 如果模型实例中有其他属性,也可以添加
|
|
131
|
-
exposedToDesigner:
|
|
97
|
+
exposedToDesigner:
|
|
98
|
+
modelInstance.exposedToDesigner !== undefined ? modelInstance.exposedToDesigner : true,
|
|
132
99
|
namespace: modelInstance.namespace || 'neo-cmp-cli',
|
|
133
|
-
enableDuplicate:
|
|
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}
|
|
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 /
|
|
129
|
+
console.error('未找到 NeoCRM 平台授权配置(neo.config.js / neoConfig)');
|
|
164
130
|
return;
|
|
165
131
|
}
|
|
166
132
|
|
|
@@ -168,33 +134,77 @@ const pushCmp = async (config, cmpType) => {
|
|
|
168
134
|
|
|
169
135
|
try {
|
|
170
136
|
// 步骤 1: 初始化 NeoService
|
|
171
|
-
|
|
172
|
-
|
|
137
|
+
let neoService = new NeoService(config);
|
|
138
|
+
// 获取 token
|
|
139
|
+
await neoService.ensureValidToken();
|
|
173
140
|
|
|
174
141
|
// 步骤 2: 打包源码文件(打包单个自定义组件源码)
|
|
175
|
-
spinner.
|
|
176
|
-
|
|
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.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
// 步骤
|
|
190
|
-
spinner.
|
|
191
|
-
|
|
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
|
-
|
|
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
194
|
} catch (error) {
|
|
195
|
-
spinner
|
|
195
|
+
// 内层 catch 已经处理了步骤错误并显示了 spinner 失败状态
|
|
196
|
+
// 这里处理未预期的错误(如果 spinner 还在运行)
|
|
197
|
+
try {
|
|
198
|
+
// ora 的 spinner 对象可能没有 isSpinning 属性,使用 try-catch 安全访问
|
|
199
|
+
if (spinner && spinner.isSpinning) {
|
|
200
|
+
spinner.fail(`❌ 自定义组件发布失败: ${error.message}`);
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
// 如果访问失败或 spinner 已停止,直接输出错误信息
|
|
204
|
+
console.error(`\n❌ 自定义组件发布失败: ${error.message}`);
|
|
205
|
+
}
|
|
196
206
|
throw error;
|
|
197
207
|
}
|
|
198
208
|
};
|
|
199
209
|
|
|
200
|
-
module.exports = pushCmp;
|
|
210
|
+
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,15 +1,15 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { consoleTag } = require('../
|
|
4
|
-
const { replaceInPackage } = require('../
|
|
5
|
-
const { resetPackageVersion } = require('../
|
|
6
|
-
const autoEntryRootDir = require('../
|
|
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 = {
|
|
10
10
|
'react-ts': {
|
|
11
11
|
projectName: 'empty-custom-cmp-template',
|
|
12
|
-
dir: path.resolve(__dirname, '
|
|
12
|
+
dir: path.resolve(__dirname, '../../template/empty-custom-cmp-template')
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -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(
|
|
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(
|
|
32
|
+
console.error(
|
|
33
|
+
`${consoleTag}创建自定义组件项目失败,当前已存在(${projectName})项目,请勿创建重名项目。`
|
|
34
|
+
);
|
|
31
35
|
process.exit(1);
|
|
32
36
|
}
|
|
33
37
|
|