@arkxio/ark-dev-utils 0.1.5 → 0.1.8

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.
@@ -1,84 +1,84 @@
1
- import fs from 'fs';
2
- import { verbose } from '../inner-utils/index';
3
- import { fillAssetListByDist } from './fillAssetList';
4
- import { parseIndexHtml } from './parse';
5
- import { getIndexHtmlFileName, makeArkMetaJson } from './utils';
6
- import path from "path";
7
- import {noDupPush} from "../inner-utils/arr";
8
-
9
- /**
10
- * 从 index.html 提取资源的描述数据,包含 htmlContent、srcMap
11
- * @param {import('../../typings').IUserExtractOptions} userExtractOptions
12
- */
13
- export default async function extractArkMetaJson(userExtractOptions) {
14
- const { buildDirFullPath, writeMetaJsonToDist = true } = userExtractOptions;
15
- const appInfo = userExtractOptions.appInfo || userExtractOptions.subApp;
16
- const indexHtmlName = userExtractOptions.indexHtmlName || 'index.html';// getIndexHtmlFileName(buildDirFullPath);
17
-
18
- if (!appInfo) {
19
- throw new Error('appInfo should be supplied in ver 3.0+ ark-dev-utils: extractArkMetaJson({appInfo, ...})');
20
- }
21
-
22
- const { homePage } = appInfo;
23
- const options = { ...userExtractOptions, appInfo, subApp: appInfo, indexHtmlName };
24
-
25
- verbose(`start extractArkMetaJson, appHomePage is [${homePage}]`);
26
- // 分析 html 入口,提取 sdk 加载需要的资源清单
27
- const parsedRet = await parseIndexHtml(options);
28
- // 分析构建产物目录,提取剩余的资源清单补充到 chunkJsSrcList chunkCssSrcList 下,以便描述出应用的所有构建产物的资源路径
29
- // fillAssetListByDist({ ...userExtractOptions, srcMap: parsedRet.srcMap, homePage, buildDirFullPath });
30
- if (userExtractOptions.chunkJsFiles) {
31
- for (const chunkJsFile of userExtractOptions.chunkJsFiles) {
32
- noDupPush(parsedRet.srcMap.chunkJsSrcList, chunkJsFile);
33
-
34
- noDupPush(parsedRet.srcMap.bodyAssetList, {
35
- tag: 'script',
36
- append: true,
37
- attrs: {
38
- src: chunkJsFile,
39
- type: 'text/javascript',
40
- },
41
- });
42
- }
43
- }
44
-
45
- // 有替换内容生成,则将 index.html 内容重写,让后续上传 cdn 步骤上传的是替换后的文件内容
46
- if (parsedRet.hasReplacedContent) {
47
- const htmlFilePath = `${buildDirFullPath}/${indexHtmlName}`;
48
- fs.writeFileSync(htmlFilePath, parsedRet.htmlContent, { encoding: 'utf-8' });
49
- }
50
-
51
- const arkMeta = makeArkMetaJson(options, parsedRet);
52
- verbose('userExtractOptions.isDev', userExtractOptions.isDev)
53
- if(userExtractOptions.isDev) {
54
- // 开发模式:写入内存文件系统
55
- const metaFilename = 'ark-meta.json';
56
- verbose('[begin] write memory ark meta ' + metaFilename)
57
-
58
- const metaContent = JSON.stringify(arkMeta, null, 2);
59
- const compilation = userExtractOptions.compilation;
60
-
61
- // Webpack 5 正确的 API:使用 emitAsset
62
- if (compilation.emitAsset) {
63
- const { sources } = compilation.compiler.webpack;
64
- compilation.emitAsset(
65
- metaFilename,
66
- new sources.RawSource(metaContent)
67
- );
68
- } else {
69
- // Webpack 4 兼容
70
- compilation.assets[metaFilename] = {
71
- source: () => metaContent,
72
- size: () => metaContent.length
73
- };
74
- }
75
- verbose('[finish] write memory ark meta ' + metaFilename)
76
- }else if (writeMetaJsonToDist) {
77
- // 生产模式:写入物理文件
78
- const arkMetaJsonFile = `${buildDirFullPath}/ark-meta.json`;
79
- verbose('finish write ark meta')
80
- fs.writeFileSync(arkMetaJsonFile, JSON.stringify(arkMeta, null, 2));
81
- }
82
-
83
- return arkMeta;
84
- }
1
+ import fs from 'fs';
2
+ import { verbose } from '../inner-utils/index';
3
+ import { fillAssetListByDist } from './fillAssetList';
4
+ import { parseIndexHtml } from './parse';
5
+ import { getIndexHtmlFileName, makeArkMetaJson } from './utils';
6
+ import path from "path";
7
+ import {noDupPush} from "../inner-utils/arr";
8
+
9
+ /**
10
+ * 从 index.html 提取资源的描述数据,包含 htmlContent、srcMap
11
+ * @param {import('../../typings').IUserExtractOptions} userExtractOptions
12
+ */
13
+ export default async function extractArkMetaJson(userExtractOptions) {
14
+ const { buildDirFullPath, writeMetaJsonToDist = true } = userExtractOptions;
15
+ const appInfo = userExtractOptions.appInfo || userExtractOptions.subApp;
16
+ const indexHtmlName = userExtractOptions.indexHtmlName || 'index.html';// getIndexHtmlFileName(buildDirFullPath);
17
+
18
+ if (!appInfo) {
19
+ throw new Error('appInfo should be supplied in ver 3.0+ ark-dev-utils: extractArkMetaJson({appInfo, ...})');
20
+ }
21
+
22
+ const { homePage } = appInfo;
23
+ const options = { ...userExtractOptions, appInfo, subApp: appInfo, indexHtmlName };
24
+
25
+ verbose(`start extractArkMetaJson, appHomePage is [${homePage}]`);
26
+ // 分析 html 入口,提取 sdk 加载需要的资源清单
27
+ const parsedRet = await parseIndexHtml(options);
28
+ // 分析构建产物目录,提取剩余的资源清单补充到 chunkJsSrcList chunkCssSrcList 下,以便描述出应用的所有构建产物的资源路径
29
+ // fillAssetListByDist({ ...userExtractOptions, srcMap: parsedRet.srcMap, homePage, buildDirFullPath });
30
+ if (userExtractOptions.chunkJsFiles) {
31
+ for (const chunkJsFile of userExtractOptions.chunkJsFiles) {
32
+ noDupPush(parsedRet.srcMap.chunkJsSrcList, chunkJsFile);
33
+
34
+ noDupPush(parsedRet.srcMap.bodyAssetList, {
35
+ tag: 'script',
36
+ append: true,
37
+ attrs: {
38
+ src: chunkJsFile,
39
+ type: 'text/javascript',
40
+ },
41
+ });
42
+ }
43
+ }
44
+
45
+ // 有替换内容生成,则将 index.html 内容重写,让后续上传 cdn 步骤上传的是替换后的文件内容
46
+ if (parsedRet.hasReplacedContent) {
47
+ const htmlFilePath = `${buildDirFullPath}/${indexHtmlName}`;
48
+ fs.writeFileSync(htmlFilePath, parsedRet.htmlContent, { encoding: 'utf-8' });
49
+ }
50
+
51
+ const arkMeta = makeArkMetaJson(options, parsedRet);
52
+ verbose('userExtractOptions.isDev', userExtractOptions.isDev)
53
+ if(userExtractOptions.isDev) {
54
+ // 开发模式:写入内存文件系统
55
+ const metaFilename = 'ark-meta.json';
56
+ verbose('[begin] write memory ark meta ' + metaFilename)
57
+
58
+ const metaContent = JSON.stringify(arkMeta, null, 2);
59
+ const compilation = userExtractOptions.compilation;
60
+
61
+ // Webpack 5 正确的 API:使用 emitAsset
62
+ if (compilation.emitAsset) {
63
+ const { sources } = compilation.compiler.webpack;
64
+ compilation.emitAsset(
65
+ metaFilename,
66
+ new sources.RawSource(metaContent)
67
+ );
68
+ } else {
69
+ // Webpack 4 兼容
70
+ compilation.assets[metaFilename] = {
71
+ source: () => metaContent,
72
+ size: () => metaContent.length
73
+ };
74
+ }
75
+ verbose('[finish] write memory ark meta ' + metaFilename)
76
+ }else if (writeMetaJsonToDist) {
77
+ // 生产模式:写入物理文件
78
+ const arkMetaJsonFile = `${buildDirFullPath}/ark-meta.json`;
79
+ verbose('finish write ark meta')
80
+ fs.writeFileSync(arkMetaJsonFile, JSON.stringify(arkMeta, null, 2));
81
+ }
82
+
83
+ return arkMeta;
84
+ }
@@ -1,56 +1,56 @@
1
- /** @typedef {import('../../typings').SrcMap} SrcMap */
2
- /** @typedef {import('../../typings').IUserExtractOptions} IUserExtractOptions */
3
- /** @typedef {import('../../typings').IInnerFillAssetListOptions} IInnerFillAssetListOptions */
4
- import * as fs from 'fs';
5
- import jsdom from 'jsdom';
6
- import * as util from 'util';
7
- import cst from '../configs/consts';
8
- import { verbose } from '../inner-utils/index';
9
- import { fillAssetList } from './fillAssetList';
10
- import { makeAppVersionSrcMap } from './utils';
11
-
12
- const readFile = util.promisify(fs.readFile);
13
- const { JSDOM } = jsdom;
14
-
15
- /**
16
- * @param {IUserExtractOptions} extractOptions
17
- */
18
- export async function parseIndexHtml(extractOptions) {
19
- const { appInfo, indexHtmlPath, extractMode = 'all', indexHtmlName = cst.DEFAULT_HTML_INDEX_NAME } = extractOptions;
20
- const { name, homePage } = appInfo;
21
- const htmlFilePath = `${indexHtmlPath}`;
22
- verbose(`start to parse ${name} index.html file [${indexHtmlPath}]`);
23
-
24
- let htmlContent = await readFile(htmlFilePath, { encoding: 'UTF-8' });
25
- const srcMap = makeAppVersionSrcMap(extractOptions);
26
-
27
- const dom = new JSDOM(htmlContent);
28
- const { head, body } = dom.window.document;
29
- /** @type {IInnerFillAssetListOptions} */
30
- const fillAssetListOptions = { srcMap, homePage, ...extractOptions };
31
- const [replaceContentListOfHead, replaceContentLisOfBody] = await Promise.all([
32
- fillAssetList(head.children, { ...fillAssetListOptions, isHead: true }),
33
- fillAssetList(body.children, fillAssetListOptions),
34
- ]);
35
-
36
- replaceContentListOfHead.forEach((item) => {
37
- htmlContent = htmlContent.replace(item.toMatch, item.toReplace);
38
- });
39
- replaceContentLisOfBody.forEach((item) => {
40
- htmlContent = htmlContent.replace(item.toMatch, item.toReplace);
41
- });
42
-
43
- const shouldRecordHtmlContent = extractMode === 'all' || extractMode === 'build';
44
- const htmlContentVar = shouldRecordHtmlContent ? htmlContent : '';
45
- if (!shouldRecordHtmlContent) {
46
- verbose(`user set extractMode='${extractMode}', dev-utils will ignore write version.html_content`);
47
- }
48
-
49
- const hasReplacedContent = replaceContentListOfHead.length || replaceContentLisOfBody.length;
50
- const parsedRet = { srcMap, htmlContent: htmlContentVar, hasReplacedContent };
51
- verbose(`parse app [${name}] index.html file done!`);
52
- verbose('replaceContentListOfHead: ', replaceContentListOfHead);
53
- verbose('replaceContentLisOfBody: ', replaceContentLisOfBody);
54
- verbose('parsedRet: ', parsedRet);
55
- return parsedRet;
56
- }
1
+ /** @typedef {import('../../typings').SrcMap} SrcMap */
2
+ /** @typedef {import('../../typings').IUserExtractOptions} IUserExtractOptions */
3
+ /** @typedef {import('../../typings').IInnerFillAssetListOptions} IInnerFillAssetListOptions */
4
+ import * as fs from 'fs';
5
+ import jsdom from 'jsdom';
6
+ import * as util from 'util';
7
+ import cst from '../configs/consts';
8
+ import { verbose } from '../inner-utils/index';
9
+ import { fillAssetList } from './fillAssetList';
10
+ import { makeAppVersionSrcMap } from './utils';
11
+
12
+ const readFile = util.promisify(fs.readFile);
13
+ const { JSDOM } = jsdom;
14
+
15
+ /**
16
+ * @param {IUserExtractOptions} extractOptions
17
+ */
18
+ export async function parseIndexHtml(extractOptions) {
19
+ const { appInfo, indexHtmlPath, extractMode = 'all', indexHtmlName = cst.DEFAULT_HTML_INDEX_NAME } = extractOptions;
20
+ const { name, homePage } = appInfo;
21
+ const htmlFilePath = `${indexHtmlPath}`;
22
+ verbose(`start to parse ${name} index.html file [${indexHtmlPath}]`);
23
+
24
+ let htmlContent = await readFile(htmlFilePath, { encoding: 'UTF-8' });
25
+ const srcMap = makeAppVersionSrcMap(extractOptions);
26
+
27
+ const dom = new JSDOM(htmlContent);
28
+ const { head, body } = dom.window.document;
29
+ /** @type {IInnerFillAssetListOptions} */
30
+ const fillAssetListOptions = { srcMap, homePage, ...extractOptions };
31
+ const [replaceContentListOfHead, replaceContentLisOfBody] = await Promise.all([
32
+ fillAssetList(head.children, { ...fillAssetListOptions, isHead: true }),
33
+ fillAssetList(body.children, fillAssetListOptions),
34
+ ]);
35
+
36
+ replaceContentListOfHead.forEach((item) => {
37
+ htmlContent = htmlContent.replace(item.toMatch, item.toReplace);
38
+ });
39
+ replaceContentLisOfBody.forEach((item) => {
40
+ htmlContent = htmlContent.replace(item.toMatch, item.toReplace);
41
+ });
42
+
43
+ const shouldRecordHtmlContent = extractMode === 'all' || extractMode === 'build';
44
+ const htmlContentVar = shouldRecordHtmlContent ? htmlContent : '';
45
+ if (!shouldRecordHtmlContent) {
46
+ verbose(`user set extractMode='${extractMode}', dev-utils will ignore write version.html_content`);
47
+ }
48
+
49
+ const hasReplacedContent = replaceContentListOfHead.length || replaceContentLisOfBody.length;
50
+ const parsedRet = { srcMap, htmlContent: htmlContentVar, hasReplacedContent };
51
+ verbose(`parse app [${name}] index.html file done!`);
52
+ verbose('replaceContentListOfHead: ', replaceContentListOfHead);
53
+ verbose('replaceContentLisOfBody: ', replaceContentLisOfBody);
54
+ verbose('parsedRet: ', parsedRet);
55
+ return parsedRet;
56
+ }
@@ -1,141 +1,141 @@
1
- /** @typedef {import('../../typings').SrcMap} SrcMap*/
2
- import * as fs from 'fs';
3
- import { slash } from '../base-utils/index';
4
- import cst from '../configs/consts';
5
-
6
- export function getIndexHtmlFileName(dirPath) {
7
- const names = fs.readdirSync(dirPath);
8
- let indexHtmlName = '';
9
- let matchCount = 0;
10
- names.forEach((name) => {
11
- if (name.endsWith('.html')) {
12
- matchCount += 1;
13
- indexHtmlName = name;
14
- }
15
- });
16
- if (!matchCount) {
17
- throw new Error('no index.html found');
18
- }
19
- if (matchCount > 1) {
20
- throw new Error(`there are more than one indexHtml file under [${dirPath}]!`);
21
- }
22
- return indexHtmlName;
23
- }
24
-
25
- /**
26
- * 递归获得某个目录下的所有文件绝对路径
27
- * @param {string} dirPath 形如:/user/zzk/log/build
28
- * @return {string[]} filePathList
29
- * 形如 ['/user/zzk/log/build/js/xx.js', '/user/zzk/log/build/img/xx.png']
30
- */
31
- export function getAllFilePath(dirPath) {
32
- const _getAllFilePath = (dirPath, filePathList) => {
33
- const names = fs.readdirSync(dirPath);
34
- names.forEach((name) => {
35
- const stats = fs.statSync(`${dirPath}/${name}`);
36
- if (stats.isDirectory()) {
37
- _getAllFilePath(`${dirPath}/${name}`, filePathList);
38
- } else {
39
- filePathList.push(`${dirPath}/${name}`);
40
- }
41
- });
42
- };
43
-
44
- const filePathList = [];
45
- _getAllFilePath(dirPath, filePathList);
46
- return filePathList;
47
- }
48
-
49
- /**
50
- * @param {import('../../typings').IUserExtractOptions} extractOptions
51
- */
52
- export function makeAppVersionSrcMap(extractOptions) {
53
- const { appInfo, indexHtmlName = cst.DEFAULT_HTML_INDEX_NAME, extractMode = 'all' } = extractOptions;
54
- const { homePage } = appInfo;
55
- // 用于更新到数据库的app信息,通常来说在构建机器上触发
56
- // 从上往下的key顺序也是在html创建的顺序
57
- return {
58
- webDirPath: homePage,
59
- htmlIndexSrc: `${slash.end(homePage)}${indexHtmlName}`,
60
- extractMode,
61
- iframeSrc: '',
62
- chunkCssSrcList: [], // all build css files
63
- chunkJsSrcList: [], // all build js files
64
- staticCssSrcList: [], // all static css files
65
- staticJsSrcList: [], // all static js files
66
- relativeCssSrcList: [], // all relative js files
67
- relativeJsSrcList: [], // all relative js files
68
- headAssetList: [],
69
- bodyAssetList: [],
70
- otherSrcList: [],
71
- };
72
- }
73
-
74
- /**
75
- * 从 index.html 提取资源的描述数据,包含 htmlContent、srcMap
76
- * @param {import('../../typings').IUserExtractOptions} userExtractOptions
77
- */
78
- export function makeArkMetaJson(userExtractOptions, parsedRet) {
79
- const { packageJson, extractMode = 'build', subApp } = userExtractOptions;
80
- const { homePage, groupName, name: appName, semverApi } = subApp;
81
-
82
- /**
83
- * 构建版本号,当指定了 homePage 且不想采用默认的版本号生成规则时,才需要透传 buildVer 值
84
- * 默认生成规则:
85
- * 内网包:裁出 homePage ${cdnHost}/${appZone}/${appName}_${dateStr} 里的 ${appName}_${dateStr} 作为版本号
86
- * 外网包:pkg.version
87
- */
88
- let version = userExtractOptions.buildVer;
89
- const packVer = packageJson.version;
90
- if (!version) {
91
- if (semverApi) {
92
- version = packVer;
93
- } else {
94
- try {
95
- // ${cdnHost}/${appZone}/${appName}_${dateStr}
96
- const [, restStr] = homePage.split('//');
97
- const [, , versionMakeOnPipeline] = restStr.split('/');
98
- if (versionMakeOnPipeline) {
99
- const arr = versionMakeOnPipeline.split('_');
100
- const lastItem = arr[arr.length - 1];
101
- // 特征符合 arkpack 的版本号
102
- if (lastItem && lastItem.length === 14 && new RegExp('^[1-9]+[0-9]*$').test(lastItem)) {
103
- version = versionMakeOnPipeline;
104
- }
105
- }
106
- } catch (err) {}
107
-
108
- if (!version) {
109
- // 自定义 homePage 后,版本未必能推导出来,降级为使用 package.json 版本号
110
- version = packVer;
111
- }
112
- }
113
- }
114
- const repo = packageJson.repository || {};
115
-
116
- // 新增依赖处理逻辑
117
- const { dependencies = {}, arkDependencies = {} } = packageJson;
118
- const arklibDeps = Object.entries(dependencies)
119
- .filter(([name]) => name.indexOf('arklib-') !== -1)
120
- .reduce((acc, [name, version]) => ({ ...acc, [name]: version }), {});
121
-
122
- return {
123
- app: {
124
- name: appName,
125
- app_group_name: groupName,
126
- git_repo_url: repo.url || packageJson.homepage || '',
127
- online_version: version,
128
- build_version: version,
129
- },
130
- version: {
131
- plugin_ver: cst.PLUGIN_VER,
132
- extract_mode: extractMode,
133
- sub_app_name: appName,
134
- sub_app_version: version,
135
- // ... existing version fields ...
136
- arkDependencies: { ...arklibDeps, ...arkDependencies },
137
- src_map: parsedRet.srcMap,
138
- html_content: parsedRet.htmlContent,
139
- },
140
- };
141
- }
1
+ /** @typedef {import('../../typings').SrcMap} SrcMap*/
2
+ import * as fs from 'fs';
3
+ import { slash } from '../base-utils/index';
4
+ import cst from '../configs/consts';
5
+
6
+ export function getIndexHtmlFileName(dirPath) {
7
+ const names = fs.readdirSync(dirPath);
8
+ let indexHtmlName = '';
9
+ let matchCount = 0;
10
+ names.forEach((name) => {
11
+ if (name.endsWith('.html')) {
12
+ matchCount += 1;
13
+ indexHtmlName = name;
14
+ }
15
+ });
16
+ if (!matchCount) {
17
+ throw new Error('no index.html found');
18
+ }
19
+ if (matchCount > 1) {
20
+ throw new Error(`there are more than one indexHtml file under [${dirPath}]!`);
21
+ }
22
+ return indexHtmlName;
23
+ }
24
+
25
+ /**
26
+ * 递归获得某个目录下的所有文件绝对路径
27
+ * @param {string} dirPath 形如:/user/zzk/log/build
28
+ * @return {string[]} filePathList
29
+ * 形如 ['/user/zzk/log/build/js/xx.js', '/user/zzk/log/build/img/xx.png']
30
+ */
31
+ export function getAllFilePath(dirPath) {
32
+ const _getAllFilePath = (dirPath, filePathList) => {
33
+ const names = fs.readdirSync(dirPath);
34
+ names.forEach((name) => {
35
+ const stats = fs.statSync(`${dirPath}/${name}`);
36
+ if (stats.isDirectory()) {
37
+ _getAllFilePath(`${dirPath}/${name}`, filePathList);
38
+ } else {
39
+ filePathList.push(`${dirPath}/${name}`);
40
+ }
41
+ });
42
+ };
43
+
44
+ const filePathList = [];
45
+ _getAllFilePath(dirPath, filePathList);
46
+ return filePathList;
47
+ }
48
+
49
+ /**
50
+ * @param {import('../../typings').IUserExtractOptions} extractOptions
51
+ */
52
+ export function makeAppVersionSrcMap(extractOptions) {
53
+ const { appInfo, indexHtmlName = cst.DEFAULT_HTML_INDEX_NAME, extractMode = 'all' } = extractOptions;
54
+ const { homePage } = appInfo;
55
+ // 用于更新到数据库的app信息,通常来说在构建机器上触发
56
+ // 从上往下的key顺序也是在html创建的顺序
57
+ return {
58
+ webDirPath: homePage,
59
+ htmlIndexSrc: `${slash.end(homePage)}${indexHtmlName}`,
60
+ extractMode,
61
+ iframeSrc: '',
62
+ chunkCssSrcList: [], // all build css files
63
+ chunkJsSrcList: [], // all build js files
64
+ staticCssSrcList: [], // all static css files
65
+ staticJsSrcList: [], // all static js files
66
+ relativeCssSrcList: [], // all relative js files
67
+ relativeJsSrcList: [], // all relative js files
68
+ headAssetList: [],
69
+ bodyAssetList: [],
70
+ otherSrcList: [],
71
+ };
72
+ }
73
+
74
+ /**
75
+ * 从 index.html 提取资源的描述数据,包含 htmlContent、srcMap
76
+ * @param {import('../../typings').IUserExtractOptions} userExtractOptions
77
+ */
78
+ export function makeArkMetaJson(userExtractOptions, parsedRet) {
79
+ const { packageJson, extractMode = 'build', subApp } = userExtractOptions;
80
+ const { homePage, groupName, name: appName, semverApi } = subApp;
81
+
82
+ /**
83
+ * 构建版本号,当指定了 homePage 且不想采用默认的版本号生成规则时,才需要透传 buildVer 值
84
+ * 默认生成规则:
85
+ * 内网包:裁出 homePage ${cdnHost}/${appZone}/${appName}_${dateStr} 里的 ${appName}_${dateStr} 作为版本号
86
+ * 外网包:pkg.version
87
+ */
88
+ let version = userExtractOptions.buildVer;
89
+ const packVer = packageJson.version;
90
+ if (!version) {
91
+ if (semverApi) {
92
+ version = packVer;
93
+ } else {
94
+ try {
95
+ // ${cdnHost}/${appZone}/${appName}_${dateStr}
96
+ const [, restStr] = homePage.split('//');
97
+ const [, , versionMakeOnPipeline] = restStr.split('/');
98
+ if (versionMakeOnPipeline) {
99
+ const arr = versionMakeOnPipeline.split('_');
100
+ const lastItem = arr[arr.length - 1];
101
+ // 特征符合 arkpack 的版本号
102
+ if (lastItem && lastItem.length === 14 && new RegExp('^[1-9]+[0-9]*$').test(lastItem)) {
103
+ version = versionMakeOnPipeline;
104
+ }
105
+ }
106
+ } catch (err) {}
107
+
108
+ if (!version) {
109
+ // 自定义 homePage 后,版本未必能推导出来,降级为使用 package.json 版本号
110
+ version = packVer;
111
+ }
112
+ }
113
+ }
114
+ const repo = packageJson.repository || {};
115
+
116
+ // 新增依赖处理逻辑
117
+ const { dependencies = {}, arkDependencies = {} } = packageJson;
118
+ const arklibDeps = Object.entries(dependencies)
119
+ .filter(([name]) => name.indexOf('arklib-') !== -1)
120
+ .reduce((acc, [name, version]) => ({ ...acc, [name]: version }), {});
121
+
122
+ return {
123
+ app: {
124
+ name: appName,
125
+ app_group_name: groupName,
126
+ git_repo_url: repo.url || packageJson.homepage || '',
127
+ online_version: version,
128
+ build_version: version,
129
+ },
130
+ version: {
131
+ plugin_ver: cst.PLUGIN_VER,
132
+ extract_mode: extractMode,
133
+ sub_app_name: appName,
134
+ sub_app_version: version,
135
+ // ... existing version fields ...
136
+ arkDependencies: { ...arklibDeps, ...arkDependencies },
137
+ src_map: parsedRet.srcMap,
138
+ html_content: parsedRet.htmlContent,
139
+ },
140
+ };
141
+ }