支持了打包web项目

This commit is contained in:
qcqcqc@wsl 2025-10-29 12:11:06 +08:00
parent 36f2ae82c2
commit 0b521a16c6
2 changed files with 159 additions and 15 deletions

86
dist/cli.js vendored
View File

@ -35,11 +35,21 @@ function parseCliArgs() {
},
port: {
type: "string",
default: "3001"
default: ["3001", "8080"],
multiple: true
},
"node-version": {
type: "string",
default: "20"
},
// 打包web还是后端
"build-type": {
type: "string",
default: "backend"
},
"web-source": {
type: "string",
default: "web"
}
},
allowPositionals: true
@ -57,6 +67,7 @@ function parseCliArgs() {
--registry=<url> npm \u955C\u50CF\u7AD9\u5730\u5740\uFF0C\u9ED8\u8BA4: https://registry.npmmirror.com
--port=<port> \u66B4\u9732\u7684\u7AEF\u53E3\u53F7\uFF0C\u9ED8\u8BA4: 3001
--node-version=<ver> Node.js \u7248\u672C\uFF0C\u9ED8\u8BA4: 20
--build-type=<type> \u6784\u5EFA\u7C7B\u578B (native|wechatMp|web|backend)\uFF0C\u9ED8\u8BA4: backend
-h, --help \u663E\u793A\u6B64\u5E2E\u52A9\u4FE1\u606F
\u793A\u4F8B:
@ -78,6 +89,11 @@ function parseCliArgs() {
console.error(" \u652F\u6301\u7684\u73AF\u5883: dev, prod, staging");
process.exit(1);
}
if (!["native", "wechatMp", "web", "backend"].includes(values["build-type"])) {
console.error(`\u274C \u65E0\u6548\u7684\u6784\u5EFA\u7C7B\u578B: ${values["build-type"]}`);
console.error(" \u652F\u6301\u7684\u7C7B\u578B: native, wechatMp, web, backend");
process.exit(1);
}
return {
projectDir,
options: {
@ -85,7 +101,9 @@ function parseCliArgs() {
extra: values.extra,
registry: values.registry,
port: values.port,
nodeVersion: values["node-version"]
nodeVersion: values["node-version"],
buildType: values["build-type"],
webSource: values["web-source"]
}
};
}
@ -195,7 +213,7 @@ RUN rm -rf src \\
# \u5207\u6362\u56DE\u4E3B\u9879\u76EE\u76EE\u5F55
WORKDIR /app/${projectName}
EXPOSE ${port}
EXPOSE ${port.join(" ")}
CMD ["pm2-runtime", "start", "pm2.${env}.json"]
`;
@ -262,6 +280,7 @@ function main() {
console.log(`-> \u914D\u7F6E\u4FE1\u606F:`);
console.log(` \u9879\u76EE\u76EE\u5F55: ${projectDir}`);
console.log(` \u73AF\u5883: ${options.env}`);
console.log(` \u6784\u5EFA\u7C7B\u578B: ${options.buildType}`);
console.log(
` \u989D\u5916\u4F9D\u8D56: ${options.extra.length > 0 ? options.extra.join(", ") : "\u65E0"}`
);
@ -272,6 +291,19 @@ function main() {
console.error(`\u274C \u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${projectDir}`);
process.exit(1);
}
switch (options.buildType) {
case "backend":
packageBackend(projectDir, options);
break;
case "web":
packageWeb(projectDir, options);
break;
default:
console.error(`\u274C \u4E0D\u652F\u6301\u7684\u6784\u5EFA\u7C7B\u578B: ${options.buildType}`);
process.exit(1);
}
}
function packageBackend(projectDir, options) {
let skipConfigReplace = false;
const configDir = path.join(projectDir, "configurations");
if (!fs.existsSync(configDir)) {
@ -284,8 +316,8 @@ function main() {
const projectName = path.basename(projectDir);
const dockerfileContent = generateDockerfile(projectName, options);
const dockerignoreContent = generateDockerignore();
fs.writeFileSync(path.join(pwd2, "Dockerfile"), dockerfileContent);
fs.writeFileSync(path.join(pwd2, ".dockerignore"), dockerignoreContent);
fs.writeFileSync(path.join(pwd, "Dockerfile"), dockerfileContent);
fs.writeFileSync(path.join(pwd, ".dockerignore"), dockerignoreContent);
console.log("\n\u{1F4DD} \u5DF2\u751F\u6210 Dockerfile \u548C .dockerignore");
try {
if (!skipConfigReplace) {
@ -299,23 +331,55 @@ function main() {
configPath,
path.join(projectDir, "configuration/mysql.json")
);
buildDockerImage(imageBase, name, pwd2);
saveDockerImage(imageBase, name, pwd2);
buildDockerImage(imageBase, name, pwd);
saveDockerImage(imageBase, name, pwd);
}
} else {
const name = `default-${options.env}`;
console.log(`
\u{1F527} \u6784\u5EFA\u9ED8\u8BA4\u955C\u50CF ${name}...`);
buildDockerImage(imageBase, name, pwd2);
saveDockerImage(imageBase, name, pwd2);
buildDockerImage(imageBase, name, pwd);
saveDockerImage(imageBase, name, pwd);
}
console.log("\n\u2705 \u6240\u6709\u955C\u50CF\u6784\u5EFA\u6210\u529F\uFF01");
} finally {
fs.rmSync(path.join(projectDir, "configuration/mysql.json"), {
force: true
});
fs.rmSync(path.join(pwd2, "Dockerfile"), { force: true });
fs.rmSync(path.join(pwd2, ".dockerignore"), { force: true });
fs.rmSync(path.join(pwd, "Dockerfile"), { force: true });
fs.rmSync(path.join(pwd, ".dockerignore"), { force: true });
}
}
function packageWeb(projectDir, options) {
console.log(`
\u{1F527} \u6253\u5305 Web \u9879\u76EE...`);
const distDir = path.join(pwd, "dist");
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir);
}
execSync(`npm install`, {
stdio: "inherit",
cwd: projectDir
});
execSync(`npm run build:${options.webSource}${options.env === "staging" ? ":staging" : ""}`, {
stdio: "inherit",
cwd: projectDir
});
const webDistDir = path.join(projectDir, options.webSource, "build");
if (!fs.existsSync(webDistDir)) {
console.error(`\u274C \u6784\u5EFA\u5931\u8D25\uFF0C\u627E\u4E0D\u5230 Web \u6784\u5EFA\u4EA7\u7269\u76EE\u5F55: ${webDistDir}`);
process.exit(1);
}
const projectName = path.basename(projectDir);
const outputWebDir = path.join(distDir, "html", projectName, options.webSource);
if (!fs.existsSync(path.join(distDir, "html", projectName))) {
fs.mkdirSync(path.join(distDir, "html", projectName));
}
fs.rmSync(outputWebDir, { recursive: true, force: true });
fs.mkdirSync(outputWebDir);
execSync(`cp -r ${webDistDir}/* ${outputWebDir}/`, {
stdio: "inherit"
});
console.log(`\u2705 Web \u9879\u76EE\u6253\u5305\u6210\u529F\uFF0C\u4EA7\u7269\u4F4D\u4E8E: ${outputWebDir}`);
}
main();

View File

@ -9,8 +9,10 @@ interface BuildOptions {
env: string;
extra: string[];
registry: string;
port: string;
port: string[];
nodeVersion: string;
buildType: string;
webSource: string;
}
interface ParsedArgs {
@ -52,12 +54,22 @@ function parseCliArgs(): ParsedArgs | null {
},
port: {
type: "string",
default: "3001",
default: ["3001", "8080"],
multiple: true,
},
"node-version": {
type: "string",
default: "20",
},
// 打包web还是后端
"build-type": {
type: "string",
default: "backend",
},
"web-source": {
type: "string",
default: "web",
}
},
allowPositionals: true,
});
@ -76,6 +88,7 @@ function parseCliArgs(): ParsedArgs | null {
--registry=<url> npm 默认: https://registry.npmmirror.com
--port=<port> 默认: 3001
--node-version=<ver> Node.js 默认: 20
--build-type=<type> (native|wechatMp|web|backend)默认: backend
-h, --help
:
@ -103,14 +116,22 @@ function parseCliArgs(): ParsedArgs | null {
process.exit(1);
}
if (!["native", "wechatMp", "web", "backend"].includes(values["build-type"] as string)) {
console.error(`❌ 无效的构建类型: ${values["build-type"]}`);
console.error(" 支持的类型: native, wechatMp, web, backend");
process.exit(1);
}
return {
projectDir,
options: {
env,
extra: values.extra as string[],
registry: values.registry as string,
port: values.port as string,
port: values.port as string[],
nodeVersion: values["node-version"] as string,
buildType: values["build-type"] as string,
webSource: values["web-source"] as string,
},
};
}
@ -241,7 +262,7 @@ RUN rm -rf src \\
#
WORKDIR /app/${projectName}
EXPOSE ${port}
EXPOSE ${port.join(" ")}
CMD ["pm2-runtime", "start", "pm2.${env}.json"]
`;
@ -334,6 +355,7 @@ function main(): void {
console.log(`-> 配置信息:`);
console.log(` 项目目录: ${projectDir}`);
console.log(` 环境: ${options.env}`);
console.log(` 构建类型: ${options.buildType}`);
console.log(
` 额外依赖: ${options.extra.length > 0 ? options.extra.join(", ") : "无"}`
);
@ -346,6 +368,21 @@ function main(): void {
process.exit(1);
}
switch (options.buildType) {
case "backend":
packageBackend(projectDir, options);
break;
case "web":
packageWeb(projectDir, options);
break;
default:
console.error(`❌ 不支持的构建类型: ${options.buildType}`);
process.exit(1);
}
}
function packageBackend(projectDir: string, options: BuildOptions): void {
let skipConfigReplace = false;
const configDir = path.join(projectDir, "configurations");
if (!fs.existsSync(configDir)) {
@ -408,5 +445,48 @@ function main(): void {
}
}
function packageWeb(projectDir: string, options: BuildOptions): void {
// Web 项目的打包逻辑:
// 1. 进入项目目录,执行 npm install 和 npm run build:web
// 2. 将web/build目录下的内容压缩后复制到pwd/dist目录下
console.log(`\n🔧 打包 Web 项目...`);
const distDir = path.join(pwd, "dist");
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir);
}
// 进入项目目录执行构建命令
execSync(`npm install`, {
stdio: "inherit",
cwd: projectDir,
});
execSync(`npm run build:${options.webSource}${options.env === 'staging' ? ':staging' : ''}`, {
stdio: "inherit",
cwd: projectDir,
});
const webDistDir = path.join(projectDir, options.webSource, "build");
if (!fs.existsSync(webDistDir)) {
console.error(`❌ 构建失败,找不到 Web 构建产物目录: ${webDistDir}`);
process.exit(1);
}
const projectName = path.basename(projectDir);
// 复制构建产物到 dist 目录
const outputWebDir = path.join(distDir, "html", projectName, options.webSource);
if (!fs.existsSync(path.join(distDir, "html", projectName))) {
fs.mkdirSync(path.join(distDir, "html", projectName));
}
fs.rmSync(outputWebDir, { recursive: true, force: true });
fs.mkdirSync(outputWebDir);
execSync(`cp -r ${webDistDir}/* ${outputWebDir}/`, {
stdio: "inherit",
});
console.log(`✅ Web 项目打包成功,产物位于: ${outputWebDir}`);
}
// 执行主函数
main();