Compare commits

..

19 Commits

Author SHA1 Message Date
34f64184d9 Bump version 2024-02-13 01:33:31 +01:00
b9abd74156 Create a .gitignore that matches all in the build_keycloak directory 2024-02-13 01:33:15 +01:00
a1c0bfda6c Bump version 2024-02-13 01:13:26 +01:00
617dcef09d Merge pull request #499 from keycloakify/vite
Vite
2024-02-13 01:04:54 +01:00
d9c406800a Fix tests 2024-02-12 23:57:21 +01:00
54b869def1 Release candidate 2024-02-12 23:43:21 +01:00
d80a583979 Better test for isStorybook 2024-02-12 23:42:31 +01:00
99bfd7379b Release candidate 2024-02-12 13:43:34 +01:00
5f257382fa Prevent accumulation of assets in build dir 2024-02-12 13:43:12 +01:00
e3e6847c82 Prevent users from having to use any 2024-02-12 13:27:07 +01:00
4ee0823acb Bump version 2024-02-12 01:47:21 +01:00
d466123b1c Use Keycloak 23.0.6 2024-02-12 01:41:08 +01:00
21cbc14a48 Release candidate 2024-02-12 01:34:54 +01:00
b2f2c3e386 Disalow releative basename in vite config 2024-02-12 01:34:34 +01:00
b03340ed10 Do not dynamically import "en" to make vite happy 2024-02-12 00:33:12 +01:00
5b563d8e9b Improve privacy on the buildinfo file that might be served 2024-02-12 00:32:18 +01:00
2790487fc7 Release candidate 2024-02-11 23:59:23 +01:00
ad5a368065 Run vite configResolved in dev mode as well 2024-02-11 23:59:10 +01:00
7c0a631a9a Fix crash in vite-plugin 2024-02-11 23:54:28 +01:00
10 changed files with 74 additions and 33 deletions

View File

