React core
Skill LaoitdevOpen/laoitdev-skills/skills/frontend/react-core
How to implement the src/core folder — app-level infrastructure shared by every feature. Covers folder structure, Axios config with auth interceptors, QueryClient, router config, i18n setup, theme, AuthContext, SnackbarContext, ThemeContext, type-safe storage utility, Zustand layout store, and main.tsx provider composition. Use whenever setting up a new project, adding a new core concern, or modifying any of these foundational files.From its SKILL.md
npx -y skills add LaoitdevOpen/laoitdev-skills --skill react-coreAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.3 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Core Folder
src/core/ contains app-level infrastructure that every feature depends on but no single feature owns. Nothing in core/ should import from features/.
Core Invariants (always enforced — never violate)
- Nothing in
core/may import fromfeatures/.
References
Read the relevant file when you need it:
references/contexts.md— full implementation ofThemeContext,AuthContext,SnackbarContextreferences/storage-store.md—storageutility,STORAGE_KEYS,useLayoutStore(Zustand)
Folder Structure
src/core/
├── api/
│ └── axios.config.ts # Axios instance — auth header + 401 handling
├── config/
│ ├── i18n.config.ts # i18next init — import side-effect in main.tsx
│ ├── query-client.config.ts # QueryClient singleton with default options
│ └── theme.config.ts # createAppTheme(mode) factory
├── router/
│ ├── index.tsx # createRouter + Register declaration
│ └── routeTree.gen.ts # auto-generated — never edit manually
├── context/
│ ├── AuthContext.tsx # user state, login(), logout()
│ ├── SnackbarContext.tsx # showSuccess/Error/Warning/Info
│ └── ThemeContext.tsx # ThemeProvider + MUI + dayjs
├── store/
│ └── layout.store.ts # Zustand — sidebar open/close (persisted)
└── utils/
└── storage.ts # Type-safe localStorage + STORAGE_KEYS
core/api/axios.config.ts
Single Axios instance. Attaches the Bearer token on every request; handles global 401 by clearing the token and redirecting to /login.
import axios from 'axios'
import { storage, STORAGE_KEYS } from '@/core/utils/storage'
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 30000,
headers: { 'Content-Type': 'application/json' },
})
axiosInstance.interceptors.request.use((config) => {
const token = storage.get<string>(STORAGE_KEYS.ACCESS_TOKEN)
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
const isLoginRequest = error.config?.url?.includes('/auth/login')
const isOnLoginPage = window.location.pathname.includes('/login')
if (error.response?.status === 401 && !isLoginRequest && !isOnLoginPage) {
storage.remove(STORAGE_KEYS.ACCESS_TOKEN)
window.location.href = '/login'
}
return Promise.reject(error)
}
)
export default axiosInstance
All feature services: import axiosInstance from '@/core/api/axios.config'
core/config/query-client.config.ts
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 min
gcTime: 1000 * 60 * 10, // 10 min
retry: 1,
refetchOnWindowFocus: false,
},
},
})
core/router/index.tsx
Route tree generation config → see tanstack-router skill.
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
import { queryClient } from '@/core/config/query-client.config'
import type { RouterContext } from '@/routes/__root'
export function createRouter() {
return createTanStackRouter({
routeTree,
defaultPreload: 'intent',
scrollRestoration: true,
context: {
queryClient,
user: undefined,
} as RouterContext,
})
}
declare module '@tanstack/react-router' {
interface Register { router: ReturnType<typeof createRouter> }
}
core/config/i18n.config.ts
Import as a side-effect in main.tsx — never import the default export unless you need the i18n instance.
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import enTranslation from '@/locales/en.json'
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: { en: { translation: enTranslation } },
lng: 'en',
fallbackLng: 'en',
defaultNS: 'translation',
interpolation: { escapeValue: false },
detection: { order: ['localStorage', 'navigator'], caches: ['localStorage'] },
debug: import.meta.env.DEV,
})
export default i18n
Add languages by adding keys under resources and JSON files under src/locales/.
main.tsx — Provider Composition
Order matters — outer providers must not depend on inner ones.
import { StrictMode, Suspense } from 'react'
import { createRoot } from 'react-dom/client'
import { QueryClientProvider } from '@tanstack/react-query'
import { RouterProvider } from '@tanstack/react-router'
import { ThemeProvider } from '@/core/context/ThemeContext'
import { AuthProvider } from '@/core/context/AuthContext'
import { SnackbarProvider } from '@/core/context/SnackbarContext'
import { queryClient } from '@/core/config/query-client.config'
import { createRouter } from '@/core/router'
import '@/core/config/i18n.config' // side-effect — init i18next before first render
import './index.css'
const router = createRouter()
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={queryClient}> {/* outermost — loaders + AuthProvider need it */}
<ThemeProvider> {/* MUI theme always available */}
<AuthProvider> {/* inside Theme, outside Snackbar */}
<SnackbarProvider> {/* route components can call useSnackbar() */}
<Suspense fallback={null}>
<RouterProvider router={router} />
</Suspense>
</SnackbarProvider>
</AuthProvider>
</ThemeProvider>
</QueryClientProvider>
</StrictMode>,
)
What ships with it: 2 files
7.8 KB alongside SKILL.md
references/
- contexts.md5.9 KB
- storage-store.md1.9 KB