Compare commits

...

12 Commits

8 changed files with 172 additions and 47 deletions

View File

@ -1,3 +1,19 @@
### **0.3.8** (2021-03-22)
- Make standalone mode the default
### **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) ### **0.3.4** (2021-03-22)
- Bugfix: Import assets from CSS - Bugfix: Import assets from CSS

View File

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

View File

@ -29,15 +29,25 @@ 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;
} }
) { ) {
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode } = params; const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, mode } = params;
const $ = cheerio.load(indexHtmlCode); const $ = cheerio.load(indexHtmlCode);
@ -45,7 +55,8 @@ export function generateFtlFilesCodeFactory(
const { fixedJsCode } = replaceImportFromStaticInJsCode({ const { fixedJsCode } = replaceImportFromStaticInJsCode({
ftlValuesGlobalName, ftlValuesGlobalName,
"jsCode": $(element).html()! "jsCode": $(element).html()!,
mode
}); });
$(element).text(fixedJsCode); $(element).text(fixedJsCode);
@ -60,11 +71,28 @@ export function generateFtlFilesCodeFactory(
const href = $(element).attr(attrName); const href = $(element).attr(attrName);
if (!href?.startsWith("/")) { if (href === undefined) {
return; return;
} }
$(element).attr(attrName, "${url.resourcesPath}/build" + href); switch (mode.type) {
case "external assets":
$(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 ? [] : [ ...(Object.keys(cssGlobalsToDefine).length === 0 ? [] : [
'', '',
'<style>', '<style>',
generateCssCodeToDefineGlobals( generateCssCodeToDefineGlobals({
{ cssGlobalsToDefine } cssGlobalsToDefine,
).cssCodeToPrependInHead, "urlPathname": mode.urlPathname
}).cssCodeToPrependInHead,
'</style>', '</style>',
'' ''
]), ]),

View File

@ -6,23 +6,25 @@ import {
replaceImportFromStaticInCssCode, replaceImportFromStaticInCssCode,
replaceImportFromStaticInJsCode replaceImportFromStaticInJsCode
} from "./replaceImportFromStatic"; } from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl"; import { generateFtlFilesCodeFactory, pageIds, Mode } 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";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName"; import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath"; import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside"; import { isInside } from "../tools/isInside";
export function generateKeycloakThemeResources( export function generateKeycloakThemeResources(
params: { params: {
themeName: string; themeName: string;
reactAppBuildDirPath: string; reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: 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"); const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
@ -43,6 +45,7 @@ export function generateKeycloakThemeResources(
return undefined; return undefined;
} }
if (mode.type === "standalone") {
if (/\.css?$/i.test(filePath)) { if (/\.css?$/i.test(filePath)) {
@ -63,13 +66,16 @@ export function generateKeycloakThemeResources(
const { fixedJsCode } = replaceImportFromStaticInJsCode({ const { fixedJsCode } = replaceImportFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"), "jsCode": sourceCode.toString("utf8"),
ftlValuesGlobalName ftlValuesGlobalName,
mode
}); });
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") }; return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
} }
}
return { "modifiedSourceCode": sourceCode }; return { "modifiedSourceCode": sourceCode };
} }
@ -80,7 +86,8 @@ export function generateKeycloakThemeResources(
ftlValuesGlobalName, ftlValuesGlobalName,
"indexHtmlCode": fs.readFileSync( "indexHtmlCode": fs.readFileSync(
pathJoin(reactAppBuildDirPath, "index.html") pathJoin(reactAppBuildDirPath, "index.html")
).toString("utf8") ).toString("utf8"),
mode
}); });
pageIds.forEach(pageId => { 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 { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process"; import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles"; import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { URL } from "url";
const reactProjectDirPath = process.cwd(); const reactProjectDirPath = process.cwd();
const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-assets";
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json")); const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak"); export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
@ -22,7 +25,51 @@ if (require.main === module) {
generateKeycloakThemeResources({ generateKeycloakThemeResources({
keycloakThemeBuildingDirPath, keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"), "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 !doUseExternalAssets ?
{
"type": "standalone",
urlPathname
} as const
:
{
"type": "external assets",
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({ const { jarFilePath } = generateJavaStackFiles({

View File

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

View File

@ -9,8 +9,12 @@ import {
setupSampleReactProject(); setupSampleReactProject();
generateKeycloakThemeResources({ generateKeycloakThemeResources({
"themeName": "onyxia-ui", "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": {
"type": "standalone",
"urlPathname": "/keycloakify-demo-app/"
}
}); });

View File

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