UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

252 lines 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getReleaseFormData = exports.prepareExtensionConfigMap = exports.getBundleFilesOptions = exports.getReleaseDataForParallel = exports.getReleaseData = void 0; const types_1 = require("./types"); const utils_1 = require("../../utils"); const body_1 = require("./body"); const utils_2 = require("./utils"); const nasl_types_1 = require("@lcap/nasl-types"); const utils_3 = require("../../utils"); async function getReleaseData(app, data, naslServer, inputLogger, isBackendValidation) { return (await getReleaseDataInternal(app, data, naslServer, inputLogger, isBackendValidation)).releaseBody; } exports.getReleaseData = getReleaseData; // 相对 getReleaseData 函数,getReleaseDataForParallel 需要额外返回调用参数 app/opt,以供并行发布中的前端编译使用 async function getReleaseDataForParallel(app, data, naslServer, inputLogger, isBackendValidation) { return getReleaseDataInternal(app, data, naslServer, inputLogger, isBackendValidation); } exports.getReleaseDataForParallel = getReleaseDataForParallel; async function getAppInfo(http, data, logger) { if (globalThis.appInfo) { return globalThis.appInfo; } const result = await (0, utils_2.getAppInfo)(http, data); await logger.info('构建环境', '获取环境信息成功', nasl_types_1.Deployment.Session.GetEnvData); return result; } async function getVersionDetail(http, app, logger) { if (globalThis.globalData?.ideVersionDetail) { return globalThis.globalData.ideVersionDetail; } const result = await (0, utils_2.getVersionDetail)(http, app); await logger.info('构建环境', '获取版本数据成功', nasl_types_1.Deployment.Session.GetVersionData); return result; } async function getBundleFilesOptions(app, data, naslServer, inputLogger) { const { http, logger: defaultLogger } = naslServer; const logger = inputLogger ?? defaultLogger; console.time('all'); console.time('request'); const appInfo = await getAppInfo(http, data, logger); const { version, fullVersion } = await getVersionDetail(http, app, logger); const allFrontend = (0, utils_2.getFrontendByTypes)(app.frontendTypes); const inputFrontendNames = (data.config.frontendNames ?? []).filter(Boolean); const releaseFrontends = inputFrontendNames.length > 0 ? allFrontend.filter((item) => data.config.frontendNames.includes(item.name)) : allFrontend; const result = { appInfo, version, fullVersion, env: data.env, envTag: data.envTag, branchId: data.branchId, debug: data.config.debug ?? false, replicas: data.replicas ?? 1, isIncremental: data.config.mode === types_1.ReleaseMode.IncrementalRelease, realRelease: data.config.mode === types_1.ReleaseMode.Release || data.config.mode === types_1.ReleaseMode.IncrementalRelease, isExport: data.config.mode === types_1.ReleaseMode.ExportCode, isPreviewFe: data.config.mode === types_1.ReleaseMode.ExportTemplate, ignoreFiles: data.config.ignoreFiles ?? false, previewVersion: data.config.previewVersion, appSpecification: data.appSpecification, frontends: releaseFrontends, validations: { validationRules: {}, downloadFileTasks: {}, }, assets: [], assetsMap: new Map(), // URL中读取的 beta 开关 extensionConfigMap: prepareExtensionConfigMap(), logPublishFunc: (text) => logger.info('前端生成器', text), }; // 设置依赖数据 if (app.packageInfos.length === 0) { app.packageInfos = await (0, utils_2.getPackageInfos)(http, app, appInfo.STATIC_URL, fullVersion); await logger.info('构建环境', '设置依赖库内容'); } return result; } exports.getBundleFilesOptions = getBundleFilesOptions; /** * 从URL中读取beta开关参数 * @returns */ function prepareExtensionConfigMap() { // 从URL中读取heuristicalSplit系列参数 const heuristicalSplitEnabledRaw = new URLSearchParams(globalThis?.location?.search).get('heuristicalSplitEnabled'); const heuristicalSplitSizeThresholdRaw = new URLSearchParams(globalThis?.location?.search).get('heuristicalSplitSizeThreshold'); const sizeThreshold = Number(heuristicalSplitSizeThresholdRaw); return { heuristicalSplit: { enabled: heuristicalSplitEnabledRaw === 'true', sizeThreshold: Math.max(Number.isInteger(sizeThreshold) ? sizeThreshold : 1, 1), }, }; } exports.prepareExtensionConfigMap = prepareExtensionConfigMap; function getCallLogicUuidToHeaderMap(validations) { const callLogicUuidToHeaderMap = {}; Object.values(validations).forEach((arr) => { arr.forEach(({ uuid, appHeader }) => { if (uuid && appHeader) callLogicUuidToHeaderMap[uuid] = appHeader; }); }); return callLogicUuidToHeaderMap; } async function getReleaseDataInternal(__app, data, naslServer, inputLogger, isBackendValidation) { // @ts-ignore toRaw 是静态函数 const app = naslServer.constructor.toRaw(__app); const { http, logger: defaultLogger } = naslServer; const logger = inputLogger ?? defaultLogger; const result = await getBundleFilesOptions(app, data, naslServer, inputLogger); const assets = await (0, utils_2.loadFiles)(http, data.appId); const assetsMap = new Map(); assets.forEach((asset) => { const { fileUrl } = asset; assetsMap.set(fileUrl, asset); }); result.assetsMap = assetsMap; // Defer assets array creation to reduce memory duplication // We'll create the array just before it's needed in the result // 私有化环境,需要同步资源;内部环境暂不需要,针对使用 CDN 场景增加判断 if (String(result.appInfo.isPrivatized) === 'true') { result.staticUrl = await (0, utils_2.staticResourceSync)(http, assets, data.appId, data.env, result.frontends); logger.info('构建环境', '私有化部署同步资源成功', nasl_types_1.Deployment.Session.SyncPrivateResource); } // Release assets array early to save memory - we only need the Map going forward assets.length = 0; console.time('fastGetNaslAnnotatedJSON'); console.info('等待当前类型检查完成...'); await app.naslServer?.lsRunEnd; console.info('当前类型检查已完成'); let annotatedNaslJson = result.isIncremental ? undefined : await (0, body_1.__getNaslAnnotatedJSON)(app, { ...result, logPublishFunc: (...message) => logger.info(...message), }); console.timeEnd('fastGetNaslAnnotatedJSON'); let downloadFileTasks = {}; let naslJsonForFile = null; // For memory optimization // 是否由服务端自己来获取校验规则,不是的话需要前端获取校验规则数据传给服务端 if (!isBackendValidation) { if ((0, utils_2.needFrontendBatch)(app)) { let batchData = await (0, utils_2.getValidationRules)(http, result.version, app.frontendTypes); result.validations = batchData || {}; // 关掉按需生成,CallLogic不需要传 header let uuidToHeaderMap = getCallLogicUuidToHeaderMap(batchData?.validationRules); app.saveCallLogicUuidToHeaderMap(uuidToHeaderMap); // Clear the map reference to help with garbage collection uuidToHeaderMap = null; // result.downloadFileTasks = downloadFileTasks = batchData.downloadFileTasks || {}; batchData = null; if (typeof result.validations === 'string') { throw new Error(result.validations); } else { logger.info('生成器', '服务端验证数据获取成功', nasl_types_1.Deployment.Session.GetServiceValidation); } // 暂时发布的时候加一个实体 // 为了服务端发布,使用文件系统,标注的nasl 强制增加一个 // 服务端承诺 2024年10月份会挪走, @钟春燕 @杨剑飞 if (Object.keys(result.validations?.downloadFileTasks || {}).length) { const defaultDS = annotatedNaslJson?.dataSources?.find((item) => item.name === 'defaultDS'); if (defaultDS) { (0, body_1.addEntityToDefaultDS)(app, defaultDS); } } } else { app.saveCallLogicUuidToHeaderMap({}); } } // Memory optimization: Store stringified JSON and release the large object early naslJsonForFile = annotatedNaslJson ? JSON.stringify(annotatedNaslJson) : null; annotatedNaslJson = null; // Release large object early to save memory await (0, utils_1.delay)(200); // Memory monitoring - log memory usage if available if (performance?.memory) { const memory = performance.memory; const usedMB = Math.round(memory.usedJSHeapSize / 1024 / 1024); console.log(`当前内存使用: ${usedMB}MB`); } console.timeEnd('request'); console.time('前端构建'); logger.info('构建环境', '构建环境完成,开始拼装发布数据'); const releaseBodyRes = await (0, body_1.genReleaseBodyForParallel)(app, { ...result, isBackendValidation, logPublishFunc: (...message) => logger.info(...message), }); // 是否由服务端自己来获取校验规则,是的话只需要将获取校验规则的参数传给服务端即可 if (isBackendValidation) { if ((0, utils_2.needFrontendBatch)(app)) { let frontendNaslAnnotatedJSON = (0, utils_2.transformFrontendsToJson)(app.frontendTypes); releaseBodyRes.releaseBody.files.push({ name: 'frontend-nasl-annotated.json', content: JSON.stringify(frontendNaslAnnotatedJSON), }); frontendNaslAnnotatedJSON = null; await (0, utils_1.delay)(200); } } else { releaseBodyRes.releaseBody.downloadFileTasks = downloadFileTasks; downloadFileTasks = null; // Release large validation data after assignment } if (naslJsonForFile) { releaseBodyRes.releaseBody.files.push({ name: 'nasl-annotated.json', content: naslJsonForFile, }); } await (0, utils_1.delay)(200); // 前端额外配置 if (data.config.frontCodeExtraConfig) { releaseBodyRes.releaseBody.frontCodeExtraConfig = data.config.frontCodeExtraConfig; } logger.info('前端生成器', '应用发布数据准备完成', nasl_types_1.Deployment.Session.AssemblyFrontData); console.timeEnd('前端构建'); console.timeEnd('all'); if (result.isIncremental) { logger.info('前端生成器', '开始进行增量发布'); } // Create assets array only when needed for final result to reduce memory duplication if (releaseBodyRes.releaseBody && !result.assets) { result.assets = Array.from(result.assetsMap.values()); } return releaseBodyRes; } function getReleaseFormData(body) { const formData = new FormData(); if (!body.isPreviewFe && body.files) { body.files = body.files.map((item) => new utils_3.File([item.content], item.name, { type: (0, utils_2.getContentType)(item.name) })); } Object.keys(body).forEach((item) => { const data = body[item]; if (item === 'files') { data.forEach((it) => formData.append(item, it)); } else if (typeof data === 'object') { formData.append(item, JSON.stringify(data)); } else { formData.append(item, data); } }); return formData; } exports.getReleaseFormData = getReleaseFormData; //# sourceMappingURL=data.js.map