Remove all reference to --external-assets, broken feature
This commit is contained in:
parent
e892a0e7e6
commit
2309bd21c6
51
README.md
51
README.md
@ -41,7 +41,6 @@ Here is `yarn add keycloakify` for you 🍸
|
|||||||
- [Motivations](#motivations)
|
- [Motivations](#motivations)
|
||||||
- [How to use](#how-to-use)
|
- [How to use](#how-to-use)
|
||||||
- [Setting up the build tool](#setting-up-the-build-tool)
|
- [Setting up the build tool](#setting-up-the-build-tool)
|
||||||
- [Specify from where the resources should be downloaded.](#specify-from-where-the-resources-should-be-downloaded)
|
|
||||||
- [Developing your login and register pages in your React app](#developing-your-login-and-register-pages-in-your-react-app)
|
- [Developing your login and register pages in your React app](#developing-your-login-and-register-pages-in-your-react-app)
|
||||||
- [Just changing the look](#just-changing-the-look)
|
- [Just changing the look](#just-changing-the-look)
|
||||||
- [Changing the look **and** feel](#changing-the-look-and-feel)
|
- [Changing the look **and** feel](#changing-the-look-and-feel)
|
||||||
@ -70,10 +69,8 @@ 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
|
`"homepage"` must be specified only if the url path is not `/`
|
||||||
`--external-assets`(#specify-from-where-the-resources-should-be-downloaded) or if
|
(Onl `/YOUR-APP` matters `URL.OF` don't have to be the actual domain)
|
||||||
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.
|
||||||
@ -85,46 +82,6 @@ dependency with `yarn install` and build the keycloak theme with
|
|||||||
Once the build is complete instructions about how to load
|
Once the build is complete instructions about how to load
|
||||||
the theme into Keycloak are printed in the console.
|
the theme into Keycloak are printed in the console.
|
||||||
|
|
||||||
### Specify from where the resources should be downloaded.
|
|
||||||
|
|
||||||
*TL;DR*: Building the theme with the `--external-assets` option enables the login
|
|
||||||
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.
|
|
||||||
- Each time the app is updated, the theme must be updated.
|
|
||||||
- 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>
|
|
||||||
<summary>Click to expand</summary>
|
|
||||||
|
|
||||||
When you run `npx build-keycloak-theme` without arguments, Keycloakify will build
|
|
||||||
a standalone version of the Keycloak theme. That is to say even if your app, the
|
|
||||||
one hosted at the url specified as `homepage`, is down the Keycloak theme will still work.
|
|
||||||
It also mean that you won't have to update your theme on your Keycloak server each time
|
|
||||||
your app is updated.
|
|
||||||
In this mode, the default, every asset are served by the keycloak server.
|
|
||||||
The drawback of this approach is that when users access the login page for the first time
|
|
||||||
they have to download the whole app again.
|
|
||||||
You probably have [long-term asset caching](https://create-react-app.dev/docs/production-build/#static-file-caching)
|
|
||||||
enabled in the server that host your app ([example](https://github.com/garronej/keycloakify-demo-app/blob/224c43383548635a463fa68e8909c147ac189f0e/nginx.conf#L14))
|
|
||||||
so it can be interesting to only serve the html from Keycloak server and everything
|
|
||||||
else, your JS bundles, your CSS ect from the server that host your app.
|
|
||||||
|
|
||||||
To enable this behavior you car run:
|
|
||||||
```bash
|
|
||||||
npx build-keycloak-theme --external-assets
|
|
||||||
```
|
|
||||||
(instead of `npx build-keycloak-theme`)
|
|
||||||
|
|
||||||
This is something you probably want to do in your CI pipeline. [Example](https://github.com/garronej/keycloakify-demo-app/blob/224c43383548635a463fa68e8909c147ac189f0e/.github/workflows/ci.yaml#L112)
|
|
||||||
|
|
||||||
Also note that there is [a same-origin policy exception for fonts](https://en.wikipedia.org/wiki/Same-origin_policy#cite_note-3) so you must enabled
|
|
||||||
CORS for fonts on the server hosting your app. Concretely this mean that your server should add a `Access-Control-Allow-Origin: *` response header to
|
|
||||||
GET request on *.woff2?. [Example with Nginx](https://github.com/garronej/keycloakify-demo-app/blob/224c43383548635a463fa68e8909c147ac189f0e/nginx.conf#L18-L20)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
## Developing your login and register pages in your React app
|
## Developing your login and register pages in your React app
|
||||||
|
|
||||||
### Just changing the look
|
### Just changing the look
|
||||||
@ -240,8 +197,6 @@ NOTE: This build tool has only be tested on MacOS.
|
|||||||
You won't be able to [import things from your public directory in your JavaScript code](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system). (This isn't recommended anyway).
|
You won't be able to [import things from your public directory in your JavaScript code](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system). (This isn't recommended anyway).
|
||||||
|
|
||||||
## `@font-face` importing fonts from the `src/` dir
|
## `@font-face` importing fonts from the `src/` dir
|
||||||
|
|
||||||
**If you are building the theme with `--external-assets` this limitation doesn't apply.**
|
|
||||||
### Example of setup that **won't** work
|
### Example of setup that **won't** work
|
||||||
|
|
||||||
- We have a `fonts/` directory in `src/`
|
- We have a `fonts/` directory in `src/`
|
||||||
@ -322,5 +277,5 @@ flash of the blank html before the js bundle have been evaluated
|
|||||||
|
|
||||||
Part of the lib that runs with node, at build time.
|
Part of the lib that runs with node, at build time.
|
||||||
|
|
||||||
- `npx build-keycloak-theme [--external-assets]`: Builds the theme, the CWD is assumed to be the root of your react project.
|
- `npx build-keycloak-theme`: Builds the theme, the CWD is assumed to be the root of your react project.
|
||||||
- `npx download-sample-keycloak-themes`: Downloads the keycloak default themes (for development purposes)
|
- `npx download-sample-keycloak-themes`: Downloads the keycloak default themes (for development purposes)
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "keycloakify",
|
"name": "keycloakify",
|
||||||
"version": "0.3.14",
|
"version": "0.3.15",
|
||||||
"description": "Keycloak theme generator for Reacts app",
|
"description": "Keycloak theme generator for Reacts app",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -37,12 +37,7 @@ export function generateFtlFilesCodeFactory(
|
|||||||
cssGlobalsToDefine: Record<string, string>;
|
cssGlobalsToDefine: Record<string, string>;
|
||||||
indexHtmlCode: string;
|
indexHtmlCode: string;
|
||||||
urlPathname: string;
|
urlPathname: string;
|
||||||
} & ({
|
}
|
||||||
mode: "standalone";
|
|
||||||
} | {
|
|
||||||
mode: "external assets";
|
|
||||||
urlOrigin: string;
|
|
||||||
})
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, urlPathname } = params;
|
const { ftlValuesGlobalName, cssGlobalsToDefine, indexHtmlCode, urlPathname } = params;
|
||||||
@ -53,19 +48,7 @@ export function generateFtlFilesCodeFactory(
|
|||||||
|
|
||||||
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
||||||
ftlValuesGlobalName,
|
ftlValuesGlobalName,
|
||||||
"jsCode": $(element).html()!,
|
"jsCode": $(element).html()!
|
||||||
...(() => {
|
|
||||||
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);
|
||||||
@ -76,18 +59,7 @@ export function generateFtlFilesCodeFactory(
|
|||||||
|
|
||||||
const { fixedCssCode } = replaceImportsInInlineCssCode({
|
const { fixedCssCode } = replaceImportsInInlineCssCode({
|
||||||
"cssCode": $(element).html()!,
|
"cssCode": $(element).html()!,
|
||||||
"urlPathname": params.urlPathname,
|
"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);
|
||||||
@ -106,24 +78,13 @@ export function generateFtlFilesCodeFactory(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (params.mode) {
|
$(element).attr(
|
||||||
case "external assets":
|
attrName,
|
||||||
$(element).attr(
|
href.replace(
|
||||||
attrName,
|
new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`),
|
||||||
href.replace(/^\//, `${params.urlOrigin}/`)
|
"${url.resourcesPath}/build/"
|
||||||
);
|
)
|
||||||
break;
|
);
|
||||||
case "standalone":
|
|
||||||
$(element).attr(
|
|
||||||
attrName,
|
|
||||||
href.replace(
|
|
||||||
new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`),
|
|
||||||
"${url.resourcesPath}/build/"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -21,12 +21,7 @@ export function generateKeycloakThemeResources(
|
|||||||
reactAppBuildDirPath: string;
|
reactAppBuildDirPath: string;
|
||||||
keycloakThemeBuildingDirPath: string;
|
keycloakThemeBuildingDirPath: string;
|
||||||
urlPathname: string;
|
urlPathname: string;
|
||||||
} & ({
|
}
|
||||||
mode: "standalone";
|
|
||||||
} | {
|
|
||||||
mode: "external assets";
|
|
||||||
urlOrigin: string;
|
|
||||||
})
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, urlPathname } = params;
|
const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, urlPathname } = params;
|
||||||
@ -50,42 +45,28 @@ export function generateKeycloakThemeResources(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.mode === "standalone") {
|
|
||||||
|
|
||||||
if (/\.css?$/i.test(filePath)) {
|
if (/\.css?$/i.test(filePath)) {
|
||||||
|
|
||||||
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode(
|
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode(
|
||||||
{ "cssCode": sourceCode.toString("utf8") }
|
{ "cssCode": sourceCode.toString("utf8") }
|
||||||
);
|
);
|
||||||
|
|
||||||
allCssGlobalsToDefine = {
|
allCssGlobalsToDefine = {
|
||||||
...allCssGlobalsToDefine,
|
...allCssGlobalsToDefine,
|
||||||
...cssGlobalsToDefine
|
...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 } = replaceImportsFromStaticInJsCode({
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
||||||
"jsCode": sourceCode.toString("utf8"),
|
"jsCode": sourceCode.toString("utf8"),
|
||||||
ftlValuesGlobalName,
|
ftlValuesGlobalName
|
||||||
...(() => {
|
|
||||||
switch (params.mode) {
|
|
||||||
case "external assets": return {
|
|
||||||
"mode": params.mode,
|
|
||||||
"urlOrigin": params.urlOrigin,
|
|
||||||
"urlPathname": params.urlPathname
|
|
||||||
};
|
|
||||||
case "standalone": return {
|
|
||||||
"mode": params.mode
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
||||||
@ -103,18 +84,7 @@ export function generateKeycloakThemeResources(
|
|||||||
"indexHtmlCode": fs.readFileSync(
|
"indexHtmlCode": fs.readFileSync(
|
||||||
pathJoin(reactAppBuildDirPath, "index.html")
|
pathJoin(reactAppBuildDirPath, "index.html")
|
||||||
).toString("utf8"),
|
).toString("utf8"),
|
||||||
urlPathname,
|
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 => {
|
||||||
|
@ -11,8 +11,6 @@ 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");
|
||||||
@ -26,8 +24,7 @@ if (require.main === module) {
|
|||||||
keycloakThemeBuildingDirPath,
|
keycloakThemeBuildingDirPath,
|
||||||
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
|
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
|
||||||
"themeName": parsedPackageJson.name,
|
"themeName": parsedPackageJson.name,
|
||||||
...(() => {
|
"urlPathname": (() => {
|
||||||
|
|
||||||
|
|
||||||
const url = (() => {
|
const url = (() => {
|
||||||
|
|
||||||
@ -39,35 +36,12 @@ if (require.main === module) {
|
|||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const urlPathname =
|
return url === undefined ?
|
||||||
url === undefined ?
|
"/" :
|
||||||
"/" :
|
url.pathname.replace(/([^/])$/, "$1/");
|
||||||
url.pathname.replace(/([^/])$/, "$1/");
|
|
||||||
|
|
||||||
return !doUseExternalAssets ?
|
|
||||||
{
|
|
||||||
"mode": "standalone",
|
|
||||||
urlPathname
|
|
||||||
} as const
|
|
||||||
:
|
|
||||||
{
|
|
||||||
"mode": "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({
|
||||||
|
@ -5,27 +5,14 @@ export function replaceImportsFromStaticInJsCode(
|
|||||||
params: {
|
params: {
|
||||||
ftlValuesGlobalName: string;
|
ftlValuesGlobalName: string;
|
||||||
jsCode: string;
|
jsCode: string;
|
||||||
} & ({
|
}
|
||||||
mode: "standalone";
|
|
||||||
} | {
|
|
||||||
mode: "external assets";
|
|
||||||
urlOrigin: string;
|
|
||||||
urlPathname: string;
|
|
||||||
})
|
|
||||||
): { fixedJsCode: string; } {
|
): { fixedJsCode: string; } {
|
||||||
|
|
||||||
const { jsCode, ftlValuesGlobalName } = 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,
|
||||||
(() => {
|
`window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
|
||||||
switch (params.mode) {
|
|
||||||
case "standalone":
|
|
||||||
return `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`;
|
|
||||||
case "external assets":
|
|
||||||
return `"${params.urlOrigin}${params.urlPathname}static/`;
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return { fixedJsCode };
|
return { fixedJsCode };
|
||||||
@ -36,12 +23,7 @@ export function replaceImportsInInlineCssCode(
|
|||||||
params: {
|
params: {
|
||||||
cssCode: string;
|
cssCode: string;
|
||||||
urlPathname: string;
|
urlPathname: string;
|
||||||
} & ({
|
}
|
||||||
mode: "standalone";
|
|
||||||
} | {
|
|
||||||
mode: "external assets";
|
|
||||||
urlOrigin: string;
|
|
||||||
})
|
|
||||||
): { fixedCssCode: string; } {
|
): { fixedCssCode: string; } {
|
||||||
|
|
||||||
const { cssCode, urlPathname } = params;
|
const { cssCode, urlPathname } = params;
|
||||||
@ -50,13 +32,7 @@ export function replaceImportsInInlineCssCode(
|
|||||||
urlPathname === "/" ?
|
urlPathname === "/" ?
|
||||||
/url\(\/([^/][^)]+)\)/g :
|
/url\(\/([^/][^)]+)\)/g :
|
||||||
new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"),
|
new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"),
|
||||||
(...[, group]) => `url(${(() => {
|
(...[, group]) => `url(${"${url.resourcesPath}/build/" + group})`
|
||||||
switch (params.mode) {
|
|
||||||
case "standalone": return "${url.resourcesPath}/build/" + group;
|
|
||||||
case "external assets": return params.urlOrigin + urlPathname + group
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
})`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return { fixedCssCode };
|
return { fixedCssCode };
|
||||||
|
@ -12,7 +12,6 @@ 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": "standalone",
|
|
||||||
"urlPathname": "/keycloakify-demo-app/"
|
"urlPathname": "/keycloakify-demo-app/"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@ const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
|||||||
3: "0664cdc0"
|
3: "0664cdc0"
|
||||||
}[e] + ".chunk.js"
|
}[e] + ".chunk.js"
|
||||||
}
|
}
|
||||||
`,
|
`
|
||||||
"mode": "standalone"
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log({ fixedJsCode });
|
console.log({ fixedJsCode });
|
||||||
|
Loading…
x
Reference in New Issue
Block a user