Compare commits

...

12 Commits

8 changed files with 174 additions and 53 deletions

View File

@ -1,3 +1,19 @@
### **0.3.7** (2021-03-22)
- (test) external asset mode by default
### **0.3.6** (2021-03-22)
- Fix previous release
### **0.3.5** (2021-03-22)
- support homepage with urlPath
### **0.3.4** (2021-03-22)
- Bugfix: Import assets from CSS
### **0.3.3** (2021-03-22)
- Fix submit not receving correct text

View File

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

View File

@ -11,9 +11,9 @@ import { objectKeys } from "evt/tools/typeSafety/objectKeys";
export const pageIds = ["login.ftl", "register.ftl", "info.ftl", "error.ftl", "login-reset-password.ftl", "login-verify-email.ftl"] as const;
export type PageId = typeof pageIds[number];
export type PageId = typeof pageIds[number];
function loadAdjacentFile(fileBasename: string){
function loadAdjacentFile(fileBasename: string) {
return fs.readFileSync(pathJoin(__dirname, fileBasename))
.toString("utf8");
};
@ -29,15 +29,25 @@ function loadFtlFile(ftlFileBasename: PageId | "template.ftl") {
}
}
export type Mode = {
type: "standalone";
urlPathname: string;
} | {
type: "static fetched from app";
urlPathname: string;
urlOrigin: string;
}
export function generateFtlFilesCodeFactory(
params: {
ftlValuesGlobalName: string;
cssGlobalsToDefine: Record<string, string>;
indexHtmlCode: string;
mode: Mode;
}
) {
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode } = params;
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, mode } = params;
const $ = cheerio.load(indexHtmlCode);
@ -45,7 +55,8 @@ export function generateFtlFilesCodeFactory(
const { fixedJsCode } = replaceImportFromStaticInJsCode({
ftlValuesGlobalName,
"jsCode": $(element).html()!
"jsCode": $(element).html()!,
mode
});
$(element).text(fixedJsCode);
@ -60,11 +71,28 @@ export function generateFtlFilesCodeFactory(
const href = $(element).attr(attrName);
if (!href?.startsWith("/")) {
if (href === undefined) {
return;
}
$(element).attr(attrName, "${url.resourcesPath}/build" + href);
switch (mode.type) {
case "static fetched from app":
$(element).attr(
attrName,
href.replace(/^\//, `${mode.urlOrigin}/`)
);
break;
case "standalone":
$(element).attr(
attrName,
href.replace(
new RegExp(`^${mode.urlPathname.replace(/\//g, "\\/")}`),
"${url.resourcesPath}/build/"
)
);
break;
}
})
);
@ -89,9 +117,10 @@ export function generateFtlFilesCodeFactory(
...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
'',
'<style>',
generateCssCodeToDefineGlobals(
{ cssGlobalsToDefine }
).cssCodeToPrependInHead,
generateCssCodeToDefineGlobals({
cssGlobalsToDefine,
"urlPathname": mode.urlPathname
}).cssCodeToPrependInHead,
'</style>',
''
]),

View File

