keycloak_theme/src/vite-plugin/vite-plugin.ts

218 lines
6.8 KiB
TypeScript
Raw Normal View History

import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
2024-01-30 00:06:17 +01:00
import type { Plugin } from "vite";
2024-05-20 15:48:51 +02:00
import {
2024-09-08 00:06:47 +02:00
WELL_KNOWN_DIRECTORY_BASE_NAME,
2024-07-13 19:33:59 +02:00
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES
2024-05-20 15:48:51 +02:00
} from "../bin/shared/constants";
2024-01-30 05:54:36 +01:00
import { id } from "tsafe/id";
import { rm } from "../bin/tools/fs.rm";
import { copyKeycloakResourcesToPublic } from "../bin/shared/copyKeycloakResourcesToPublic";
import { assert } from "tsafe/assert";
2024-05-20 15:48:51 +02:00
import {
2024-06-09 09:15:16 +02:00
getBuildContext,
type BuildContext,
2024-05-20 15:48:51 +02:00
type BuildOptions,
type ResolvedViteConfig
2024-06-09 09:15:16 +02:00
} from "../bin/shared/buildContext";
2024-02-24 05:08:39 +01:00
import MagicString from "magic-string";
import { generateKcGenTs } from "../bin/shared/generateKcGenTs";
export namespace keycloakify {
export type Params = BuildOptions & {
postBuild?: (buildContext: Omit<BuildContext, "bundler">) => Promise<void>;
};
}
export function keycloakify(params: keycloakify.Params) {
const { postBuild, ...buildOptions } = params;
2024-01-27 18:49:29 +01:00
let projectDirPath: string | undefined = undefined;
2024-01-30 05:54:36 +01:00
let urlPathname: string | undefined = undefined;
let buildDirPath: string | undefined = undefined;
let command: "build" | "serve" | undefined = undefined;
2024-02-24 05:08:39 +01:00
let shouldGenerateSourcemap: boolean | undefined = undefined;
2024-01-27 18:49:29 +01:00
const plugin = {
2024-06-09 14:34:41 +02:00
name: "keycloakify",
2024-05-20 15:48:51 +02:00
configResolved: async resolvedConfig => {
2024-02-24 05:08:39 +01:00
shouldGenerateSourcemap = resolvedConfig.build.sourcemap !== false;
run_post_build_script_case: {
2024-05-20 15:48:51 +02:00
const envValue =
2024-07-13 19:33:59 +02:00
process.env[VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RUN_POST_BUILD_SCRIPT];
if (envValue === undefined) {
break run_post_build_script_case;
}
const { buildContext, resourcesDirPath } = JSON.parse(envValue) as {
buildContext: BuildContext;
resourcesDirPath: string;
};
process.chdir(resourcesDirPath);
2024-06-10 09:12:24 +02:00
2024-06-10 09:26:47 +02:00
await postBuild?.(buildContext);
process.exit(0);
}
command = resolvedConfig.command;
projectDirPath = resolvedConfig.root;
2024-01-30 05:54:36 +01:00
urlPathname = (() => {
let out = resolvedConfig.env.BASE_URL;
2024-01-30 00:06:17 +01:00
2024-05-20 15:48:51 +02:00
if (
out.startsWith(".") &&
command === "build" &&
resolvedConfig.envPrefix?.includes("STORYBOOK_") !== true
) {
throw new Error(
[
2024-05-16 08:22:56 +02:00
`BASE_URL=${out} is not supported By Keycloakify. Use an absolute path instead.`,
`If this is a problem, please open an issue at https://github.com/keycloakify/keycloakify/issues/new`
].join("\n")
);
}
2024-01-30 05:54:36 +01:00
if (out === undefined) {
return undefined;
}
2024-01-30 00:06:17 +01:00
2024-01-30 05:54:36 +01:00
if (!out.startsWith("/")) {
out = "/" + out;
}
2024-01-30 00:06:17 +01:00
2024-01-30 05:54:36 +01:00
if (!out.endsWith("/")) {
out += "/";
2024-01-30 00:06:17 +01:00
}
2024-01-27 18:49:29 +01:00
2024-01-30 05:54:36 +01:00
return out;
2024-01-30 00:06:17 +01:00
})();
2024-01-27 18:49:29 +01:00
buildDirPath = pathJoin(projectDirPath, resolvedConfig.build.outDir);
resolve_vite_config_case: {
2024-05-20 15:48:51 +02:00
const envValue =
2024-07-13 19:33:59 +02:00
process.env[VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RESOLVE_VITE_CONFIG];
2024-01-30 05:54:36 +01:00
if (envValue === undefined) {
break resolve_vite_config_case;
}
2024-01-30 00:06:17 +01:00
2024-07-13 19:33:59 +02:00
console.log(VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.RESOLVE_VITE_CONFIG);
console.log(
JSON.stringify(
id<ResolvedViteConfig>({
2024-05-20 15:48:51 +02:00
publicDir: pathRelative(
projectDirPath,
2024-05-20 15:48:51 +02:00
resolvedConfig.publicDir
),
assetsDir: resolvedConfig.build.assetsDir,
buildDir: resolvedConfig.build.outDir,
urlPathname,
2024-06-09 09:15:16 +02:00
buildOptions
})
)
);
process.exit(0);
}
2024-06-09 09:15:16 +02:00
const buildContext = getBuildContext({
cliCommandOptions: {
projectDirPath
}
});
2024-09-08 00:06:47 +02:00
copyKeycloakResourcesToPublic({ buildContext }),
await generateKcGenTs({ buildContext });
2024-01-27 18:49:29 +01:00
},
2024-05-20 15:48:51 +02:00
transform: (code, id) => {
assert(command !== undefined);
2024-02-24 05:08:39 +01:00
assert(shouldGenerateSourcemap !== undefined);
if (command !== "build") {
return;
}
assert(projectDirPath !== undefined);
2024-01-27 18:49:29 +01:00
2024-02-24 05:08:39 +01:00
{
2024-05-20 15:48:51 +02:00
const isWithinSourceDirectory = id.startsWith(
pathJoin(projectDirPath, "src") + pathSep
2024-05-20 15:48:51 +02:00
);
2024-01-30 00:06:17 +01:00
2024-02-24 05:08:39 +01:00
if (!isWithinSourceDirectory) {
return;
2024-01-30 00:06:17 +01:00
}
2024-02-24 05:08:39 +01:00
}
2024-01-30 00:06:17 +01:00
2024-02-24 05:08:39 +01:00
{
const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
const isTypeScriptFile = id.endsWith(".ts") || id.endsWith(".tsx");
2024-01-27 18:49:29 +01:00
2024-02-24 05:08:39 +01:00
if (!isTypeScriptFile && !isJavascriptFile) {
return;
2024-01-30 00:06:17 +01:00
}
2024-02-24 05:08:39 +01:00
}
2024-01-30 00:06:17 +01:00
2024-02-24 05:08:39 +01:00
const transformedCode = new MagicString(code);
transformedCode.replaceAll(
/import\.meta\.env(?:(?:\.BASE_URL)|(?:\["BASE_URL"\]))/g,
[
`(`,
`(window.kcContext === undefined || import.meta.env.MODE === "development")?`,
2024-02-24 05:08:39 +01:00
`"${urlPathname ?? "/"}":`,
2024-09-08 00:06:47 +02:00
`(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/")`,
2024-02-24 05:08:39 +01:00
`)`
].join("")
);
2024-01-30 00:06:17 +01:00
2024-02-24 05:08:39 +01:00
if (!transformedCode.hasChanged()) {
return;
2024-01-30 00:06:17 +01:00
}
2024-02-24 05:08:39 +01:00
if (!shouldGenerateSourcemap) {
return transformedCode.toString();
2024-01-30 00:06:17 +01:00
}
2024-01-30 05:54:36 +01:00
2024-02-24 05:08:39 +01:00
const map = transformedCode.generateMap({
2024-05-20 15:48:51 +02:00
source: id,
includeContent: true,
hires: true
2024-02-24 05:08:39 +01:00
});
2024-01-30 05:54:36 +01:00
return {
2024-05-20 15:48:51 +02:00
code: transformedCode.toString(),
map: map.toString()
2024-01-30 05:54:36 +01:00
};
},
2024-05-20 15:48:51 +02:00
closeBundle: async () => {
assert(command !== undefined);
if (command !== "build") {
return;
}
assert(buildDirPath !== undefined);
2024-09-08 00:06:47 +02:00
await rm(
pathJoin(
buildDirPath,
WELL_KNOWN_DIRECTORY_BASE_NAME.KEYCLOAKIFY_DEV_RESOURCES
),
2024-09-08 00:06:47 +02:00
{
recursive: true,
force: true
}
);
2024-01-30 00:06:17 +01:00
}
} satisfies Plugin;
return plugin as any;
2024-01-27 18:49:29 +01:00
}