228 lines
7.8 KiB
TypeScript
228 lines
7.8 KiB
TypeScript
import {
|
||
BuildHook,
|
||
IBuildResult,
|
||
IBuildTaskOption,
|
||
} from "@cocos/creator-types/editor/packages/builder/@types/public";
|
||
import path from "path";
|
||
import { existsSync, readFile, writeFile } from "fs";
|
||
import { ensureDirSync } from "fs-extra";
|
||
import { generator, GenPackageConfig } from "./version_generator";
|
||
import { createMinIOUploader, MinIOConfig } from "./minio-uploader";
|
||
|
||
const injectScript = `(function () {
|
||
const native = globalThis?.jsb || window.jsb || native;
|
||
if (typeof native === 'object') {
|
||
var hotUpdateSearchPaths = localStorage.getItem('HotUpdateSearchPaths');
|
||
if (hotUpdateSearchPaths) {
|
||
var paths = JSON.parse(hotUpdateSearchPaths);
|
||
native.fileUtils.setSearchPaths(paths);
|
||
|
||
var fileList = [];
|
||
var storagePath = paths[0] || '';
|
||
var tempPath = storagePath + '_temp/';
|
||
var baseOffset = tempPath.length;
|
||
if (native.fileUtils.isDirectoryExist(tempPath) && !native.fileUtils.isFileExist(tempPath + 'project.manifest.temp')) {
|
||
native.fileUtils.listFilesRecursively(tempPath, fileList);
|
||
fileList.forEach(srcPath => {
|
||
var relativePath = srcPath.substr(baseOffset);
|
||
var dstPath = storagePath + relativePath;
|
||
if (srcPath[srcPath.length - 1] === '/') {
|
||
native.fileUtils.createDirectory(dstPath)
|
||
}
|
||
else {
|
||
if (native.fileUtils.isFileExist(dstPath)) {
|
||
native.fileUtils.removeFile(dstPath)
|
||
}
|
||
native.fileUtils.renameFile(srcPath, dstPath);
|
||
}
|
||
})
|
||
native.fileUtils.removeDirectory(tempPath);
|
||
}
|
||
}
|
||
}
|
||
})();`;
|
||
|
||
export const onBeforeBuild: BuildHook.onBeforeBuild = async function (
|
||
options: IBuildTaskOption,
|
||
result: IBuildResult
|
||
) {};
|
||
|
||
export const onAfterBuild: BuildHook.onAfterBuild = async function (
|
||
options: IBuildTaskOption,
|
||
result: IBuildResult
|
||
) {
|
||
console.log("onAfterBuild platform", options.platform);
|
||
|
||
if (!["android", "mac", "ios", "windows"].includes(options.platform)) {
|
||
return;
|
||
}
|
||
|
||
let url = path.join(result.dest, "data", "main.js");
|
||
console.log("onAfterBuild url", url);
|
||
if (!existsSync(url)) {
|
||
url = path.join(result.dest, "assets", "main.js");
|
||
}
|
||
console.log("onAfterBuild url", url);
|
||
|
||
const hotupdateConfig: {
|
||
hotupdatePluginCheck: boolean;
|
||
configInput: string;
|
||
outInput: string;
|
||
// MinIO 配置
|
||
minioAutoUpload: boolean;
|
||
minioEndpoint: string;
|
||
minioAccessKeyId: string;
|
||
minioSecretAccessKey: string;
|
||
minioBucketName: string;
|
||
minioUseSSL: boolean;
|
||
minioPathPrefix: string;
|
||
} = options.packages?.["max-framework"];
|
||
console.log(
|
||
"onAfterBuild hotupdateConfig",
|
||
url,
|
||
hotupdateConfig.hotupdatePluginCheck,
|
||
hotupdateConfig.configInput,
|
||
hotupdateConfig.outInput,
|
||
JSON.stringify(hotupdateConfig)
|
||
);
|
||
if (!!hotupdateConfig.hotupdatePluginCheck) {
|
||
// 验证配置参数
|
||
if (!hotupdateConfig.configInput || !hotupdateConfig.outInput) {
|
||
console.error("热更新配置不完整:configInput 和 outInput 不能为空");
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// configInput 是带 project:// 前缀的,需要转换为实际文件路径
|
||
let configPath = hotupdateConfig.configInput;
|
||
if (configPath.startsWith("project://")) {
|
||
configPath = path.resolve(
|
||
Editor.Project.path,
|
||
configPath.replace("project://", "")
|
||
);
|
||
} else if (!path.isAbsolute(configPath)) {
|
||
configPath = path.resolve(Editor.Project.path, configPath);
|
||
}
|
||
let outInput = hotupdateConfig.outInput;
|
||
if (outInput.startsWith("project://")) {
|
||
outInput = path.resolve(
|
||
Editor.Project.path,
|
||
outInput.replace("project://", "")
|
||
);
|
||
} else if (!path.isAbsolute(outInput)) {
|
||
outInput = path.resolve(Editor.Project.path, outInput);
|
||
}
|
||
console.log("onAfterBuild configPath", configPath, outInput);
|
||
const obj = require(configPath) as GenPackageConfig[];
|
||
for (const item of obj) {
|
||
// 验证包名不能为空
|
||
if (!item.pkgName || item.pkgName.trim() === "") {
|
||
console.error("热更新包名不能为空:", item);
|
||
continue;
|
||
}
|
||
const source = path.join(result.dest, "data");
|
||
console.log("开始生成Package: ", item.pkgName, source);
|
||
ensureDirSync(
|
||
path.join(outInput, item.pkgName)
|
||
);
|
||
generator(source, outInput, item);
|
||
}
|
||
|
||
// MinIO上传功能
|
||
if (hotupdateConfig.minioAutoUpload) {
|
||
console.log("开始MinIO自动上传流程...");
|
||
await uploadToMinIO(hotupdateConfig, outInput, obj);
|
||
}
|
||
} catch (error) {
|
||
console.error("热更新配置文件加载失败:", error);
|
||
return;
|
||
}
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
readFile(url, "utf8", (err, data) => {
|
||
if (err) {
|
||
reject(err);
|
||
return;
|
||
}
|
||
const newStr = injectScript + data;
|
||
writeFile(url, newStr, (err) => {
|
||
if (err) {
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
resolve();
|
||
});
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 上传到MinIO
|
||
* @param config 热更新配置
|
||
* @param outputPath 输出路径
|
||
* @param packages 包配置列表
|
||
*/
|
||
async function uploadToMinIO(
|
||
config: {
|
||
minioEndpoint: string;
|
||
minioAccessKeyId: string;
|
||
minioSecretAccessKey: string;
|
||
minioBucketName: string;
|
||
minioUseSSL: boolean;
|
||
minioPathPrefix: string;
|
||
},
|
||
outputPath: string,
|
||
packages: GenPackageConfig[]
|
||
) {
|
||
try {
|
||
// 验证MinIO配置
|
||
if (!config.minioEndpoint || !config.minioAccessKeyId ||
|
||
!config.minioSecretAccessKey || !config.minioBucketName) {
|
||
console.error("MinIO配置不完整,跳过上传");
|
||
return;
|
||
}
|
||
|
||
// 创建MinIO上传器
|
||
const minioConfig: MinIOConfig = {
|
||
endpoint: config.minioEndpoint,
|
||
accessKeyId: config.minioAccessKeyId,
|
||
secretAccessKey: config.minioSecretAccessKey,
|
||
bucketName: config.minioBucketName,
|
||
useSSL: config.minioUseSSL,
|
||
pathPrefix: config.minioPathPrefix
|
||
};
|
||
|
||
const uploader = createMinIOUploader(minioConfig);
|
||
|
||
// 上传每个包
|
||
for (const pkg of packages) {
|
||
if (!pkg.pkgName || pkg.pkgName.trim() === "") {
|
||
continue;
|
||
}
|
||
|
||
const packageDir = path.join(outputPath, pkg.pkgName);
|
||
if (!existsSync(packageDir)) {
|
||
console.error(`包目录不存在: ${packageDir}`);
|
||
continue;
|
||
}
|
||
|
||
console.log(`开始上传包到MinIO: ${pkg.pkgName}`);
|
||
|
||
const result = await uploader.uploadDirectory(packageDir, pkg.pkgName);
|
||
|
||
if (result.success) {
|
||
console.log(`包 ${pkg.pkgName} 上传成功,共 ${result.uploadedFiles.length} 个文件`);
|
||
console.log(`上传的文件: ${result.uploadedFiles.join(', ')}`);
|
||
} else {
|
||
console.error(`包 ${pkg.pkgName} 上传失败: ${result.error}`);
|
||
}
|
||
}
|
||
|
||
console.log("所有包MinIO上传完成");
|
||
} catch (error) {
|
||
console.error("MinIO上传过程中发生错误:", error);
|
||
}
|
||
}
|