Fix previous build, improve README

This commit is contained in:
Joseph Garrone 2021-03-26 15:29:17 +01:00
parent 4f733736db
commit 6f133428f8
8 changed files with 99 additions and 60 deletions

View File

@ -70,6 +70,10 @@ Here is `yarn add keycloakify` for you 🍸
"keycloak": "yarn build && build-keycloak-theme", "keycloak": "yarn build && build-keycloak-theme",
}, },
``` ```
`"homepage"` must be specified only if the theme is build using
`--external-assets`(#specify-from-where-the-resources-should-be-downloaded) or if
the url path is not `/` (only the url path will be considered so it doesn't matter if the
base url is wrong)
It is mandatory that you specify the url where your app will be available It is mandatory that you specify the url where your app will be available
using the `homepage` field. using the `homepage` field.
@ -88,6 +92,7 @@ page to load faster for first time users but it also implies that:
- If the app is down, your Keycloak login and register pages are down as well. - If the app is down, your Keycloak login and register pages are down as well.
- Each time the app is updated, the theme must be updated. - Each time the app is updated, the theme must be updated.
- CORS must be enabled for fonts. - CORS must be enabled for fonts.
- You must know at build time what will be the url of your app (`"homepage"` in `package.json`).
<details> <details>
<summary>Click to expand</summary> <summary>Click to expand</summary>

View File

@ -1,6 +1,6 @@
{ {
"name": "keycloakify", "name": "keycloakify",
"version": "0.3.10", "version": "0.3.11",
"description": "Keycloak theme generator for Reacts app", "description": "Keycloak theme generator for Reacts app",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -30,25 +30,22 @@ function loadFtlFile(ftlFileBasename: PageId | "template.ftl") {
} }
} }
export type Mode = {
type: "standalone";
urlPathname: string;
} | {
type: "external assets";
urlPathname: string;
urlOrigin: string;
}
export function generateFtlFilesCodeFactory( export function generateFtlFilesCodeFactory(
params: { params: {
ftlValuesGlobalName: string; ftlValuesGlobalName: string;
cssGlobalsToDefine: Record<string, string>; cssGlobalsToDefine: Record<string, string>;
indexHtmlCode: string; indexHtmlCode: string;
mode: Mode; urlPathname: string;
} } & ({
mode: "standalone";
} | {
mode: "external assets";
urlOrigin: string;
})
) { ) {
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, mode } = params; const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, urlPathname } = params;
const $ = cheerio.load(indexHtmlCode); const $ = cheerio.load(indexHtmlCode);
@ -57,7 +54,18 @@ export function generateFtlFilesCodeFactory(
const { fixedJsCode } = replaceImportsFromStaticInJsCode({ const { fixedJsCode } = replaceImportsFromStaticInJsCode({
ftlValuesGlobalName, ftlValuesGlobalName,
"jsCode": $(element).html()!, "jsCode": $(element).html()!,
mode ...(() => {
switch (params.mode) {
case "standalone": return {
"mode": params.mode
};
case "external assets": return {
"mode": params.mode,
"urlOrigin": params.urlOrigin,
"urlPathname": params.urlPathname,
};
}
})()
}); });
$(element).text(fixedJsCode); $(element).text(fixedJsCode);
@ -68,7 +76,18 @@ export function generateFtlFilesCodeFactory(
const { fixedCssCode } = replaceImportsInInlineCssCode({ const { fixedCssCode } = replaceImportsInInlineCssCode({
"cssCode": $(element).html()!, "cssCode": $(element).html()!,
mode "urlPathname": params.urlPathname,
...(() => {
switch (params.mode) {
case "standalone": return {
"mode": params.mode
};
case "external assets": return {
"mode": params.mode,
"urlOrigin": params.urlOrigin,
};
}
})()
}); });
$(element).text(fixedCssCode); $(element).text(fixedCssCode);
@ -87,18 +106,18 @@ export function generateFtlFilesCodeFactory(
return; return;
} }
switch (mode.type) { switch (params.mode) {
case "external assets": case "external assets":
$(element).attr( $(element).attr(
attrName, attrName,
href.replace(/^\//, `${mode.urlOrigin}/`) href.replace(/^\//, `${params.urlOrigin}/`)
); );
break; break;
case "standalone": case "standalone":
$(element).attr( $(element).attr(
attrName, attrName,
href.replace( href.replace(
new RegExp(`^${mode.urlPathname.replace(/\//g, "\\/")}`), new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`),
"${url.resourcesPath}/build/" "${url.resourcesPath}/build/"
) )
); );
@ -131,7 +150,7 @@ export function generateFtlFilesCodeFactory(
'<style>', '<style>',
generateCssCodeToDefineGlobals({ generateCssCodeToDefineGlobals({
cssGlobalsToDefine, cssGlobalsToDefine,
"urlPathname": mode.urlPathname urlPathname
}).cssCodeToPrependInHead, }).cssCodeToPrependInHead,
'</style>', '</style>',
'' ''

View File

@ -6,7 +6,7 @@ import {
replaceImportsInCssCode, replaceImportsInCssCode,
replaceImportsFromStaticInJsCode replaceImportsFromStaticInJsCode
} from "./replaceImportFromStatic"; } from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds, Mode } from "./generateFtl"; import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes"; import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip"; import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import * as child_process from "child_process"; import * as child_process from "child_process";
@ -20,11 +20,16 @@ export function generateKeycloakThemeResources(
themeName: string; themeName: string;
reactAppBuildDirPath: string; reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string; keycloakThemeBuildingDirPath: string;
mode: Mode; urlPathname: string;
} } & ({
mode: "standalone";
} | {
mode: "external assets";
urlOrigin: string;
})
) { ) {
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, mode } = params; const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, urlPathname } = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login"); const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
@ -45,7 +50,7 @@ export function generateKeycloakThemeResources(
return undefined; return undefined;
} }
if (mode.type === "standalone") { if (params.mode === "standalone") {
if (/\.css?$/i.test(filePath)) { if (/\.css?$/i.test(filePath)) {
@ -67,7 +72,7 @@ export function generateKeycloakThemeResources(
const { fixedJsCode } = replaceImportsFromStaticInJsCode({ const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"), "jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName, ftlValuesGlobalName,
mode "mode": params.mode
}); });
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") }; return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
@ -87,7 +92,18 @@ export function generateKeycloakThemeResources(
"indexHtmlCode": fs.readFileSync( "indexHtmlCode": fs.readFileSync(
pathJoin(reactAppBuildDirPath, "index.html") pathJoin(reactAppBuildDirPath, "index.html")
).toString("utf8"), ).toString("utf8"),
mode urlPathname,
...(() => {
switch (params.mode) {
case "external assets": return {
"mode": params.mode,
"urlOrigin": params.urlOrigin
};
case "standalone": return {
"mode": params.mode
};
}
})()
}); });
pageIds.forEach(pageId => { pageIds.forEach(pageId => {

View File

@ -26,7 +26,7 @@ if (require.main === module) {
keycloakThemeBuildingDirPath, keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"), "reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
"themeName": parsedPackageJson.name, "themeName": parsedPackageJson.name,
"mode": (() => { ...(() => {
const url = (() => { const url = (() => {
@ -44,16 +44,14 @@ if (require.main === module) {
"/" : "/" :
url.pathname.replace(/([^/])$/, "$1/"); url.pathname.replace(/([^/])$/, "$1/");
return !doUseExternalAssets ? return !doUseExternalAssets ?
{ {
"type": "standalone", "mode": "standalone",
urlPathname urlPathname
} as const } as const
: :
{ {
"type": "external assets", "mode": "external assets",
urlPathname, urlPathname,
"urlOrigin": (() => { "urlOrigin": (() => {

View File

@ -1,32 +1,29 @@
import * as crypto from "crypto"; import * as crypto from "crypto";
type Mode = {
type: "standalone";
} | {
type: "external assets";
urlOrigin: string;
urlPathname: string;
}
export function replaceImportsFromStaticInJsCode( export function replaceImportsFromStaticInJsCode(
params: { params: {
ftlValuesGlobalName: string; ftlValuesGlobalName: string;
jsCode: string; jsCode: string;
mode: Mode; } & ({
} mode: "standalone";
} | {
mode: "external assets";
urlOrigin: string;
urlPathname: string;
})
): { fixedJsCode: string; } { ): { fixedJsCode: string; } {
const { jsCode, ftlValuesGlobalName, mode } = params; const { jsCode, ftlValuesGlobalName } = params;
const fixedJsCode = jsCode.replace( const fixedJsCode = jsCode.replace(
/[a-z]+\.[a-z]+\+"static\//g, /[a-z]+\.[a-z]+\+"static\//g,
(() => { (() => {
switch (mode.type) { switch (params.mode) {
case "standalone": case "standalone":
return `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`; return `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`;
case "external assets": case "external assets":
return `"${mode.urlOrigin}${mode.urlPathname}static/`; return `"${params.urlOrigin}${params.urlPathname}static/`;
} }
})() })()
); );
@ -38,22 +35,28 @@ export function replaceImportsFromStaticInJsCode(
export function replaceImportsInInlineCssCode( export function replaceImportsInInlineCssCode(
params: { params: {
cssCode: string; cssCode: string;
mode: Mode; urlPathname: string;
} } & ({
mode: "standalone";
} | {
mode: "external assets";
urlOrigin: string;
})
): { fixedCssCode: string; } { ): { fixedCssCode: string; } {
const { cssCode, mode } = params; const { cssCode, urlPathname } = params;
const fixedCssCode = cssCode.replace( const fixedCssCode = cssCode.replace(
/url\((\/[^/][^)]+)\)/g, urlPathname === "/" ?
(...[,group])=> `url(${ /url\(\/([^/][^)]+)\)/g :
(()=>{ new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"),
switch(mode.type){ (...[, group]) => `url(${(() => {
case "standalone": return "${url.resourcesPath}/build" + group; switch (params.mode) {
case "external assets": return mode.urlOrigin + group case "standalone": return "${url.resourcesPath}/build/" + group;
} case "external assets": return params.urlOrigin + urlPathname + group
})() }
})` })()
})`
); );
return { fixedCssCode }; return { fixedCssCode };

View File

@ -12,9 +12,7 @@ generateKeycloakThemeResources({
"themeName": "keycloakify-demo-app", "themeName": "keycloakify-demo-app",
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"), "reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"), "keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"mode": { "mode": "standalone",
"type": "standalone", "urlPathname": "/keycloakify-demo-app/"
"urlPathname": "/keycloakify-demo-app/"
}
}); });

View File

@ -20,7 +20,7 @@ const { fixedJsCode } = replaceImportsFromStaticInJsCode({
}[e] + ".chunk.js" }[e] + ".chunk.js"
} }
`, `,
"mode": { "type": "standalone" } "mode": "standalone"
}); });
console.log({ fixedJsCode }); console.log({ fixedJsCode });