130 lines
4.5 KiB
TypeScript
Raw Normal View History

import * as child_process from "child_process";
import { Deferred } from "evt/tools/Deferred";
import { assert } from "tsafe/assert";
import { is } from "tsafe/is";
2024-06-09 09:15:16 +02:00
import type { BuildContext } from "../shared/buildContext";
import * as fs from "fs";
import { join as pathJoin } from "path";
2024-06-09 09:15:16 +02:00
export type BuildContextLike = {
projectDirPath: string;
keycloakifyBuildDirPath: string;
bundler: "vite" | "webpack";
npmWorkspaceRootDirPath: string;
projectBuildDirPath: string;
};
2024-06-09 09:15:16 +02:00
assert<BuildContext extends BuildContextLike ? true : false>();
export async function appBuild(params: {
2024-06-09 09:15:16 +02:00
buildContext: BuildContextLike;
}): Promise<{ isAppBuildSuccess: boolean }> {
2024-06-09 09:15:16 +02:00
const { buildContext } = params;
2024-06-09 09:15:16 +02:00
const { bundler } = buildContext;
const { command, args, cwd } = (() => {
switch (bundler) {
case "vite":
return {
command: "npx",
args: ["vite", "build"],
2024-06-09 09:15:16 +02:00
cwd: buildContext.projectDirPath
};
case "webpack": {
for (const dirPath of [
2024-06-09 09:15:16 +02:00
buildContext.projectDirPath,
buildContext.npmWorkspaceRootDirPath
]) {
try {
const parsedPackageJson = JSON.parse(
fs
.readFileSync(pathJoin(dirPath, "package.json"))
.toString("utf8")
);
const [scriptName] =
Object.entries(parsedPackageJson.scripts).find(
([, scriptValue]) => {
assert(is<string>(scriptValue));
if (
scriptValue.includes("webpack") &&
scriptValue.includes("--mode production")
) {
return true;
}
if (
scriptValue.includes("react-scripts") &&
scriptValue.includes("build")
) {
return true;
}
if (
scriptValue.includes("react-app-rewired") &&
scriptValue.includes("build")
) {
return true;
}
if (
scriptValue.includes("craco") &&
scriptValue.includes("build")
) {
return true;
}
2024-05-27 17:21:06 +02:00
if (
scriptValue.includes("ng") &&
scriptValue.includes("build")
) {
return true;
}
return false;
}
) ?? [];
if (scriptName === undefined) {
continue;
}
return {
command: "npm",
args: ["run", scriptName],
cwd: dirPath
};
} catch {
continue;
}
}
throw new Error(
"Keycloakify was unable to determine which script is responsible for building the app."
);
}
}
})();
const dResult = new Deferred<{ isSuccess: boolean }>();
const child = child_process.spawn(command, args, { cwd, shell: true });
child.stdout.on("data", data => {
if (data.toString("utf8").includes("gzip:")) {
return;
}
process.stdout.write(data);
});
child.stderr.on("data", data => process.stderr.write(data));
child.on("exit", code => dResult.resolve({ isSuccess: code === 0 }));
const { isSuccess } = await dResult.pr;
return { isAppBuildSuccess: isSuccess };
}