@ -6,23 +6,25 @@ import {
replaceImportFromStaticInCssCode,
replaceImportFromStaticInJsCode
} from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import { generateFtlFilesCodeFactory, pageIds, Mode } from "./generateFtl";
import { builtinThemesUrl } from "../install-builtin-keycloak-themes";
import { downloadAndUnzip } from "../tools/downloadAndUnzip";
import * as child_process from "child_process";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
export function generateKeycloakThemeResources(
params: {
themeName: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
mode: Mode;
}
) {
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath } = params;
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, mode } = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
@ -43,30 +45,34 @@ export function generateKeycloakThemeResources(
return undefined;
}
if (mode.type === "standalone") {
if (/\.css?$/i.test(filePath)) {
if (/\.css?$/i.test(filePath)) {
const { cssGlobalsToDefine, fixedCssCode } = replaceImportFromStaticInCssCode(
{ "cssCode": sourceCode.toString("utf8") }
);
const { cssGlobalsToDefine, fixedCssCode } = replaceImportFromStaticInCssCode(
{ "cssCode": sourceCode.toString("utf8") }
);
allCssGlobalsToDefine = {
...allCssGlobalsToDefine,
...cssGlobalsToDefine
};
allCssGlobalsToDefine = {
...allCssGlobalsToDefine,
...cssGlobalsToDefine
};
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
}
}
if (/\.js?$/i.test(filePath)) {
if (/\.js?$/i.test(filePath)) {
const { fixedJsCode } = replaceImportFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName
});
const { fixedJsCode } = replaceImportFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName,
mode
});
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
}
}
@ -80,7 +86,8 @@ export function generateKeycloakThemeResources(
ftlValuesGlobalName,
"indexHtmlCode": fs.readFileSync(
pathJoin(reactAppBuildDirPath, "index.html")
).toString("utf8")
).toString("utf8"),
mode
});
pageIds.forEach(pageId => {

View File

@ -6,10 +6,13 @@ import type { ParsedPackageJson } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { URL } from "url";
const reactProjectDirPath = process.cwd();
const isStandalone = process.argv[2]?.toLowerCase() === "--standalone";
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
@ -22,7 +25,51 @@ if (require.main === module) {
generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
"themeName": parsedPackageJson.name
"themeName": parsedPackageJson.name,
"mode": (() => {
const url = (() => {
const { homepage } = parsedPackageJson;
return homepage === undefined ?
undefined :
new URL(homepage);
})();
const urlPathname =
url === undefined ?
"/" :
url.pathname.replace(/([^/])$/, "$1/");
return isStandalone ?
{
"type": "standalone",
urlPathname
} as const
:
{
"type": "static fetched from app",
urlPathname,
"urlOrigin": (() => {
if (url === undefined) {
console.error("ERROR: You must specify 'homepage' in your package.json");
process.exit(-1);
}
return url.origin;
})()
} as const;
})()
});
const { jarFilePath } = generateJavaStackFiles({

View File

@ -1,19 +1,39 @@
import * as crypto from "crypto";
type Mode = {
type: "standalone";
} | {
type: "static fetched from app";
urlOrigin: string;
urlPathname: string;
}
export function replaceImportFromStaticInJsCode(
params: {
ftlValuesGlobalName: string;
jsCode: string;
mode: Mode;
}
): { fixedJsCode: string; } {
const { jsCode, ftlValuesGlobalName } = params;
const { jsCode, ftlValuesGlobalName, mode } = params;
const fixedJsCode = (() => {
switch (mode.type) {
case "standalone":
return jsCode!.replace(
/[a-z]+\.[a-z]+\+"static\//g,
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
);
case "static fetched from app":
return jsCode!.replace(
/[a-z]+\.[a-z]+\+"static\//g,
`"${mode.urlOrigin}${mode.urlPathname}static/`
);
}
})();
const fixedJsCode = jsCode!.replace(
/"static\//g,
`window.${ftlValuesGlobalName}.url.resourcesPath.replace(/^\\//,"") + "/build/static/`
);
return { fixedJsCode };
@ -32,7 +52,7 @@ export function replaceImportFromStaticInCssCode(
const cssGlobalsToDefine: Record<string, string> = {};
new Set(cssCode.match(/(url\(\/[^)]+\))/g) ?? [])
new Set(cssCode.match(/url\(\/[^)]+\)[^;}]*/g) ?? [])
.forEach(match =>
cssGlobalsToDefine[
"url" + crypto
@ -60,12 +80,13 @@ export function replaceImportFromStaticInCssCode(
export function generateCssCodeToDefineGlobals(
params: {
cssGlobalsToDefine: Record<string, string>;
urlPathname: string;
}
): {
cssCodeToPrependInHead: string;
} {
const { cssGlobalsToDefine } = params;
const { cssGlobalsToDefine, urlPathname } = params;
return {
"cssCodeToPrependInHead": [
@ -73,12 +94,8 @@ export function generateCssCodeToDefineGlobals(
...Object.keys(cssGlobalsToDefine)
.map(cssVariableName => [
`--${cssVariableName}:`,
[
"url(",
"${url.resourcesPath}/build" +
cssGlobalsToDefine[cssVariableName].match(/^url\(([^)]+)\)$/)![1],
")"
].join("")
cssGlobalsToDefine[cssVariableName]
.replace(new RegExp(`url\\(${urlPathname.replace(/\//g, "\\/")}`, "g"), "url(${url.resourcesPath}/build/")
].join(" "))
.map(line => ` ${line};`),
"}"

View File

@ -1,7 +1,7 @@
import { join as pathJoin } from "path";
import { generateKeycloakThemeResources } from "../bin/build-keycloak-theme/generateKeycloakThemeResources";
import {
import {
setupSampleReactProject,
sampleReactProjectDirPath
} from "./setupSampleReactProject";
@ -9,8 +9,12 @@ import {
setupSampleReactProject();
generateKeycloakThemeResources({
"themeName": "onyxia-ui",
"themeName": "keycloakify-demo-app",
"reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"),
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme")
"keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"),
"mode": {
"type": "standalone",
"urlPathname": "/keycloakify-demo-app/"
}
});

View File

@ -19,7 +19,8 @@ const { fixedJsCode } = replaceImportFromStaticInJsCode({
3: "0664cdc0"
}[e] + ".chunk.js"
}
`
`,
"mode": { "type": "standalone" }
});
console.log({ fixedJsCode });
@ -45,6 +46,6 @@ const { fixedCssCode, cssGlobalsToDefine } = replaceImportFromStaticInCssCode({
console.log({ fixedCssCode, cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine });
const { cssCodeToPrependInHead } = generateCssCodeToDefineGlobals({ cssGlobalsToDefine, "urlPathname": "/" });
console.log({ cssCodeToPrependInHead });