I want to make some changes to the admin-ui of Keycloak and make it the way I want. But I can't run the project in development mode. Is there a way that I can run the admin-ui project in development mode so that I can see it immediately after making the changes. When I use pnpm run dev, I get a 404 error on localhost:5174.
In keycloak-26.4.2/bin I run backend as dev by this command: kc.bat start-dev. Then keycloak backend will run. Next in keycloak-main/js/apps/admin-ui I run pnpm run dev:
VITE v7.1.10 ready in 2182 ms
➜ Local: http://localhost:5174/
➜ Network: http://192.168.61.12:5174/
But keycloak is not accessible on localhost:5174. The request:
Request URL http://localhost:5174/
Request Method GET
Status Code 404 Not Found Remote Address [::1]:5174
Referrer Policy strict-origin-when-cross-origin
Keycloak v26.4.2 and Node v22.21.0
admin-ui/package.json:
{
"name": "@keycloak/keycloak-admin-ui",
"version": "999.0.0-SNAPSHOT",
"type": "module",
"main": "lib/keycloak-admin-ui.js",
"types": "./lib/keycloak-admin-ui.d.ts",
"exports": {
".": {
"import": "./lib/keycloak-admin-ui.js",
"types": "./lib/keycloak-admin-ui.d.ts"
}
},
"files": [
"lib"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"dev": "wireit",
"build": "wireit",
"build-lib": "wireit",
"preview": "wireit",
"lint": "wireit",
"test": "wireit",
"test:integration": "wireit"
},
"wireit": {
"dev": {
"command": "vite --host",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
]
},
"preview": {
"command": "vite preview",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
]
},
"build": {
"command": "vite build",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
],
"files": [
"public",
"src",
"tsconfig.json",
"vite.config.ts"
],
"output": [
"target/classes/theme/keycloak.v2/admin/resources"
]
},
"build-lib": {
"command": "cross-env LIB=true vite build",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
]
},
"lint": {
"command": "eslint .",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
]
},
"test": {
"command": "vitest",
"dependencies": [
"../../libs/ui-shared:build",
"../../libs/keycloak-admin-client:build"
]
},
"test:integration": {
"command": "playwright test",
"dependencies": [
"../../libs/keycloak-admin-client:build"
]
}
},
"dependencies": {
"@dagrejs/dagre": "^1.1.5",
"@keycloak/keycloak-admin-client": "workspace:*",
"@keycloak/keycloak-ui-shared": "workspace:*",
"@patternfly/patternfly": "^5.4.2",
"@patternfly/react-core": "^5.4.14",
"@patternfly/react-icons": "^5.4.2",
"@patternfly/react-styles": "^5.4.1",
"@patternfly/react-table": "^5.4.16",
"@uiw/react-textarea-code-editor": "^3.1.1",
"admin-ui": "file:",
"file-saver": "^2.0.5",
"flat": "^6.0.1",
"i18next": "^25.6.0",
"i18next-fetch-backend": "^6.0.0",
"jszip": "^3.10.1",
"keycloak-js": "^26.2.0",
"lodash-es": "^4.17.21",
"p-debounce": "^5.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.63.0",
"react-i18next": "^16.0.1",
"react-router-dom": "^6.30.1",
"reactflow": "^11.11.4",
"use-react-router-breadcrumbs": "^4.0.1"
},
"devDependencies": {
"@axe-core/playwright": "^4.10.2",
"@playwright/test": "^1.56.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@types/dagre": "^0.7.53",
"@types/file-saver": "^2.0.7",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react-swc": "^4.1.0",
"cross-env": "^10.1.0",
"jsdom": "^27.0.0",
"lightningcss": "^1.30.2",
"properties-file": "^3.6.1",
"ts-node": "^10.9.2",
"uuid": "^13.0.0",
"vite": "^7.1.10",
"vite-plugin-checker": "^0.11.0",
"vite-plugin-dts": "^4.5.4",
"vitest": "^3.2.4"
},
"author": {
"name": "Red Hat, Inc.",
"url": "https://www.keycloak.org/"
},
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/keycloak/keycloak.git",
"directory": "js/apps/admin-ui"
},
"homepage": "https://www.keycloak.org/"
}
admin-ui/vite-config.ts:
import react from "@vitejs/plugin-react-swc";
import { readFileSync } from "node:fs";
import path from "path";
import { getProperties } from "properties-file";
import { defineConfig, loadEnv } from "vite";
import { checker } from "vite-plugin-checker";
import dts from "vite-plugin-dts";
import { configDefaults } from "vitest/config";
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
const external = ["react", "react/jsx-runtime", "react-dom"];
const plugins = [
react(),
checker({ typescript: true }),
{
name: "message-bundle-transformer",
resolveId(source) {
if (source === "message-bundle") {
return source;
}
return null;
},
load(id) {
if (id === "message-bundle") {
let properties = {};
if (process.env.NODE_ENV === "development") {
properties = getProperties(
readFileSync(
"./maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties",
),
);
}
return {
code: `export default ${JSON.stringify(properties)};`,
};
}
return null;
},
},
];
const input = env.LIB ? undefined : "src/main.tsx";
if (env.LIB) {
external.push("react-router-dom");
external.push("react-i18next");
plugins.push(dts({ insertTypesEntry: true }));
}
const lib = env.LIB
? {
outDir: "lib",
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
formats: ["es"],
},
}
: {
outDir: "target/classes/theme/keycloak.v2/admin/resources",
external: ["src/index.ts"],
};
return {
base: "",
server: {
origin: "http://localhost:5174",
port: 5174,
},
build: {
...lib,
sourcemap: true,
target: "esnext",
modulePreload: false,
cssMinify: "lightningcss",
manifest: true,
rollupOptions: {
input,
external,
},
},
plugins,
test: {
watch: false,
environment: "jsdom",
exclude: [...configDefaults.exclude, "./test/**"],
server: {
deps: {
inline: [/@patternfly\/.*/],
},
},
},
};
});
What is the way I can run the react admin-ui on the dev mode? Thanks a lot.