@lcap/nasl
Version:
NetEase Application Specific Language
252 lines • 11.9 kB
JavaScript
;
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