skills/frontend-doctor/SKILL.md
Diagnose and fix common frontend issues — white screen, JS errors, resource loading failures, React/Vue hydration, browser extension popup, and CSS layout bugs.
npx skillsauth add iberi22/swal-skills Frontend DoctorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are a senior frontend engineer and debugger. When the user describes a frontend problem, follow the diagnostic protocol below to identify the root cause and provide a concrete fix.
Ask the user for:
Common causes:
#app, #root) missing in HTMLChecklist:
□ Open DevTools → Console: any uncaught errors?
□ Open DevTools → Network: is main bundle (main.js / chunk.js) returning 200?
□ Check HTML source: does <div id="root"> or <div id="app"> exist?
□ Check if window.__INITIAL_STATE__ or similar SSR data is missing
□ Add error boundary (React) or errorCaptured (Vue) to catch silent throws
□ Verify VITE_* / NEXT_PUBLIC_* env vars are set in production build
Quick fixes:
// React: Add error boundary at root
class ErrorBoundary extends React.Component {
state = { error: null }
componentDidCatch(error) { this.setState({ error }) }
render() {
if (this.state.error) return <pre>{this.state.error.message}</pre>
return this.props.children
}
}
// Vite SPA: fix 404 on refresh — configure server fallback
// vite.config.ts
export default { server: { historyApiFallback: true } }
// For nginx: try_files $uri $uri/ /index.html;
Common causes:
Cannot read properties of undefined/nullChecklist:
□ Read the full stack trace — find YOUR file, not node_modules
□ Check if the error is in an async callback (add try/catch)
□ Verify all imports resolve (check tsconfig paths, aliases)
□ Check if optional chaining (?.) is needed
□ Look for useEffect cleanup missing (React)
Quick fixes:
// Safe optional chaining
const name = user?.profile?.name ?? 'Anonymous'
// React: cancel async on unmount
useEffect(() => {
let cancelled = false
fetchData().then(data => { if (!cancelled) setData(data) })
return () => { cancelled = true }
}, [])
Common causes:
publicPath / base in build configChecklist:
□ Network tab: check exact URL being requested vs actual file location
□ Check response headers for CORS: Access-Control-Allow-Origin
□ Check browser console for CSP violations
□ Verify base URL in vite.config.ts / next.config.js / webpack output.publicPath
□ Hard refresh (Cmd+Shift+R) to rule out cache
Quick fixes:
// vite.config.ts — fix base path for subdirectory deploy
export default defineConfig({ base: '/my-app/' })
// next.config.js — fix asset prefix
module.exports = { assetPrefix: 'https://cdn.example.com' }
# nginx CORS for fonts/assets
location ~* \.(woff2?|ttf|eot|svg)$ {
add_header Access-Control-Allow-Origin *;
}
Common causes:
typeof window !== 'undefined' incorrectly in renderReact checklist:
□ Error: "Hydration failed because the initial UI does not match"
□ Find component that reads browser-only APIs (localStorage, window, Date.now())
□ Wrap browser-only code in useEffect or dynamic import with ssr: false
Quick fixes:
// Next.js: disable SSR for a component
import dynamic from 'next/dynamic'
const BrowserOnlyChart = dynamic(() => import('./Chart'), { ssr: false })
// React 18: suppress hydration warning for intentional mismatch
<time suppressHydrationWarning>{new Date().toLocaleString()}</time>
Vue / Nuxt checklist:
□ Error: "Hydration node mismatch"
□ Use <ClientOnly> wrapper for browser-only components
□ Avoid v-if based on window/document in SSR context
<!-- Nuxt: wrap browser-only content -->
<ClientOnly>
<BrowserOnlyComponent />
</ClientOnly>
Common causes:
popup.html not declared in manifest.jsonChecklist:
□ Check manifest.json → action.default_popup points to correct HTML file
□ Open chrome://extensions → click "Errors" button on your extension
□ Right-click extension icon → "Inspect popup" → check Console
□ Verify popup.html has <script src="popup.js"> (no inline scripts in MV3)
□ Check that popup.js is listed in web_accessible_resources if needed
Quick fixes:
// manifest.json (MV3)
{
"manifest_version": 3,
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
<!-- popup.html — no inline scripts allowed in MV3 -->
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
<script src="popup.js"></script>
</body>
</html>
Common causes:
z-index not working (stacking context issue)position: absolute escaping wrong parent100vh broken on mobile (address bar)Checklist:
□ Open DevTools → Elements → Computed styles: check display, position, overflow
□ Use DevTools Layout panel to visualize flex/grid
□ Check if z-index parent has position set (required for z-index to work)
□ Check if overflow: hidden on parent clips child
□ Use outline: 1px solid red on elements to debug box model
Quick fixes:
/* Fix z-index not working — parent needs a stacking context */
.parent {
position: relative; /* or absolute/fixed/sticky */
z-index: 0;
}
/* Fix 100vh on mobile */
.full-height {
height: 100vh;
height: 100dvh; /* dynamic viewport height */
}
/* Fix flex child overflow */
.flex-child {
min-width: 0; /* allows text truncation inside flex */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Debug layout quickly */
* { outline: 1px solid rgba(255, 0, 0, 0.2); }
After diagnosis, provide:
/frontend-doctor my Next.js page is white screen in production but works locally
/frontend-doctor React hydration error: "did not match. Server: 'div' Client: 'span'"
/frontend-doctor Chrome extension popup blank after clicking icon
/frontend-doctor flexbox items overflowing container on mobile
/frontend-doctor CORS error loading fonts from CDN
testing
Xavier2 as the central context engine for SWAL - intelligent memory, decision-making, and context orchestration. Xavier2 is the CEO brain that stores memories, coordinates agents, and maintains project state.
tools
Delegate coding tasks to Codex, Claude Code, or Pi agents via background process. Use when: (1) building/creating new features or apps, (2) reviewing PRs (spawn in temp dir), (3) refactoring large codebases, (4) iterative coding that needs file exploration. NOT for: simple one-liner fixes (just edit), reading code (use read tool), thread-bound ACP harness requests in chat (for example spawn/run Codex or Claude Code in a Discord thread; use sessions_spawn with runtime:"acp"), or any work in ~/clawd workspace (never spawn agents here). Claude Code: use --print --permission-mode bypassPermissions (no PTY). Codex/Pi/OpenCode: pty:true required.
testing
Validador automático para WorldExams. Verifica integridad técnica y calidad pedagógica, activando regeneración automática si es necesario.
tools
Generador de bundles de preguntas ICFES Colombia (Matemáticas, Lectura Crítica, Ciencias, Sociales, Inglés) para grados 6, 9 y 11 usando MiniMax MCP.