Build the app when running npx keycloak start-keycloak
This commit is contained in:
128
src/bin/start-keycloak/appBuild.ts
Normal file
128
src/bin/start-keycloak/appBuild.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import * as child_process from "child_process";
|
||||
import { Deferred } from "evt/tools/Deferred";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { is } from "tsafe/is";
|
||||
import type { BuildOptions } from "../shared/buildOptions";
|
||||
import * as fs from "fs";
|
||||
import { join as pathJoin } from "path";
|
||||
|
||||
export type BuildOptionsLike = {
|
||||
reactAppRootDirPath: string;
|
||||
keycloakifyBuildDirPath: string;
|
||||
bundler: "vite" | "webpack";
|
||||
npmWorkspaceRootDirPath: string;
|
||||
reactAppBuildDirPath: string;
|
||||
};
|
||||
|
||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
export async function appBuild(params: {
|
||||
doSkipIfReactAppBuildDirExists: boolean;
|
||||
buildOptions: BuildOptionsLike;
|
||||
}): Promise<{ isAppBuildSuccess: boolean }> {
|
||||
const { doSkipIfReactAppBuildDirExists, buildOptions } = params;
|
||||
|
||||
if (
|
||||
doSkipIfReactAppBuildDirExists &&
|
||||
fs.existsSync(buildOptions.reactAppBuildDirPath)
|
||||
) {
|
||||
return { isAppBuildSuccess: true };
|
||||
}
|
||||
|
||||
const { bundler } = buildOptions;
|
||||
|
||||
const { command, args, cwd } = (() => {
|
||||
switch (bundler) {
|
||||
case "vite":
|
||||
return {
|
||||
command: "npx",
|
||||
args: ["vite", "build"],
|
||||
cwd: buildOptions.reactAppRootDirPath
|
||||
};
|
||||
case "webpack": {
|
||||
for (const dirPath of [
|
||||
buildOptions.reactAppRootDirPath,
|
||||
buildOptions.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;
|
||||
}
|
||||
}
|
||||
) ?? [];
|
||||
|
||||
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 });
|
||||
|
||||
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 };
|
||||
}
|
51
src/bin/start-keycloak/keycloakifyBuild.ts
Normal file
51
src/bin/start-keycloak/keycloakifyBuild.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { skipBuildJarsEnvName } from "../shared/constants";
|
||||
import * as child_process from "child_process";
|
||||
import chalk from "chalk";
|
||||
import { Deferred } from "evt/tools/Deferred";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { BuildOptions } from "../shared/buildOptions";
|
||||
|
||||
export type BuildOptionsLike = {
|
||||
reactAppRootDirPath: string;
|
||||
keycloakifyBuildDirPath: string;
|
||||
bundler: "vite" | "webpack";
|
||||
npmWorkspaceRootDirPath: string;
|
||||
};
|
||||
|
||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||
|
||||
export async function keycloakifyBuild(params: {
|
||||
doSkipBuildJars: boolean;
|
||||
buildOptions: BuildOptionsLike;
|
||||
}): Promise<{ isKeycloakifyBuildSuccess: boolean }> {
|
||||
const { buildOptions, doSkipBuildJars } = params;
|
||||
|
||||
const dResult = new Deferred<{ isSuccess: boolean }>();
|
||||
|
||||
const child = child_process.spawn("npx", ["keycloakify", "build"], {
|
||||
cwd: buildOptions.reactAppRootDirPath,
|
||||
env: {
|
||||
...process.env,
|
||||
...(doSkipBuildJars ? {} : { [skipBuildJarsEnvName]: "true" })
|
||||
}
|
||||
});
|
||||
|
||||
child.stdout.on("data", data => process.stdout.write(data));
|
||||
|
||||
child.stderr.on("data", data => process.stderr.write(data));
|
||||
|
||||
child.on("exit", code => {
|
||||
if (code !== 0) {
|
||||
console.log(chalk.yellow("Theme not updated, build failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(chalk.green("Rebuild done"));
|
||||
});
|
||||
|
||||
child.on("exit", code => dResult.resolve({ isSuccess: code === 0 }));
|
||||
|
||||
const { isSuccess } = await dResult.pr;
|
||||
|
||||
return { isKeycloakifyBuildSuccess: isSuccess };
|
||||
}
|
Reference in New Issue
Block a user