Fundation
This commit is contained in:
parent
b6d2f9f691
commit
5b350274bd
@ -1,8 +1,11 @@
|
|||||||
|
export const nameOfTheGlobal = "kcContext";
|
||||||
export const keycloak_resources = "keycloak-resources";
|
export const keycloak_resources = "keycloak-resources";
|
||||||
export const resources_common = "resources-common";
|
export const resources_common = "resources-common";
|
||||||
export const lastKeycloakVersionWithAccountV1 = "21.1.2";
|
export const lastKeycloakVersionWithAccountV1 = "21.1.2";
|
||||||
|
export const keycloakifyViteConfigJsonBasename = ".keycloakifyViteConfig.json";
|
||||||
|
export const basenameOfTheKeycloakifyResourcesDir = "build";
|
||||||
|
|
||||||
export const themeTypes = ["login", "account"] as const;
|
export const themeTypes = ["login", "account"] as const;
|
||||||
export const accountV1 = "account-v1";
|
export const accountV1ThemeName = "account-v1";
|
||||||
|
|
||||||
export type ThemeType = (typeof themeTypes)[number];
|
export type ThemeType = (typeof themeTypes)[number];
|
||||||
|
@ -24,6 +24,8 @@ export type BuildOptions = {
|
|||||||
/** If your app is hosted under a subpath, it's the case in CRA if you have "homepage": "https://example.com/my-app" in your package.json
|
/** If your app is hosted under a subpath, it's the case in CRA if you have "homepage": "https://example.com/my-app" in your package.json
|
||||||
* In this case the urlPathname will be "/my-app/" */
|
* In this case the urlPathname will be "/my-app/" */
|
||||||
urlPathname: string | undefined;
|
urlPathname: string | undefined;
|
||||||
|
assetsDirPath: string;
|
||||||
|
bundler: "vite" | "webpack";
|
||||||
};
|
};
|
||||||
|
|
||||||
export function readBuildOptions(params: { reactAppRootDirPath: string; processArgv: string[] }): BuildOptions {
|
export function readBuildOptions(params: { reactAppRootDirPath: string; processArgv: string[] }): BuildOptions {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export const ftlValuesGlobalName = "kcContext";
|
|
@ -5,10 +5,9 @@ import { replaceImportsInInlineCssCode } from "../replacers/replaceImportsInInli
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { objectKeys } from "tsafe/objectKeys";
|
import { objectKeys } from "tsafe/objectKeys";
|
||||||
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
|
|
||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import type { ThemeType } from "../../constants";
|
import { type ThemeType, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../constants";
|
||||||
|
|
||||||
export type BuildOptionsLike = {
|
export type BuildOptionsLike = {
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
@ -20,7 +19,6 @@ assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
|||||||
export function generateFtlFilesCodeFactory(params: {
|
export function generateFtlFilesCodeFactory(params: {
|
||||||
themeName: string;
|
themeName: string;
|
||||||
indexHtmlCode: string;
|
indexHtmlCode: string;
|
||||||
//NOTE: Expected to be an empty object if external assets mode is enabled.
|
|
||||||
cssGlobalsToDefine: Record<string, string>;
|
cssGlobalsToDefine: Record<string, string>;
|
||||||
buildOptions: BuildOptionsLike;
|
buildOptions: BuildOptionsLike;
|
||||||
keycloakifyVersion: string;
|
keycloakifyVersion: string;
|
||||||
@ -70,7 +68,10 @@ export function generateFtlFilesCodeFactory(params: {
|
|||||||
|
|
||||||
$(element).attr(
|
$(element).attr(
|
||||||
attrName,
|
attrName,
|
||||||
href.replace(new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`), "${url.resourcesPath}/build/")
|
href.replace(
|
||||||
|
new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`),
|
||||||
|
`\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/`
|
||||||
|
)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -114,7 +115,7 @@ export function generateFtlFilesCodeFactory(params: {
|
|||||||
$("head").prepend(
|
$("head").prepend(
|
||||||
[
|
[
|
||||||
"<script>",
|
"<script>",
|
||||||
` window.${ftlValuesGlobalName}= ${objectKeys(replaceValueBySearchValue)[0]};`,
|
` window.${nameOfTheGlobal}= ${objectKeys(replaceValueBySearchValue)[0]};`,
|
||||||
"</script>",
|
"</script>",
|
||||||
"",
|
"",
|
||||||
objectKeys(replaceValueBySearchValue)[1]
|
objectKeys(replaceValueBySearchValue)[1]
|
||||||
|
@ -3,7 +3,7 @@ import { join as pathJoin, dirname as pathDirname } from "path";
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { Reflect } from "tsafe/Reflect";
|
import { Reflect } from "tsafe/Reflect";
|
||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { resources_common, lastKeycloakVersionWithAccountV1, accountV1 } from "../../constants";
|
import { resources_common, lastKeycloakVersionWithAccountV1, accountV1ThemeName } from "../../constants";
|
||||||
import { downloadBuiltinKeycloakTheme } from "../../download-builtin-keycloak-theme";
|
import { downloadBuiltinKeycloakTheme } from "../../download-builtin-keycloak-theme";
|
||||||
import { transformCodebase } from "../../tools/transformCodebase";
|
import { transformCodebase } from "../../tools/transformCodebase";
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike
|
|||||||
buildOptions
|
buildOptions
|
||||||
});
|
});
|
||||||
|
|
||||||
const accountV1DirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", accountV1, "account");
|
const accountV1DirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", accountV1ThemeName, "account");
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"),
|
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"),
|
||||||
|
@ -3,7 +3,7 @@ import { join as pathJoin, dirname as pathDirname } from "path";
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { Reflect } from "tsafe/Reflect";
|
import { Reflect } from "tsafe/Reflect";
|
||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { type ThemeType, accountV1 } from "../../constants";
|
import { type ThemeType, accountV1ThemeName } from "../../constants";
|
||||||
import { bringInAccountV1 } from "./bringInAccountV1";
|
import { bringInAccountV1 } from "./bringInAccountV1";
|
||||||
|
|
||||||
export type BuildOptionsLike = {
|
export type BuildOptionsLike = {
|
||||||
@ -102,7 +102,7 @@ export async function generateJavaStackFiles(params: {
|
|||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
"name": accountV1,
|
"name": accountV1ThemeName,
|
||||||
"types": ["account"]
|
"types": ["account"]
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
|
@ -4,7 +4,14 @@ import { join as pathJoin, resolve as pathResolve } from "path";
|
|||||||
import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode";
|
import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode";
|
||||||
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
|
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
|
||||||
import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
|
import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
|
||||||
import { themeTypes, type ThemeType, lastKeycloakVersionWithAccountV1, keycloak_resources, accountV1 } from "../../constants";
|
import {
|
||||||
|
themeTypes,
|
||||||
|
type ThemeType,
|
||||||
|
lastKeycloakVersionWithAccountV1,
|
||||||
|
keycloak_resources,
|
||||||
|
accountV1ThemeName,
|
||||||
|
basenameOfTheKeycloakifyResourcesDir
|
||||||
|
} from "../../constants";
|
||||||
import { isInside } from "../../tools/isInside";
|
import { isInside } from "../../tools/isInside";
|
||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
@ -18,7 +25,6 @@ export type BuildOptionsLike = {
|
|||||||
extraThemeProperties: string[] | undefined;
|
extraThemeProperties: string[] | undefined;
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
loginThemeResourcesFromKeycloakVersion: string;
|
loginThemeResourcesFromKeycloakVersion: string;
|
||||||
urlPathname: string | undefined;
|
|
||||||
keycloakifyBuildDirPath: string;
|
keycloakifyBuildDirPath: string;
|
||||||
reactAppBuildDirPath: string;
|
reactAppBuildDirPath: string;
|
||||||
cacheDirPath: string;
|
cacheDirPath: string;
|
||||||
@ -59,7 +65,7 @@ export async function generateTheme(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
"destDirPath": pathJoin(themeTypeDirPath, "resources", "build"),
|
"destDirPath": pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir),
|
||||||
"srcDirPath": buildOptions.reactAppBuildDirPath,
|
"srcDirPath": buildOptions.reactAppBuildDirPath,
|
||||||
"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/
|
||||||
@ -182,7 +188,7 @@ export async function generateTheme(params: {
|
|||||||
`parent=${(() => {
|
`parent=${(() => {
|
||||||
switch (themeType) {
|
switch (themeType) {
|
||||||
case "account":
|
case "account":
|
||||||
return accountV1;
|
return accountV1ThemeName;
|
||||||
case "login":
|
case "login":
|
||||||
return "keycloak";
|
return "keycloak";
|
||||||
}
|
}
|
||||||
|
79
src/bin/keycloakify/parsedKeycloakifyViteConfig.ts
Normal file
79
src/bin/keycloakify/parsedKeycloakifyViteConfig.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import { assert } from "tsafe";
|
||||||
|
import type { Equals } from "tsafe";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { pathJoin } from "../tools/pathJoin";
|
||||||
|
import { keycloakifyViteConfigJsonBasename } from "../constants";
|
||||||
|
import type { OptionalIfCanBeUndefined } from "../tools/OptionalIfCanBeUndefined";
|
||||||
|
|
||||||
|
export type ParsedKeycloakifyViteConfig = {
|
||||||
|
reactAppRootDirPath: string;
|
||||||
|
publicDirPath: string;
|
||||||
|
assetsDirPath: string;
|
||||||
|
reactAppBuildDirPath: string;
|
||||||
|
urlPathname: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const zParsedKeycloakifyViteConfig = z.object({
|
||||||
|
"reactAppRootDirPath": z.string(),
|
||||||
|
"publicDirPath": z.string(),
|
||||||
|
"assetsDirPath": z.string(),
|
||||||
|
"reactAppBuildDirPath": z.string(),
|
||||||
|
"urlPathname": z.string().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
type Got = ReturnType<(typeof zParsedKeycloakifyViteConfig)["parse"]>;
|
||||||
|
type Expected = OptionalIfCanBeUndefined<ParsedKeycloakifyViteConfig>;
|
||||||
|
|
||||||
|
assert<Equals<Got, Expected>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache: { parsedKeycloakifyViteConfig: ParsedKeycloakifyViteConfig | undefined } | undefined = undefined;
|
||||||
|
|
||||||
|
export function getParsedKeycloakifyViteConfig(params: { keycloakifyBuildDirPath: string }): ParsedKeycloakifyViteConfig | undefined {
|
||||||
|
const { keycloakifyBuildDirPath } = params;
|
||||||
|
|
||||||
|
if (cache !== undefined) {
|
||||||
|
return cache.parsedKeycloakifyViteConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedKeycloakifyViteConfig = (() => {
|
||||||
|
const keycloakifyViteConfigJsonFilePath = pathJoin(keycloakifyBuildDirPath, keycloakifyViteConfigJsonBasename);
|
||||||
|
|
||||||
|
if (!fs.existsSync(keycloakifyViteConfigJsonFilePath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let out: ParsedKeycloakifyViteConfig;
|
||||||
|
|
||||||
|
try {
|
||||||
|
out = JSON.parse(fs.readFileSync(keycloakifyViteConfigJsonFilePath).toString("utf8"));
|
||||||
|
} catch {
|
||||||
|
throw new Error("The output of the Keycloakify Vite plugin is not a valid JSON.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const zodParseReturn = zParsedKeycloakifyViteConfig.parse(out);
|
||||||
|
|
||||||
|
// So that objectKeys from tsafe return the expected result no matter what.
|
||||||
|
Object.keys(zodParseReturn)
|
||||||
|
.filter(key => !(key in out))
|
||||||
|
.forEach(key => {
|
||||||
|
delete (out as any)[key];
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
throw new Error("The output of the Keycloakify Vite plugin do not match the expected schema.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (parsedKeycloakifyViteConfig === undefined && fs.existsSync(pathJoin(keycloakifyBuildDirPath, "vite.config.ts"))) {
|
||||||
|
throw new Error("Make sure you have enabled the Keycloakiy plugin in your vite.config.ts");
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = { parsedKeycloakifyViteConfig };
|
||||||
|
|
||||||
|
return parsedKeycloakifyViteConfig;
|
||||||
|
}
|
@ -10,7 +10,6 @@ export type ParsedPackageJson = {
|
|||||||
homepage?: string;
|
homepage?: string;
|
||||||
keycloakify?: {
|
keycloakify?: {
|
||||||
extraThemeProperties?: string[];
|
extraThemeProperties?: string[];
|
||||||
areAppAndKeycloakServerSharingSameDomain?: boolean;
|
|
||||||
artifactId?: string;
|
artifactId?: string;
|
||||||
groupId?: string;
|
groupId?: string;
|
||||||
doCreateJar?: boolean;
|
doCreateJar?: boolean;
|
||||||
@ -18,7 +17,6 @@ export type ParsedPackageJson = {
|
|||||||
reactAppBuildDirPath?: string;
|
reactAppBuildDirPath?: string;
|
||||||
keycloakifyBuildDirPath?: string;
|
keycloakifyBuildDirPath?: string;
|
||||||
themeName?: string | string[];
|
themeName?: string | string[];
|
||||||
doBuildRetrocompatAccountTheme?: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,22 +27,20 @@ export const zParsedPackageJson = z.object({
|
|||||||
"keycloakify": z
|
"keycloakify": z
|
||||||
.object({
|
.object({
|
||||||
"extraThemeProperties": z.array(z.string()).optional(),
|
"extraThemeProperties": z.array(z.string()).optional(),
|
||||||
"areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
|
|
||||||
"artifactId": z.string().optional(),
|
"artifactId": z.string().optional(),
|
||||||
"groupId": z.string().optional(),
|
"groupId": z.string().optional(),
|
||||||
"doCreateJar": z.boolean().optional(),
|
"doCreateJar": z.boolean().optional(),
|
||||||
"loginThemeResourcesFromKeycloakVersion": z.string().optional(),
|
"loginThemeResourcesFromKeycloakVersion": z.string().optional(),
|
||||||
"reactAppBuildDirPath": z.string().optional(),
|
"reactAppBuildDirPath": z.string().optional(),
|
||||||
"keycloakifyBuildDirPath": z.string().optional(),
|
"keycloakifyBuildDirPath": z.string().optional(),
|
||||||
"themeName": z.union([z.string(), z.array(z.string())]).optional(),
|
"themeName": z.union([z.string(), z.array(z.string())]).optional()
|
||||||
"doBuildRetrocompatAccountTheme": z.boolean().optional()
|
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
|
assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
|
||||||
|
|
||||||
let parsedPackageJson: undefined | ReturnType<(typeof zParsedPackageJson)["parse"]>;
|
let parsedPackageJson: undefined | ParsedPackageJson;
|
||||||
export function getParsedPackageJson(params: { reactAppRootDirPath: string }) {
|
export function getParsedPackageJson(params: { reactAppRootDirPath: string }) {
|
||||||
const { reactAppRootDirPath } = params;
|
const { reactAppRootDirPath } = params;
|
||||||
if (parsedPackageJson) {
|
if (parsedPackageJson) {
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
|
|
||||||
|
|
||||||
export function replaceImportsFromStaticInJsCode(params: { jsCode: string; bundler: "vite" | "webpack" }): { fixedJsCode: string } {
|
|
||||||
const { jsCode } = params;
|
|
||||||
|
|
||||||
const { fixedJsCode } = (() => {
|
|
||||||
switch (params.bundler) {
|
|
||||||
case "vite":
|
|
||||||
return replaceImportsFromStaticInJsCode_vite({ jsCode });
|
|
||||||
case "webpack":
|
|
||||||
return replaceImportsFromStaticInJsCode_webpack({ jsCode });
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
return { fixedJsCode };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replaceImportsFromStaticInJsCode_vite(params: { jsCode: string }): { fixedJsCode: string } {
|
|
||||||
const { jsCode } = params;
|
|
||||||
|
|
||||||
const fixedJsCode = jsCode.replace(
|
|
||||||
/\.viteFileDeps = \[(.*)\]/g,
|
|
||||||
(...args) => `.viteFileDeps = [${args[1]}].map(viteFileDep => window.kcContext.url.resourcesPath.substring(1) + "/build/" + viteFileDep)`
|
|
||||||
);
|
|
||||||
|
|
||||||
return { fixedJsCode };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replaceImportsFromStaticInJsCode_webpack(params: { jsCode: string }): { fixedJsCode: string } {
|
|
||||||
const { jsCode } = params;
|
|
||||||
|
|
||||||
const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
|
|
||||||
new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=(function\\(([a-z]+)\\){return|([a-z]+)=>)"static\\/${language}\\/"`, "g"),
|
|
||||||
(...[, n, u, matchedFunction, eForFunction]) => {
|
|
||||||
const isArrowFunction = matchedFunction.includes("=>");
|
|
||||||
const e = isArrowFunction ? matchedFunction.replace("=>", "").trim() : eForFunction;
|
|
||||||
|
|
||||||
return `
|
|
||||||
${n}[(function(){
|
|
||||||
var pd = Object.getOwnPropertyDescriptor(${n}, "p");
|
|
||||||
if( pd === undefined || pd.configurable ){
|
|
||||||
Object.defineProperty(${n}, "p", {
|
|
||||||
get: function() { return window.${ftlValuesGlobalName}.url.resourcesPath; },
|
|
||||||
set: function() {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return "${u}";
|
|
||||||
})()] = ${isArrowFunction ? `${e} =>` : `function(${e}) { return `} "/build/static/${language}/"`
|
|
||||||
.replace(/\s+/g, " ")
|
|
||||||
.trim();
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const fixedJsCode = jsCode
|
|
||||||
.replace(...getReplaceArgs("js"))
|
|
||||||
.replace(...getReplaceArgs("css"))
|
|
||||||
.replace(/[a-zA-Z]+\.[a-zA-Z]+\+"static\//g, `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`)
|
|
||||||
//TODO: Write a test case for this
|
|
||||||
.replace(
|
|
||||||
/".chunk.css",([a-zA-Z])+=[a-zA-Z]+\.[a-zA-Z]+\+([a-zA-Z]+),/,
|
|
||||||
(...[, group1, group2]) => `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group2},`
|
|
||||||
);
|
|
||||||
|
|
||||||
return { fixedJsCode };
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
|
import { basenameOfTheKeycloakifyResourcesDir } from "../../constants";
|
||||||
|
|
||||||
export type BuildOptionsLike = {
|
export type BuildOptionsLike = {
|
||||||
urlPathname: string | undefined;
|
urlPathname: string | undefined;
|
||||||
@ -45,7 +46,7 @@ export function generateCssCodeToDefineGlobals(params: { cssGlobalsToDefine: Rec
|
|||||||
`--${cssVariableName}:`,
|
`--${cssVariableName}:`,
|
||||||
cssGlobalsToDefine[cssVariableName].replace(
|
cssGlobalsToDefine[cssVariableName].replace(
|
||||||
new RegExp(`url\\(${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`, "g"),
|
new RegExp(`url\\(${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`, "g"),
|
||||||
"url(${url.resourcesPath}/build/"
|
`url(\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/`
|
||||||
)
|
)
|
||||||
].join(" ")
|
].join(" ")
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { BuildOptions } from "../BuildOptions";
|
import type { BuildOptions } from "../BuildOptions";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
|
import { basenameOfTheKeycloakifyResourcesDir } from "../../constants";
|
||||||
|
|
||||||
export type BuildOptionsLike = {
|
export type BuildOptionsLike = {
|
||||||
urlPathname: string | undefined;
|
urlPathname: string | undefined;
|
||||||
@ -16,7 +17,7 @@ export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOp
|
|||||||
buildOptions.urlPathname === undefined
|
buildOptions.urlPathname === undefined
|
||||||
? /url\(["']?\/([^/][^)"']+)["']?\)/g
|
? /url\(["']?\/([^/][^)"']+)["']?\)/g
|
||||||
: new RegExp(`url\\(["']?${buildOptions.urlPathname}([^)"']+)["']?\\)`, "g"),
|
: new RegExp(`url\\(["']?${buildOptions.urlPathname}([^)"']+)["']?\\)`, "g"),
|
||||||
(...[, group]) => `url(\${url.resourcesPath}/build/${group})`
|
(...[, group]) => `url(\${url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/${group})`
|
||||||
);
|
);
|
||||||
|
|
||||||
return { fixedCssCode };
|
return { fixedCssCode };
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./replaceImportsInJsCode";
|
85
src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts
Normal file
85
src/bin/keycloakify/replacers/replaceImportsInJsCode/vite.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../../constants";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import type { BuildOptions } from "../../BuildOptions";
|
||||||
|
import * as nodePath from "path";
|
||||||
|
import { replaceAll } from "../../../tools/String.prototype.replaceAll";
|
||||||
|
|
||||||
|
export type BuildOptionsLike = {
|
||||||
|
reactAppBuildDirPath: string;
|
||||||
|
assetsDirPath: string;
|
||||||
|
urlPathname: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||||
|
|
||||||
|
export function replaceImportsInJsCode_vite(params: {
|
||||||
|
jsCode: string;
|
||||||
|
buildOptions: BuildOptionsLike;
|
||||||
|
basenameOfAssetsFiles: string[];
|
||||||
|
systemType?: "posix" | "win32";
|
||||||
|
}): {
|
||||||
|
fixedJsCode: string;
|
||||||
|
} {
|
||||||
|
const { jsCode, buildOptions, basenameOfAssetsFiles, systemType = nodePath.sep === "/" ? "posix" : "win32" } = params;
|
||||||
|
|
||||||
|
const { relative: pathRelative, sep: pathSep } = nodePath[systemType];
|
||||||
|
|
||||||
|
let fixedJsCode = jsCode;
|
||||||
|
|
||||||
|
replace_base_javacript_import: {
|
||||||
|
if (buildOptions.urlPathname === undefined) {
|
||||||
|
break replace_base_javacript_import;
|
||||||
|
}
|
||||||
|
// Optimization
|
||||||
|
if (!jsCode.includes(buildOptions.urlPathname)) {
|
||||||
|
break replace_base_javacript_import;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace `Hv=function(e){return"/abcde12345/"+e}` by `Hv=function(e){return"/"+e}`
|
||||||
|
fixedJsCode = fixedJsCode.replace(
|
||||||
|
new RegExp(
|
||||||
|
`([\\w\\$][\\w\\d\\$]*)=function\\(([\\w\\$][\\w\\d\\$]*)\\)\\{return"${replaceAll(buildOptions.urlPathname, "/", "\\/")}"\\+\\2\\}`,
|
||||||
|
"g"
|
||||||
|
),
|
||||||
|
(...[, funcName, paramName]) => `${funcName}=function(${paramName}){return"/"+${paramName}}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_javascript_relatives_import_paths: {
|
||||||
|
// Example: "assets/ or "foo/bar/"
|
||||||
|
const staticDir = (() => {
|
||||||
|
let out = pathRelative(buildOptions.reactAppBuildDirPath, buildOptions.assetsDirPath);
|
||||||
|
|
||||||
|
out = replaceAll(out, pathSep, "/") + "/";
|
||||||
|
|
||||||
|
if (out === "/") {
|
||||||
|
throw new Error(`The assetsDirPath must be a subdirectory of reactAppBuildDirPath`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Optimization
|
||||||
|
if (!jsCode.includes(staticDir)) {
|
||||||
|
break replace_javascript_relatives_import_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
basenameOfAssetsFiles
|
||||||
|
.map(basenameOfAssetsFile => `${staticDir}${basenameOfAssetsFile}`)
|
||||||
|
.forEach(relativePathOfAssetFile => {
|
||||||
|
fixedJsCode = replaceAll(
|
||||||
|
fixedJsCode,
|
||||||
|
`"${relativePathOfAssetFile}"`,
|
||||||
|
`(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/${relativePathOfAssetFile}")`
|
||||||
|
);
|
||||||
|
|
||||||
|
fixedJsCode = replaceAll(
|
||||||
|
fixedJsCode,
|
||||||
|
`"${buildOptions.urlPathname ?? "/"}${relativePathOfAssetFile}"`,
|
||||||
|
`(window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/${relativePathOfAssetFile}")`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { fixedJsCode };
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
import { nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../../../constants";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import type { BuildOptions } from "../../BuildOptions";
|
||||||
|
import { relative as pathRelative, sep as pathSep } from "path";
|
||||||
|
import { replaceAll } from "../../../tools/String.prototype.replaceAll";
|
||||||
|
|
||||||
|
export type BuildOptionsLike = {
|
||||||
|
reactAppBuildDirPath: string;
|
||||||
|
assetsDirPath: string;
|
||||||
|
urlPathname: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||||
|
|
||||||
|
export function replaceImportsInJsCode_webpack(params: { jsCode: string; buildOptions: BuildOptionsLike }): { fixedJsCode: string } {
|
||||||
|
const { jsCode, buildOptions } = params;
|
||||||
|
|
||||||
|
let fixedJsCode = jsCode;
|
||||||
|
|
||||||
|
// "__esModule",{value:!0})},n.p="/",function(){if("undefined" -> n.p="/abcde12345/"
|
||||||
|
|
||||||
|
// d={NODE_ENV:"production",PUBLIC_URL:"/abcde12345",WDS_SOCKET_HOST
|
||||||
|
// d={NODE_ENV:"production",PUBLIC_URL:"",WDS_SOCKET_HOST
|
||||||
|
// ->
|
||||||
|
// PUBLIC_URL:"${window.${nameOfTheGlobal}.url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}"`
|
||||||
|
|
||||||
|
if (buildOptions.urlPathname !== undefined) {
|
||||||
|
fixedJsCode = fixedJsCode.replace(
|
||||||
|
new RegExp(`,([a-zA-Z]\\.[a-zA-Z])="${replaceAll(buildOptions.urlPathname, "/", "\\/")}",`, "g"),
|
||||||
|
(...[, assignTo]) => `,${assignTo}="/",`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fixedJsCode = fixedJsCode.replace(
|
||||||
|
new RegExp(
|
||||||
|
`NODE_ENV:"production",PUBLIC_URL:"${
|
||||||
|
buildOptions.urlPathname !== undefined ? replaceAll(buildOptions.urlPathname.slice(0, -1), "/", "\\/") : ""
|
||||||
|
}",`,
|
||||||
|
"g"
|
||||||
|
),
|
||||||
|
`NODE_ENV:"production",PUBLIC_URL: window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}",`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Example: "static/ or "foo/bar/"
|
||||||
|
const staticDir = (() => {
|
||||||
|
let out = pathRelative(buildOptions.reactAppBuildDirPath, buildOptions.assetsDirPath);
|
||||||
|
|
||||||
|
out = replaceAll(out, pathSep, "/") + "/";
|
||||||
|
|
||||||
|
if (out === "/") {
|
||||||
|
throw new Error(`The assetsDirPath must be a subdirectory of reactAppBuildDirPath`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
|
||||||
|
new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=(function\\(([a-z]+)\\){return|([a-z]+)=>)"${staticDir.replace(/\//g, "\\/")}${language}\\/"`, "g"),
|
||||||
|
(...[, n, u, matchedFunction, eForFunction]) => {
|
||||||
|
const isArrowFunction = matchedFunction.includes("=>");
|
||||||
|
const e = isArrowFunction ? matchedFunction.replace("=>", "").trim() : eForFunction;
|
||||||
|
|
||||||
|
return `
|
||||||
|
${n}[(function(){
|
||||||
|
var pd = Object.getOwnPropertyDescriptor(${n}, "p");
|
||||||
|
if( pd === undefined || pd.configurable ){
|
||||||
|
Object.defineProperty(${n}, "p", {
|
||||||
|
get: function() { return window.${nameOfTheGlobal}.url.resourcesPath; },
|
||||||
|
set: function() {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return "${u}";
|
||||||
|
})()] = ${isArrowFunction ? `${e} =>` : `function(${e}) { return `} "/${basenameOfTheKeycloakifyResourcesDir}/${staticDir}${language}/"`
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
fixedJsCode = fixedJsCode
|
||||||
|
.replace(...getReplaceArgs("js"))
|
||||||
|
.replace(...getReplaceArgs("css"))
|
||||||
|
.replace(
|
||||||
|
new RegExp(`[a-zA-Z]+\\.[a-zA-Z]+\\+"${staticDir.replace(/\//g, "\\/")}"`, "g"),
|
||||||
|
`window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/${staticDir}`
|
||||||
|
)
|
||||||
|
//TODO: Write a test case for this
|
||||||
|
.replace(
|
||||||
|
/".chunk.css",([a-zA-Z])+=[a-zA-Z]+\.[a-zA-Z]+\+([a-zA-Z]+),/,
|
||||||
|
(...[, group1, group2]) =>
|
||||||
|
`".chunk.css",${group1} = window.${nameOfTheGlobal}.url.resourcesPath + "/${basenameOfTheKeycloakifyResourcesDir}/" + ${group2},`
|
||||||
|
);
|
||||||
|
|
||||||
|
return { fixedJsCode };
|
||||||
|
}
|
12
src/bin/tools/OptionalIfCanBeUndefined.ts
Normal file
12
src/bin/tools/OptionalIfCanBeUndefined.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
type PropertiesThatCanBeUndefined<T extends Record<string, unknown>> = {
|
||||||
|
[Key in keyof T]: undefined extends T[Key] ? Key : never;
|
||||||
|
}[keyof T];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OptionalIfCanBeUndefined<{ p1: string | undefined; p2: string; }>
|
||||||
|
* is
|
||||||
|
* { p1?: string | undefined; p2: string }
|
||||||
|
*/
|
||||||
|
export type OptionalIfCanBeUndefined<T extends Record<string, unknown>> = {
|
||||||
|
[K in PropertiesThatCanBeUndefined<T>]?: T[K];
|
||||||
|
} & { [K in Exclude<keyof T, PropertiesThatCanBeUndefined<T>>]: T[K] };
|
30
src/bin/tools/String.prototype.replaceAll.ts
Normal file
30
src/bin/tools/String.prototype.replaceAll.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export function replaceAll(string: string, searchValue: string | RegExp, replaceValue: string): string {
|
||||||
|
if ((string as any).replaceAll !== undefined) {
|
||||||
|
return (string as any).replaceAll(searchValue, replaceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the searchValue is a string
|
||||||
|
if (typeof searchValue === "string") {
|
||||||
|
// Escape special characters in the string to be used in a regex
|
||||||
|
var escapedSearchValue = searchValue.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
var regex = new RegExp(escapedSearchValue, "g");
|
||||||
|
|
||||||
|
return string.replace(regex, replaceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the searchValue is a global RegExp, use it directly
|
||||||
|
if (searchValue instanceof RegExp && searchValue.global) {
|
||||||
|
return string.replace(searchValue, replaceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the searchValue is a non-global RegExp, throw an error
|
||||||
|
if (searchValue instanceof RegExp) {
|
||||||
|
throw new TypeError("replaceAll must be called with a global RegExp");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert searchValue to string if it's not a string or RegExp
|
||||||
|
var searchString = String(searchValue);
|
||||||
|
var regexFromString = new RegExp(searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
||||||
|
|
||||||
|
return string.replace(regexFromString, replaceValue);
|
||||||
|
}
|
232
src/vite-plugin/config.json
Normal file
232
src/vite-plugin/config.json
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "vite:build-metadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:watch-package-data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:pre-alias"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alias"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:react-babel",
|
||||||
|
"enforce": "pre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:react-refresh",
|
||||||
|
"enforce": "pre"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:modulepreload-polyfill"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:resolve"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:html-inline-proxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:css"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:esbuild"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:wasm-helper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:worker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:asset"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite-plugin-commonjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "keycloakify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:wasm-fallback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:define"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:css-post"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:build-html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:worker-import-meta-url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:asset-import-meta-url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:force-systemjs-wrap-complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "commonjs",
|
||||||
|
"version": "25.0.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:data-uri"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:dynamic-import-vars"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:import-glob"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:build-import-analysis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:esbuild-transpile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:terser"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:reporter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vite:load-fallback"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimizeDeps": {
|
||||||
|
"disabled": "build",
|
||||||
|
"esbuildOptions": {
|
||||||
|
"preserveSymlinks": false,
|
||||||
|
"jsx": "automatic",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "vite-plugin-commonjs:pre-bundle"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": ["react", "react/jsx-dev-runtime", "react/jsx-runtime"]
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"target": ["es2020", "edge88", "firefox78", "chrome87", "safari14"],
|
||||||
|
"cssTarget": ["es2020", "edge88", "firefox78", "chrome87", "safari14"],
|
||||||
|
"outDir": "dist",
|
||||||
|
"assetsDir": "assets",
|
||||||
|
"assetsInlineLimit": 4096,
|
||||||
|
"cssCodeSplit": true,
|
||||||
|
"sourcemap": false,
|
||||||
|
"rollupOptions": {},
|
||||||
|
"minify": "esbuild",
|
||||||
|
"terserOptions": {},
|
||||||
|
"write": true,
|
||||||
|
"emptyOutDir": null,
|
||||||
|
"copyPublicDir": true,
|
||||||
|
"manifest": false,
|
||||||
|
"lib": false,
|
||||||
|
"ssr": false,
|
||||||
|
"ssrManifest": false,
|
||||||
|
"ssrEmitAssets": false,
|
||||||
|
"reportCompressedSize": true,
|
||||||
|
"chunkSizeWarningLimit": 500,
|
||||||
|
"watch": null,
|
||||||
|
"commonjsOptions": {
|
||||||
|
"include": [{}],
|
||||||
|
"extensions": [".js", ".cjs"]
|
||||||
|
},
|
||||||
|
"dynamicImportVarsOptions": {
|
||||||
|
"warnOnError": true,
|
||||||
|
"exclude": [{}]
|
||||||
|
},
|
||||||
|
"modulePreload": {
|
||||||
|
"polyfill": true
|
||||||
|
},
|
||||||
|
"cssMinify": true
|
||||||
|
},
|
||||||
|
"esbuild": {
|
||||||
|
"jsxDev": false,
|
||||||
|
"jsx": "automatic"
|
||||||
|
},
|
||||||
|
"resolve": {
|
||||||
|
"mainFields": ["browser", "module", "jsnext:main", "jsnext"],
|
||||||
|
"conditions": [],
|
||||||
|
"extensions": [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json"],
|
||||||
|
"dedupe": ["react", "react-dom"],
|
||||||
|
"preserveSymlinks": false,
|
||||||
|
"alias": [
|
||||||
|
{
|
||||||
|
"find": {},
|
||||||
|
"replacement": "/@fs/Users/joseph/github/keycloakify-starter/node_modules/vite/dist/client/env.mjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"find": {},
|
||||||
|
"replacement": "/@fs/Users/joseph/github/keycloakify-starter/node_modules/vite/dist/client/client.mjs"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"configFile": "/Users/joseph/github/keycloakify-starter/vite.config.ts",
|
||||||
|
"configFileDependencies": ["/Users/joseph/github/keycloakify-starter/vite.config.ts"],
|
||||||
|
"inlineConfig": {
|
||||||
|
"optimizeDeps": {},
|
||||||
|
"build": {}
|
||||||
|
},
|
||||||
|
"root": "/Users/joseph/github/keycloakify-starter",
|
||||||
|
"base": "/",
|
||||||
|
"rawBase": "/",
|
||||||
|
"publicDir": "/Users/joseph/github/keycloakify-starter/public",
|
||||||
|
"cacheDir": "/Users/joseph/github/keycloakify-starter/node_modules/.vite",
|
||||||
|
"command": "build",
|
||||||
|
"mode": "production",
|
||||||
|
"ssr": {
|
||||||
|
"target": "node",
|
||||||
|
"optimizeDeps": {
|
||||||
|
"disabled": true,
|
||||||
|
"esbuildOptions": {
|
||||||
|
"preserveSymlinks": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isWorker": false,
|
||||||
|
"mainConfig": null,
|
||||||
|
"isProduction": true,
|
||||||
|
"css": {},
|
||||||
|
"server": {
|
||||||
|
"preTransformRequests": true,
|
||||||
|
"middlewareMode": false,
|
||||||
|
"fs": {
|
||||||
|
"strict": true,
|
||||||
|
"allow": ["/Users/joseph/github/keycloakify-starter"],
|
||||||
|
"deny": [".env", ".env.*", "*.{crt,pem}"],
|
||||||
|
"cachedChecks": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preview": {},
|
||||||
|
"envDir": "/Users/joseph/github/keycloakify-starter",
|
||||||
|
"env": {
|
||||||
|
"BASE_URL": "/",
|
||||||
|
"MODE": "production",
|
||||||
|
"DEV": false,
|
||||||
|
"PROD": true
|
||||||
|
},
|
||||||
|
"logger": {
|
||||||
|
"hasWarned": false
|
||||||
|
},
|
||||||
|
"packageCache": {},
|
||||||
|
"worker": {
|
||||||
|
"format": "iife",
|
||||||
|
"rollupOptions": {}
|
||||||
|
},
|
||||||
|
"appType": "spa",
|
||||||
|
"experimental": {
|
||||||
|
"importGlobRestoreExtension": false,
|
||||||
|
"hmrPartialAccept": false
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,16 @@
|
|||||||
"extends": "../../tsproject.json",
|
"extends": "../../tsproject.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"target": "ES5",
|
"target": "ES2019",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["es2015", "ES2019.Object"],
|
"lib": ["es2019", "es2020.bigint", "es2020.string", "es2020.symbol.wellknown"],
|
||||||
"outDir": "../../dist/vite-plugin",
|
"outDir": "../../dist/vite-plugin",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
}
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,127 @@
|
|||||||
// index.ts
|
import { join as pathJoin, sep as pathSep } from "path";
|
||||||
|
import { getParsedPackageJson } from "../bin/keycloakify/parsedPackageJson";
|
||||||
import type { Plugin, ResolvedConfig } from "vite";
|
import type { Plugin } from "vite";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import { getAbsoluteAndInOsFormatPath } from "../bin/tools/getAbsoluteAndInOsFormatPath";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import { keycloakifyViteConfigJsonBasename, nameOfTheGlobal, basenameOfTheKeycloakifyResourcesDir } from "../bin/constants";
|
||||||
console.log("Hello world!");
|
import type { ParsedKeycloakifyViteConfig } from "../bin/keycloakify/parsedKeycloakifyViteConfig";
|
||||||
|
import { replaceAll } from "../bin/tools/String.prototype.replaceAll";
|
||||||
|
|
||||||
export function keycloakify(): Plugin {
|
export function keycloakify(): Plugin {
|
||||||
let config: ResolvedConfig;
|
let keycloakifyViteConfig: ParsedKeycloakifyViteConfig | undefined = undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name": "keycloakify",
|
"name": "keycloakify",
|
||||||
|
|
||||||
"configResolved": resolvedConfig => {
|
"configResolved": resolvedConfig => {
|
||||||
// Store the resolved config
|
const reactAppRootDirPath = resolvedConfig.root;
|
||||||
config = resolvedConfig;
|
const reactAppBuildDirPath = pathJoin(reactAppRootDirPath, resolvedConfig.build.outDir);
|
||||||
|
|
||||||
console.log("========> configResolved", config);
|
keycloakifyViteConfig = {
|
||||||
|
reactAppRootDirPath,
|
||||||
|
"publicDirPath": resolvedConfig.publicDir,
|
||||||
|
"assetsDirPath": pathJoin(reactAppBuildDirPath, resolvedConfig.build.assetsDir),
|
||||||
|
reactAppBuildDirPath,
|
||||||
|
"urlPathname": (() => {
|
||||||
|
let out = resolvedConfig.env.BASE_URL;
|
||||||
|
|
||||||
fs.writeFileSync("/Users/joseph/github/keycloakify-starter/log.txt", Buffer.from("Hello World", "utf8"));
|
if (out === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.startsWith("/")) {
|
||||||
|
out = "/" + out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.endsWith("/")) {
|
||||||
|
out += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
})()
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsedPackageJson = getParsedPackageJson({ reactAppRootDirPath });
|
||||||
|
|
||||||
|
if (parsedPackageJson.keycloakify?.reactAppBuildDirPath !== undefined) {
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
"Please do not use the keycloakify.reactAppBuildDirPath option in your package.json.",
|
||||||
|
"In Vite setups it's inferred automatically from the vite config."
|
||||||
|
].join(" ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const keycloakifyBuildDirPath = (() => {
|
||||||
|
const { keycloakifyBuildDirPath } = parsedPackageJson.keycloakify ?? {};
|
||||||
|
|
||||||
|
if (keycloakifyBuildDirPath !== undefined) {
|
||||||
|
return getAbsoluteAndInOsFormatPath({
|
||||||
|
"pathIsh": keycloakifyBuildDirPath,
|
||||||
|
"cwd": reactAppRootDirPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathJoin(reactAppRootDirPath, "build_keycloak");
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!fs.existsSync(keycloakifyBuildDirPath)) {
|
||||||
|
fs.mkdirSync(keycloakifyBuildDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(keycloakifyBuildDirPath, keycloakifyViteConfigJsonBasename),
|
||||||
|
Buffer.from(JSON.stringify(keycloakifyViteConfig, null, 2), "utf8")
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
"transform": (code, id) => {
|
||||||
|
assert(keycloakifyViteConfig !== undefined);
|
||||||
|
|
||||||
"buildStart": () => {
|
let transformedCode: string | undefined = undefined;
|
||||||
console.log("Public Directory:", config.publicDir); // Path to the public directory
|
|
||||||
console.log("Dist Directory:", config.build.outDir); // Path to the dist directory
|
replace_import_meta_env_base_url_in_source_code: {
|
||||||
console.log("Assets Directory:", config.build.assetsDir); // Path to the assets directory within outDir
|
{
|
||||||
|
const isWithinSourceDirectory = id.startsWith(pathJoin(keycloakifyViteConfig.publicDirPath, "src") + pathSep);
|
||||||
|
|
||||||
|
if (!isWithinSourceDirectory) {
|
||||||
|
break replace_import_meta_env_base_url_in_source_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isJavascriptFile = id.endsWith(".js") || id.endsWith(".jsx");
|
||||||
|
|
||||||
|
{
|
||||||
|
const isTypeScriptFile = id.endsWith(".ts") || id.endsWith(".tsx");
|
||||||
|
|
||||||
|
if (!isTypeScriptFile && !isJavascriptFile) {
|
||||||
|
break replace_import_meta_env_base_url_in_source_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const windowToken = isJavascriptFile ? "window" : "(window as any)";
|
||||||
|
|
||||||
|
if (transformedCode === undefined) {
|
||||||
|
transformedCode = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
transformedCode = replaceAll(
|
||||||
|
transformedCode,
|
||||||
|
"import.meta.env.BASE_URL",
|
||||||
|
[
|
||||||
|
`(`,
|
||||||
|
`(${windowToken}.${nameOfTheGlobal} === undefined || import.meta.env.MODE === "development") ?`,
|
||||||
|
` "${keycloakifyViteConfig.urlPathname ?? "/"}" :`,
|
||||||
|
` \`\${${windowToken}.${nameOfTheGlobal}.url.resourcesPath}/${basenameOfTheKeycloakifyResourcesDir}/\``,
|
||||||
|
`)`
|
||||||
|
].join("")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transformedCode !== undefined) {
|
||||||
|
return {
|
||||||
|
"code": transformedCode
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... other hooks
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,56 @@
|
|||||||
import { replaceImportsFromStaticInJsCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode";
|
import { replaceImportsInJsCode_vite } from "keycloakify/bin/keycloakify/replacers/replaceImportsInJsCode/vite";
|
||||||
import { generateCssCodeToDefineGlobals, replaceImportsInCssCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsInCssCode";
|
import { generateCssCodeToDefineGlobals, replaceImportsInCssCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsInCssCode";
|
||||||
import { replaceImportsInInlineCssCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsInInlineCssCode";
|
import { replaceImportsInInlineCssCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsInInlineCssCode";
|
||||||
import { same } from "evt/tools/inDepth/same";
|
import { same } from "evt/tools/inDepth/same";
|
||||||
import { expect, it, describe } from "vitest";
|
import { expect, it, describe } from "vitest";
|
||||||
|
|
||||||
import { isSameCode } from "../tools/isSameCode";
|
import { isSameCode } from "../tools/isSameCode";
|
||||||
|
import { basenameOfTheKeycloakifyResourcesDir, nameOfTheGlobal } from "keycloakify/bin/constants";
|
||||||
|
|
||||||
describe("bin/js-transforms", () => {
|
describe("bin/js-transforms - vite", () => {
|
||||||
// Vite
|
it("replaceImportsInJsCode_vite - 1", () => {
|
||||||
{
|
const before = `Uv="modulepreload",`;
|
||||||
|
const after = `,Wc={},`;
|
||||||
|
const jsCodeUntransformed = `${before}Hv=function(e){return"/foo-bar-baz/"+e}${after}`;
|
||||||
|
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode_vite({
|
||||||
|
"jsCode": jsCodeUntransformed,
|
||||||
|
"basenameOfAssetsFiles": [],
|
||||||
|
"buildOptions": {
|
||||||
|
"reactAppBuildDirPath": "/Users/someone/github/keycloakify-starter/dist/",
|
||||||
|
"assetsDirPath": "/Users/someone/github/keycloakify-starter/dist/assets/",
|
||||||
|
"urlPathname": "/foo-bar-baz/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedJsCodeExpected = `${before}Hv=function(e){return"/"+e}${after}`;
|
||||||
|
|
||||||
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("replaceImportsInJsCode_vite - 2", () => {
|
||||||
|
const before = `Uv="modulepreload",`;
|
||||||
|
const after = `,Wc={},`;
|
||||||
|
const jsCodeUntransformed = `${before}Hv=function(e){return"/foo/bar/baz/"+e}${after}`;
|
||||||
|
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode_vite({
|
||||||
|
"jsCode": jsCodeUntransformed,
|
||||||
|
"basenameOfAssetsFiles": [],
|
||||||
|
"buildOptions": {
|
||||||
|
"reactAppBuildDirPath": "/Users/someone/github/keycloakify-starter/dist/",
|
||||||
|
"assetsDirPath": "/Users/someone/github/keycloakify-starter/dist/assets/",
|
||||||
|
"urlPathname": "/foo/bar/baz/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedJsCodeExpected = `${before}Hv=function(e){return"/"+e}${after}`;
|
||||||
|
|
||||||
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("replaceImportsInJsCode_vite - 3", () => {
|
||||||
const jsCodeUntransformed = `
|
const jsCodeUntransformed = `
|
||||||
|
S="/assets/keycloakify-logo-mqjydaoZ.png",H=(()=>{
|
||||||
|
|
||||||
function __vite__mapDeps(indexes) {
|
function __vite__mapDeps(indexes) {
|
||||||
if (!__vite__mapDeps.viteFileDeps) {
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
__vite__mapDeps.viteFileDeps = ["assets/Login-dJpPRzM4.js", "assets/index-XwzrZ5Gu.js"]
|
__vite__mapDeps.viteFileDeps = ["assets/Login-dJpPRzM4.js", "assets/index-XwzrZ5Gu.js"]
|
||||||
@ -17,28 +58,157 @@ describe("bin/js-transforms", () => {
|
|||||||
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
it("Correctly replace import path in Vite dist/static/xxx.js files", () => {
|
|
||||||
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
for (const { reactAppBuildDirPath, assetsDirPath, systemType } of [
|
||||||
|
{
|
||||||
|
"systemType": "posix",
|
||||||
|
"reactAppBuildDirPath": "/Users/someone/github/keycloakify-starter/dist",
|
||||||
|
"assetsDirPath": "/Users/someone/github/keycloakify-starter/dist/assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"systemType": "win32",
|
||||||
|
"reactAppBuildDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist",
|
||||||
|
"assetsDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist\\assets"
|
||||||
|
}
|
||||||
|
] as const) {
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode_vite({
|
||||||
"jsCode": jsCodeUntransformed,
|
"jsCode": jsCodeUntransformed,
|
||||||
"bundler": "vite"
|
"basenameOfAssetsFiles": ["Login-dJpPRzM4.js", "index-XwzrZ5Gu.js"],
|
||||||
|
"buildOptions": {
|
||||||
|
reactAppBuildDirPath,
|
||||||
|
assetsDirPath,
|
||||||
|
"urlPathname": undefined
|
||||||
|
},
|
||||||
|
systemType
|
||||||
});
|
});
|
||||||
|
|
||||||
const fixedJsCodeExpected = `
|
const fixedJsCodeExpected = `
|
||||||
function __vite__mapDeps(indexes) {
|
S=(window.${nameOfTheGlobal}.url + "/${basenameOfTheKeycloakifyResourcesDir}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||||
if (!__vite__mapDeps.viteFileDeps) {
|
|
||||||
__vite__mapDeps.viteFileDeps = ["assets/Login-dJpPRzM4.js", "assets/index-XwzrZ5Gu.js"].map(viteFileDep => window.kcContext.url.resourcesPath.substring(1) + "/build/" + viteFileDep)
|
function __vite__mapDeps(indexes) {
|
||||||
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
|
__vite__mapDeps.viteFileDeps = [
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/assets/Login-dJpPRzM4.js)",
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/assets/index-XwzrZ5Gu.js)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
}
|
}
|
||||||
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
`;
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Webpack
|
it("replaceImportsInJsCode_vite - 4", () => {
|
||||||
{
|
|
||||||
const jsCodeUntransformed = `
|
const jsCodeUntransformed = `
|
||||||
|
S="/assets/keycloakify-logo-mqjydaoZ.png",H=(()=>{
|
||||||
|
|
||||||
|
function __vite__mapDeps(indexes) {
|
||||||
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
|
__vite__mapDeps.viteFileDeps = ["assets/Login-dJpPRzM4.js", "assets/index-XwzrZ5Gu.js"]
|
||||||
|
}
|
||||||
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
for (const { reactAppBuildDirPath, assetsDirPath, systemType } of [
|
||||||
|
{
|
||||||
|
"systemType": "posix",
|
||||||
|
"reactAppBuildDirPath": "/Users/someone/github/keycloakify-starter/dist",
|
||||||
|
"assetsDirPath": "/Users/someone/github/keycloakify-starter/dist/foo/bar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"systemType": "win32",
|
||||||
|
"reactAppBuildDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist",
|
||||||
|
"assetsDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist\\foo\\bar"
|
||||||
|
}
|
||||||
|
] as const) {
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode_vite({
|
||||||
|
"jsCode": jsCodeUntransformed,
|
||||||
|
"basenameOfAssetsFiles": ["Login-dJpPRzM4.js", "index-XwzrZ5Gu.js"],
|
||||||
|
"buildOptions": {
|
||||||
|
reactAppBuildDirPath,
|
||||||
|
assetsDirPath,
|
||||||
|
"urlPathname": undefined
|
||||||
|
},
|
||||||
|
systemType
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedJsCodeExpected = `
|
||||||
|
S=(window.${nameOfTheGlobal}.url + "/${basenameOfTheKeycloakifyResourcesDir}/foo/bar/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||||
|
|
||||||
|
function __vite__mapDeps(indexes) {
|
||||||
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
|
__vite__mapDeps.viteFileDeps = [
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/foo/bar/Login-dJpPRzM4.js)",
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/foo/bar/index-XwzrZ5Gu.js)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("replaceImportsInJsCode_vite - 5", () => {
|
||||||
|
const jsCodeUntransformed = `
|
||||||
|
S="/foo-bar-baz/assets/keycloakify-logo-mqjydaoZ.png",H=(()=>{
|
||||||
|
|
||||||
|
function __vite__mapDeps(indexes) {
|
||||||
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
|
__vite__mapDeps.viteFileDeps = ["assets/Login-dJpPRzM4.js", "assets/index-XwzrZ5Gu.js"]
|
||||||
|
}
|
||||||
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
for (const { reactAppBuildDirPath, assetsDirPath, systemType } of [
|
||||||
|
{
|
||||||
|
"systemType": "posix",
|
||||||
|
"reactAppBuildDirPath": "/Users/someone/github/keycloakify-starter/dist",
|
||||||
|
"assetsDirPath": "/Users/someone/github/keycloakify-starter/dist/assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"systemType": "win32",
|
||||||
|
"reactAppBuildDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist",
|
||||||
|
"assetsDirPath": "C:\\\\Users\\someone\\github\\keycloakify-starter\\dist\\assets"
|
||||||
|
}
|
||||||
|
] as const) {
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode_vite({
|
||||||
|
"jsCode": jsCodeUntransformed,
|
||||||
|
"basenameOfAssetsFiles": ["Login-dJpPRzM4.js", "index-XwzrZ5Gu.js"],
|
||||||
|
"buildOptions": {
|
||||||
|
reactAppBuildDirPath,
|
||||||
|
assetsDirPath,
|
||||||
|
"urlPathname": "/foo-bar-baz/"
|
||||||
|
},
|
||||||
|
systemType
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixedJsCodeExpected = `
|
||||||
|
S=(window.${nameOfTheGlobal}.url + "/${basenameOfTheKeycloakifyResourcesDir}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||||
|
|
||||||
|
function __vite__mapDeps(indexes) {
|
||||||
|
if (!__vite__mapDeps.viteFileDeps) {
|
||||||
|
__vite__mapDeps.viteFileDeps = [
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/assets/Login-dJpPRzM4.js)",
|
||||||
|
(window.${nameOfTheGlobal}.url.resourcesPath.substring(1) + "/${basenameOfTheKeycloakifyResourcesDir}/assets/index-XwzrZ5Gu.js)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("bin/js-transforms - webpack", () => {
|
||||||
|
const jsCodeUntransformed = `
|
||||||
function f() {
|
function f() {
|
||||||
return a.p+"static/js/" + ({}[e] || e) + "." + {
|
return a.p+"static/js/" + ({}[e] || e) + "." + {
|
||||||
3: "0664cdc0"
|
3: "0664cdc0"
|
||||||
@ -68,13 +238,13 @@ describe("bin/js-transforms", () => {
|
|||||||
|
|
||||||
t.miniCssF=e=>"static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
t.miniCssF=e=>"static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
||||||
`;
|
`;
|
||||||
it("Correctly replace import path in Webpack build/static/js/xxx.js files", () => {
|
it("Correctly replace import path in Webpack build/static/js/xxx.js files", () => {
|
||||||
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
|
||||||
"jsCode": jsCodeUntransformed,
|
"jsCode": jsCodeUntransformed,
|
||||||
"bundler": "webpack"
|
"bundler": "webpack"
|
||||||
});
|
});
|
||||||
|
|
||||||
const fixedJsCodeExpected = `
|
const fixedJsCodeExpected = `
|
||||||
function f() {
|
function f() {
|
||||||
return window.kcContext.url.resourcesPath + "/build/static/js/" + ({}[e] || e) + "." + {
|
return window.kcContext.url.resourcesPath + "/build/static/js/" + ({}[e] || e) + "." + {
|
||||||
3: "0664cdc0"
|
3: "0664cdc0"
|
||||||
@ -143,9 +313,8 @@ describe("bin/js-transforms", () => {
|
|||||||
})()] = e => "/build/static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
})()] = e => "/build/static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("bin/css-transforms", () => {
|
describe("bin/css-transforms", () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user