Documented issues and their solutions to prevent recurring mistakes.
Problem: When users refresh the page with isLayoutLarge preference saved, the layout would flash from constrained (max-w-7xl) to full-width before React hydrates.
Root Cause: React state initialization happens after prerendered HTML renders, causing a visual mismatch.
Solution:
- Inline script in prerendered HTML reads localStorage before React loads
- Script adds
layout-largeclass to html element immediately - CSS rule overrides
max-w-7xlwithmax-width: none !importantwhen class is present - React state syncs with the already-correct DOM
Files Involved:
vite.config.ts- Inline script injection (lines 152-164)src/index.css- CSS override (lines 58-62)src/contexts/AppContextProvider.tsx- State initialization and sync
Key Learning: For persistent UI state, always apply changes at the DOM/CSS level before React hydrates.
Problem: JSON Resume Reference type has optional fields, but ProfileData Reference requires all fields, causing TypeScript errors.
Root Cause: Different interface definitions for the same data concept.
Solution:
- Define
Referenceinsrc/types/profile.tswith required fields - Define
Referenceinsrc/types/json-resume.tswith optional fields - Use type assertion when mapping:
as Referencewith fallback values (|| "")
Files Involved:
src/types/profile.ts- Required fields definitionsrc/types/json-resume.ts- Optional fields definitionsrc/hooks/useJSONResumeAdapter.ts- Type assertion during mapping
Key Learning: When adapting between schemas, use type assertions with fallback values rather than trying to force type compatibility.
Problem: Adding a translation key to en.json but forgetting to add it to it.json, fr.json, es.json, ar.json causes missing translation errors in other languages.
Root Cause: Manual process with 5 separate files makes it easy to miss languages.
Solution:
- Always update all 5 language files simultaneously when adding new keys
- Use consistent key structure across all files
- Test all languages before committing
Files Involved:
src/messages/en.json- English (base)src/messages/it.json- Italiansrc/messages/fr.json- Frenchsrc/messages/es.json- Spanishsrc/messages/ar.json- Arabic
Key Learning: Treat translation updates as atomic operations across all 5 languages.
Problem: Non-English prerendered pages (e.g., /fr/recommendations/) would fall back to English default instead of loading the correct language version.
Root Cause: Overly broad catch-all redirect rule /${LOCALE_DEFAULT}/* /:splat 302 was intercepting all requests, including other language routes.
Solution:
- Remove the broad catch-all redirect
- Add specific redirects only for default language routes without trailing slash
- Language-specific redirects are processed first, preventing interception
Files Involved:
vite.config.ts- Redirect configuration (lines 178-195)
Redirect Rules Order:
1. Language-specific redirects (e.g., /fr /fr/)
2. Default language specific routes (e.g., /experience /experience/)
Key Learning: Redirect rules are processed in order; more specific rules must come before catch-all rules.
Problem: Pages with many sidebar blocks (3+) would have excessive scrolling, making the layout feel broken.
Root Cause: Sticky positioning with max-height applied to all sidebars regardless of content volume.
Solution:
- Add
disableSidebarScrollprop to PageLayout - Disable scrolling for pages with 3+ sidebar blocks (MainPage, ExperiencePage)
- Keep scrolling enabled for pages with 2 blocks (SkillsPage, RecommendationsPage)
Files Involved:
src/components/layout/PageLayout.tsx- Conditional scroll classessrc/pages/MainPage.tsx-disableSidebarScrollpropsrc/pages/ExperiencePage.tsx-disableSidebarScrollprop
Key Learning: Sticky scrolling works best with limited content; disable for content-heavy sidebars.
Problem: When toggling layout size, the max-w-7xl class wouldn't be removed even though React state changed.
Root Cause: Tailwind classes are static in the HTML; conditional className logic doesn't override them at runtime.
Solution:
- Always apply
max-w-7xlin the HTML - Use CSS to override it:
html.layout-large main { max-width: none !important; } - Let CSS handle the override, not React conditional logic
Files Involved:
src/components/layout/Navbar.tsx- Always includemax-w-7xlsrc/components/layout/PageLayout.tsx- Always includemax-w-7xlsrc/index.css- CSS override rule
Key Learning: For layout constraints, use CSS overrides rather than conditional Tailwind classes.
Problem: English resume was missing highlights that existed in Italian version, causing inconsistent project descriptions.
Root Cause: Manual data entry across multiple locale files without cross-checking.
Solution:
- Use Italian version as reference (most complete)
- Compare each project's highlights between locales
- Add missing highlights to English version
- Verify all locales have consistent project information
Files Involved:
src/data/resume-en.jsonsrc/data/resume-it.jsonsrc/data/resume-fr.jsonsrc/data/resume-es.jsonsrc/data/resume-ar.json
Key Learning: When maintaining multi-locale data, establish one locale as the source of truth for structure, then translate content.
Problem: Skills section on homepage had accordion collapsed by default, requiring users to click to see content.
Root Cause: Accordion type was "single" with collapsible, no default open values.
Solution:
- Change accordion type to
"multiple"to allow multiple open items - Set
defaultOpenValuesarray with all category IDs - Pass
value={defaultOpenValues}to Accordion component
Files Involved:
src/components/profile/SkillsSection.tsx- Lines 32-50
Key Learning: For preview sections, expand all items by default to showcase content immediately.
Problem: Attempting to optimize bundle size by splitting vendor libraries into separate chunks causes build to fail with TypeError: Cannot read properties of undefined (reading 'createContext').
Root Cause: The vite-prerender-plugin renders pages during build using Node.js SSR. When manualChunks splits React/ReactDOM into separate bundles, those modules aren't available during the SSR phase, causing createContext and other React APIs to be undefined.
Solution:
Keep manualChunks: undefined in vite.config.ts:
build: {
rollupOptions: {
output: {
manualChunks: undefined, // Required for prerendering
},
},
}Files Involved:
vite.config.ts- Build configuration
Key Learning: Prerendered apps (SSR) require all code to be synchronously available during build. Code splitting with dynamic imports (React.lazy) and vendor chunking both break prerendering. The 821KB bundle size is expected and correct for this architecture.