Frontend Quick Start
This guide shows how to integrate granit-front into an existing Vite/React
application. By the end, the application will have a structured logger, an
authenticated HTTP client, and a typed Keycloak authentication context.
Target architecture
Section titled “Target architecture”flowchart LR
APP[Vite/React App]
APP --> AUTH["@granit/react-authentication"]
APP --> API["@granit/api-client"]
APP --> UTILS["@granit/utils"]
APP --> LOGGER["@granit/logger"]
AUTH --> API
Prerequisites
Section titled “Prerequisites”- Node.js 24+
- pnpm 10+
- A running Keycloak instance (or any OIDC provider)
- Familiarity with TypeScript and React
Integration steps
Section titled “Integration steps”-
Clone the repository
Clone
granit-frontnext to the consuming application:workspace/├── granit-front/ ← framework monorepo└── my-app/ ← your Vite/React applicationTerminal window cd workspacegit clone <repository-url> granit-frontcd granit-front && pnpm install -
Declare dependencies
In the application’s
package.json, add packages using thelink:protocol:{"dependencies": {"@granit/logger": "link:../granit-front/packages/@granit/logger","@granit/utils": "link:../granit-front/packages/@granit/utils","@granit/api-client": "link:../granit-front/packages/@granit/api-client","@granit/react-authentication": "link:../granit-front/packages/@granit/react-authentication"}}Then install peer dependencies:
Terminal window pnpm add axios clsx tailwind-merge date-fns keycloak-js -
Configure Vite and TypeScript
Add aliases so Vite resolves TypeScript sources directly (source-direct pattern):
import path from 'path';import { defineConfig } from 'vite';const GRANIT = path.resolve(__dirname, '../granit-front/packages/@granit');export default defineConfig({resolve: {alias: {'@granit/logger': path.join(GRANIT, 'logger/src/index.ts'),'@granit/utils': path.join(GRANIT, 'utils/src/index.ts'),'@granit/api-client': path.join(GRANIT, 'api-client/src/index.ts'),'@granit/react-authentication': path.join(GRANIT, 'react-authentication/src/index.ts'),},},});Add matching
pathsin every tsconfig (tsconfig.app.json,tsconfig.test.json,tsconfig.storybook.json):{"compilerOptions": {"paths": {"@granit/logger": ["../granit-front/packages/@granit/logger/src/index.ts"],"@granit/utils": ["../granit-front/packages/@granit/utils/src/index.ts"],"@granit/api-client": ["../granit-front/packages/@granit/api-client/src/index.ts"],"@granit/react-authentication": ["../granit-front/packages/@granit/react-authentication/src/index.ts"]}}} -
Create the logger and API client
import { createLogger } from '@granit/logger';export const logger = createLogger('[MyApp]');import { createApiClient } from '@granit/api-client';export const api = createApiClient({baseURL: import.meta.env.VITE_API_URL,timeout: 15_000,});The Bearer token is automatically injected by
@granit/react-authenticationonce configured in the next step. -
Configure Keycloak authentication
Create the authentication context and provider:
src/auth/auth-context.ts import { createAuthContext } from '@granit/react-authentication';import type { BaseAuthContextType } from '@granit/authentication';interface AuthContextType extends BaseAuthContextType {// Add application-specific fields if needed}export const { AuthContext, useAuth } = createAuthContext<AuthContextType>();src/auth/AuthProvider.tsx import { useKeycloakInit } from '@granit/react-authentication';import { AuthContext } from './auth-context';export function AuthProvider({ children }: { children: React.ReactNode }) {const auth = useKeycloakInit({url: import.meta.env.VITE_KEYCLOAK_URL,realm: import.meta.env.VITE_KEYCLOAK_REALM,clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,});if (auth.loading) return <div>Loading…</div>;return (<AuthContext.Provider value={auth}>{children}</AuthContext.Provider>);}Wrap the application:
src/main.tsx import { AuthProvider } from './auth/AuthProvider';import { App } from './App';createRoot(document.getElementById('root')!).render(<AuthProvider><App /></AuthProvider>);
Verify the setup
Section titled “Verify the setup”# Verify granit-front is healthycd ../granit-frontpnpm lint && pnpm tsc && pnpm test run
# Start the applicationcd ../my-apppnpm devUsage example
Section titled “Usage example”import { useAuth } from './auth/auth-context';import { logger } from '@/lib/logger';
function UserProfile() { const { user, logout } = useAuth();
logger.info('Profile displayed', { userId: user?.sub });
return ( <div> <p>{user?.name}</p> <button onClick={logout}>Sign out</button> </div> );}How source resolution works
Section titled “How source resolution works”import { useQueryEndpoint } from '@granit/querying' → Vite alias → packages/@granit/querying/src/index.ts → TypeScript source → transpiled on the fly by Vite → no dist/, no intermediate buildThis source-direct approach provides instant HMR on framework code, zero build watch overhead, direct source maps, and frictionless refactoring across framework and application boundaries.
See also
Section titled “See also”- Frontend SDK Overview — package reference
- Frontend Testing — test conventions and patterns
- Frontend Troubleshooting — common issues and solutions