@ -130,6 +130,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
# Changelog highlights # Changelog highlights
## 9.4
**Vite Support 🎉**
## 9.0 ## 9.0
Bring back support for account themes in Keycloak v23 and up! [See issue](https://github.com/keycloakify/keycloakify/issues/389). Bring back support for account themes in Keycloak v23 and up! [See issue](https://github.com/keycloakify/keycloakify/issues/389).

View File

@ -1,6 +1,6 @@
{ {
"name": "keycloakify", "name": "keycloakify",
"version": "9.4.0-rc.12", "version": "9.4.1",
"description": "Create Keycloak themes using React", "description": "Create Keycloak themes using React",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -81,8 +81,7 @@ async function main() {
const generatedFileHeader = [ const generatedFileHeader = [
`//This code was automatically generated by running ${pathRelative(thisCodebaseRootDirPath, __filename)}`, `//This code was automatically generated by running ${pathRelative(thisCodebaseRootDirPath, __filename)}`,
"//PLEASE DO NOT EDIT MANUALLY", "//PLEASE DO NOT EDIT MANUALLY"
""
].join("\n"); ].join("\n");
languages.forEach(language => { languages.forEach(language => {
@ -95,6 +94,7 @@ async function main() {
Buffer.from( Buffer.from(
[ [
generatedFileHeader, generatedFileHeader,
"",
"/* spell-checker: disable */", "/* spell-checker: disable */",
`const messages= ${JSON.stringify(recordForPageType[language], null, 2)};`, `const messages= ${JSON.stringify(recordForPageType[language], null, 2)};`,
"", "",
@ -113,10 +113,15 @@ async function main() {
Buffer.from( Buffer.from(
[ [
generatedFileHeader, generatedFileHeader,
`import * as en from "./en";`,
"",
"export async function getMessages(currentLanguageTag: string) {", "export async function getMessages(currentLanguageTag: string) {",
" const { default: messages } = await (() => {", " const { default: messages } = await (() => {",
" switch (currentLanguageTag) {", " switch (currentLanguageTag) {",
...languages.map(language => ` case "${language}": return import("./${language}");`), ` case "en": return en;`,
...languages
.filter(language => language !== "en")
.map(language => ` case "${language}": return import("./${language}");`),
' default: return { "default": {} };', ' default: return { "default": {} };',
" }", " }",
" })();", " })();",

View File

@ -1,10 +1,11 @@
import type { I18n } from "keycloakify/account/i18n"; import type { I18n } from "keycloakify/account/i18n";
import type { TemplateProps, ClassKey } from "keycloakify/account/TemplateProps"; import type { TemplateProps, ClassKey } from "keycloakify/account/TemplateProps";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import type { KcContext } from "keycloakify/account/kcContext";
export type PageProps<KcContext, I18nExtended extends I18n> = { export type PageProps<NarowedKcContext = KcContext, I18nExtended extends I18n = I18n> = {
Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>; Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>;
kcContext: KcContext; kcContext: NarowedKcContext;
i18n: I18nExtended; i18n: I18nExtended;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
import { downloadKeycloakStaticResources, type BuildOptionsLike } from "./keycloakify/generateTheme/downloadKeycloakStaticResources"; import { downloadKeycloakStaticResources, type BuildOptionsLike } from "./keycloakify/generateTheme/downloadKeycloakStaticResources";
import { join as pathJoin } from "path"; import { join as pathJoin, relative as pathRelative } from "path";
import { readBuildOptions } from "./keycloakify/buildOptions"; import { readBuildOptions } from "./keycloakify/buildOptions";
import { themeTypes, keycloak_resources, lastKeycloakVersionWithAccountV1 } from "./constants"; import { themeTypes, keycloak_resources, lastKeycloakVersionWithAccountV1 } from "./constants";
import { readThisNpmProjectVersion } from "./tools/readThisNpmProjectVersion"; import { readThisNpmProjectVersion } from "./tools/readThisNpmProjectVersion";
@ -19,6 +19,7 @@ export async function copyKeycloakResourcesToPublic(params: { processArgv: strin
const keycloakifyBuildinfoFilePath = pathJoin(destDirPath, "keycloakify.buildinfo"); const keycloakifyBuildinfoFilePath = pathJoin(destDirPath, "keycloakify.buildinfo");
const { keycloakifyBuildinfoRaw } = generateKeycloakifyBuildinfoRaw({ const { keycloakifyBuildinfoRaw } = generateKeycloakifyBuildinfoRaw({
destDirPath,
"keycloakifyVersion": readThisNpmProjectVersion(), "keycloakifyVersion": readThisNpmProjectVersion(),
buildOptions buildOptions
}); });
@ -72,12 +73,13 @@ export async function copyKeycloakResourcesToPublic(params: { processArgv: strin
} }
export function generateKeycloakifyBuildinfoRaw(params: { export function generateKeycloakifyBuildinfoRaw(params: {
destDirPath: string;
keycloakifyVersion: string; keycloakifyVersion: string;
buildOptions: BuildOptionsLike & { buildOptions: BuildOptionsLike & {
loginThemeResourcesFromKeycloakVersion: string; loginThemeResourcesFromKeycloakVersion: string;
}; };
}) { }) {
const { keycloakifyVersion, buildOptions } = params; const { destDirPath, keycloakifyVersion, buildOptions } = params;
const { cacheDirPath, npmWorkspaceRootDirPath, loginThemeResourcesFromKeycloakVersion, ...rest } = buildOptions; const { cacheDirPath, npmWorkspaceRootDirPath, loginThemeResourcesFromKeycloakVersion, ...rest } = buildOptions;
@ -88,8 +90,8 @@ export function generateKeycloakifyBuildinfoRaw(params: {
keycloakifyVersion, keycloakifyVersion,
"buildOptions": { "buildOptions": {
loginThemeResourcesFromKeycloakVersion, loginThemeResourcesFromKeycloakVersion,
cacheDirPath, "cacheDirPath": pathRelative(destDirPath, cacheDirPath),
npmWorkspaceRootDirPath "npmWorkspaceRootDirPath": pathRelative(destDirPath, npmWorkspaceRootDirPath)
} }
}, },
null, null,

View File

@ -20,6 +20,7 @@ import { readFieldNameUsage } from "./readFieldNameUsage";
import { readExtraPagesNames } from "./readExtraPageNames"; import { readExtraPagesNames } from "./readExtraPageNames";
import { generateMessageProperties } from "./generateMessageProperties"; import { generateMessageProperties } from "./generateMessageProperties";
import { bringInAccountV1 } from "./bringInAccountV1"; import { bringInAccountV1 } from "./bringInAccountV1";
import { rmSync } from "../../tools/fs.rmSync";
export type BuildOptionsLike = { export type BuildOptionsLike = {
bundler: "vite" | "webpack"; bundler: "vite" | "webpack";
@ -78,6 +79,11 @@ export async function generateTheme(params: {
const themeTypeDirPath = getThemeTypeDirPath({ themeType }); const themeTypeDirPath = getThemeTypeDirPath({ themeType });
apply_replacers_and_move_to_theme_resources: { apply_replacers_and_move_to_theme_resources: {
const destDirPath = pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir);
// NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
rmSync(destDirPath, { "recursive": true, "force": true });
if (themeType === "account" && implementedThemeTypes.login) { if (themeType === "account" && implementedThemeTypes.login) {
// NOTE: We prevend doing it twice, it has been done for the login theme. // NOTE: We prevend doing it twice, it has been done for the login theme.
@ -89,7 +95,7 @@ export async function generateTheme(params: {
"resources", "resources",
basenameOfTheKeycloakifyResourcesDir basenameOfTheKeycloakifyResourcesDir
), ),
"destDirPath": pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir) destDirPath
}); });
break apply_replacers_and_move_to_theme_resources; break apply_replacers_and_move_to_theme_resources;
@ -97,7 +103,7 @@ export async function generateTheme(params: {
transformCodebase({ transformCodebase({
"srcDirPath": buildOptions.reactAppBuildDirPath, "srcDirPath": buildOptions.reactAppBuildDirPath,
"destDirPath": pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir), destDirPath,
"transformSourceCode": ({ filePath, sourceCode }) => { "transformSourceCode": ({ filePath, sourceCode }) => {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/ //NOTE: Prevent cycles, excludes the folder we generated for debug in public/
// This should not happen if users follow the new instruction setup but we keep it for retrocompatibility. // This should not happen if users follow the new instruction setup but we keep it for retrocompatibility.

View File

@ -59,7 +59,7 @@ export async function main() {
); );
} }
const containerKeycloakVersion = "23.0.0"; const containerKeycloakVersion = "23.0.6";
generateStartKeycloakTestingContainer({ generateStartKeycloakTestingContainer({
"keycloakVersion": containerKeycloakVersion, "keycloakVersion": containerKeycloakVersion,
@ -67,6 +67,8 @@ export async function main() {
buildOptions buildOptions
}); });
fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8"));
logger.log( logger.log(
[ [
"", "",

View File

@ -1,3 +1 @@
import { BASE_URL } from "./BASE_URL"; export const isStorybook = typeof window === "object" && Object.keys(window).find(key => key.startsWith("__STORYBOOK")) !== undefined;
export const isStorybook = BASE_URL.startsWith(".");

View File

@ -1,10 +1,11 @@
import type { I18n } from "keycloakify/login/i18n"; import type { I18n } from "keycloakify/login/i18n";
import { type TemplateProps, type ClassKey } from "keycloakify/login/TemplateProps"; import { type TemplateProps, type ClassKey } from "keycloakify/login/TemplateProps";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import type { KcContext } from "keycloakify/account/kcContext";
export type PageProps<KcContext, I18nExtended extends I18n> = { export type PageProps<NarowedKcContext = KcContext, I18nExtended extends I18n = I18n> = {
Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>; Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>;
kcContext: KcContext; kcContext: NarowedKcContext;
i18n: I18nExtended; i18n: I18nExtended;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;

View File

@ -1,6 +1,5 @@
import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path"; import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
import type { Plugin } from "vite"; import type { Plugin } from "vite";
import { assert } from "tsafe/assert";
import * as fs from "fs"; import * as fs from "fs";
import { resolvedViteConfigJsonBasename, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir, keycloak_resources } from "../bin/constants"; import { resolvedViteConfigJsonBasename, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir, keycloak_resources } from "../bin/constants";
import type { ResolvedViteConfig } from "../bin/keycloakify/buildOptions/resolvedViteConfig"; import type { ResolvedViteConfig } from "../bin/keycloakify/buildOptions/resolvedViteConfig";
@ -9,20 +8,32 @@ import { replaceAll } from "../bin/tools/String.prototype.replaceAll";
import { id } from "tsafe/id"; import { id } from "tsafe/id";
import { rm } from "../bin/tools/fs.rm"; import { rm } from "../bin/tools/fs.rm";
import { copyKeycloakResourcesToPublic } from "../bin/copy-keycloak-resources-to-public"; import { copyKeycloakResourcesToPublic } from "../bin/copy-keycloak-resources-to-public";
import { assert } from "tsafe/assert";
export function keycloakify(): Plugin { export function keycloakify() {
let reactAppRootDirPath: string | undefined = undefined; let reactAppRootDirPath: string | undefined = undefined;
let urlPathname: string | undefined = undefined; let urlPathname: string | undefined = undefined;
let buildDirPath: string | undefined = undefined; let buildDirPath: string | undefined = undefined;
let command: "build" | "serve" | undefined = undefined;
return { const plugin = {
"name": "keycloakify", "name": "keycloakify" as const,
"apply": "build",
"configResolved": async resolvedConfig => { "configResolved": async resolvedConfig => {
command = resolvedConfig.command;
reactAppRootDirPath = resolvedConfig.root; reactAppRootDirPath = resolvedConfig.root;
urlPathname = (() => { urlPathname = (() => {
let out = resolvedConfig.env.BASE_URL; let out = resolvedConfig.env.BASE_URL;
if (out.startsWith(".") && command === "build") {
throw new Error(
[
`BASE_URL=${out} is not supported By Keycloakify. Use an absolute URL instead.`,
`If this is a problem, please open an issue at https://github.com/keycloakify/keycloakify/issues/new`
].join("\n")
);
}
if (out === undefined) { if (out === undefined) {
return undefined; return undefined;
} }
@ -45,7 +56,7 @@ export function keycloakify(): Plugin {
}); });
if (!fs.existsSync(cacheDirPath)) { if (!fs.existsSync(cacheDirPath)) {
fs.mkdirSync(cacheDirPath); fs.mkdirSync(cacheDirPath, { "recursive": true });
} }
fs.writeFileSync( fs.writeFileSync(
@ -70,6 +81,12 @@ export function keycloakify(): Plugin {
}); });
}, },
"transform": (code, id) => { "transform": (code, id) => {
assert(command !== undefined);
if (command !== "build") {
return;
}
assert(reactAppRootDirPath !== undefined); assert(reactAppRootDirPath !== undefined);
let transformedCode: string | undefined = undefined; let transformedCode: string | undefined = undefined;
@ -83,9 +100,8 @@ export function keycloakify(): Plugin {
} }
} }
const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
{ {
const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
const isTypeScriptFile = id.endsWith(".ts") || id.endsWith(".tsx"); const isTypeScriptFile = id.endsWith(".ts") || id.endsWith(".tsx");
if (!isTypeScriptFile && !isJavascriptFile) { if (!isTypeScriptFile && !isJavascriptFile) {
@ -93,8 +109,6 @@ export function keycloakify(): Plugin {
} }
} }
const windowToken = isJavascriptFile ? "window" : "(window as any)";
if (transformedCode === undefined) { if (transformedCode === undefined) {
transformedCode = code; transformedCode = code;
} }
@ -104,9 +118,9 @@ export function keycloakify(): Plugin {
"import.meta.env.BASE_URL", "import.meta.env.BASE_URL",
[ [
`(`, `(`,
`(${windowToken}.${nameOfTheGlobal} === undefined || import.meta.env.MODE === "development") ?`, `(window.${nameOfTheGlobal} === undefined || import.meta.env.MODE === "development")?`,
` "${urlPathname ?? "/"}" :`, `"${urlPathname ?? "/"}":`,
` \`\${${windowToken}.${nameOfTheGlobal}.url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/\``, `(window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/")`,
`)` `)`
].join("") ].join("")
); );
@ -120,10 +134,18 @@ export function keycloakify(): Plugin {
"code": transformedCode "code": transformedCode
}; };
}, },
"buildEnd": async () => { "closeBundle": async () => {
assert(command !== undefined);
if (command !== "build") {
return;
}
assert(buildDirPath !== undefined); assert(buildDirPath !== undefined);
await rm(pathJoin(buildDirPath, keycloak_resources), { "recursive": true, "force": true }); await rm(pathJoin(buildDirPath, keycloak_resources), { "recursive": true, "force": true });
} }
}; } satisfies Plugin;
return plugin as any;
} }