5.5 KiB
Quality Guidelines
Code quality standards for frontend development.
Overview
(To be filled by the team)
Forbidden Patterns
(To be filled by the team)
Required Patterns
(To be filled by the team)
Testing Requirements
(To be filled by the team)
Development Workflow
Package Changes Testing
When making changes to packages/ directory and testing with examples/:
- Vite dev server auto-reloads: The dev server (
bun run dev) automatically reloads changes inpackages/when you access the example pages - Verify changes took effect: Modify
DEV_MODE_TSinpackages/manage/router/index.vue- this string is displayed at.el-menu .menu-footer(bottom of sidebar menu). Changing it forces the app to refresh. - Build before finishing: Run
bun run build:libto ensure the library builds correctly with your changes
// In packages/manage/router/index.vue - change this string to force refresh
const DEV_MODE_TS = "2026-03-26T03:50:00.000Z"; // Update timestamp to force reload
Build Commands
This project uses bun as package manager:
| Command | Purpose | When to Use |
|---|---|---|
bun run dev |
Start Vite dev server | Testing example project |
bun run build |
Build examples project | DO NOT USE - examples don't need build |
bun run build:lib |
Build library for external repos | When done with changes, to verify build |
bun run lint |
Lint code | Before commit |
Common mistake: Running bun run build which builds the examples project unnecessarily. The examples project is for development only and Vite handles hot reload automatically.
Quick Test Cycle
# 1. Make changes to packages/
# 2. Dev server auto-reloads when accessing example pages
# 3. Modify DEV_MODE_TS in packages/manage/router/index.vue if changes don't appear
# 4. Run build:lib when done to verify
bun run build:lib
Browser Automation with agent-browser
When using agent-browser for testing:
DO: Use CSS selectors with wait instead of fixed timeouts
# Good - waits for element to appear
agent-browser wait ".el-table-v2__row" && agent-browser snapshot
# Bad - arbitrary timeout, may be too short or waste time
agent-browser wait 3000
DO: Check console for errors after page interaction
agent-browser click "@e1" && agent-browser console
DO: Navigate with hash routes properly
# Hash-based SPA routes need explicit navigation
agent-browser navigate http://localhost:5173/#/table-v2
Common wait patterns:
agent-browser wait --load networkidle- for page navigationagent-browser wait ".my-selector"- for element appearanceagent-browser wait --url "**/pattern"- for URL changes
Common Mistakes / Gotchas
el-table-v2 probe row timing
When using a probe row to dynamically measure row height for el-table-v2's virtual scrolling:
Problem: Using a single requestAnimationFrame causes inconsistent row heights (first 3 rows taller than rest).
Cause: el-table-v2's virtual scroller calculates positions based on estimatedRowHeight, but a single frame isn't enough for it to fully settle.
Solution: Use TWO requestAnimationFrame calls before measuring:
await nextTick();
await new Promise(resolve => requestAnimationFrame(resolve)); // Frame 1
await new Promise(resolve => requestAnimationFrame(resolve)); // Frame 2 - el-table-v2 now settled
const height = probeRowRef.value?.offsetHeight;
Verification: All rows should have identical heights and consistent spacing.
el-table-v2 resize with probe row (clear-then-set pattern)
When handling window/container resize with a probe row for dynamic row height:
Problem: Clearing estimatedRowHeight to trigger re-measure creates a visible flash (1-2 frames) where el-table-v2 uses default height.
Root Cause: The gap between clearing the old value and setting the new value is visible to el-table-v2.
Solution: Measure first (capturing new values), then use queueMicrotask to clear and set in the SAME microtask:
// 1. Measure first while old values still set
const headerHeight = headerEl?.offsetHeight;
const rowHeight = firstRow?.offsetHeight;
const newHeader = headerHeight && headerHeight > 0 ? headerHeight : estimatedHeaderHeight.value;
const newRow = rowHeight && rowHeight > 0 ? rowHeight : estimatedRowHeight.value;
// 2. Clear then set in same microtask (before next paint)
estimatedRowHeight.value = undefined;
estimatedHeaderHeight.value = undefined;
queueMicrotask(() => {
estimatedRowHeight.value = newRow;
estimatedHeaderHeight.value = newHeader;
});
Why queueMicrotask works: It defers the set to the end of the current microtask queue, but BEFORE the next paint. So the sequence is:
- Microtask 1:
undefinedis set (triggers el-table-v2 re-measure) - Microtask 2 (queued): New value is set
- Paint: Only one paint happens with the correct value
Without queueMicrotask: The clear and set happen in separate Vue reactivity updates, causing TWO paints (one with undefined, one with new value).
Code Review Checklist
(To be filled by the team)