vue-code-review
Skill2 starsChanged 34 days agoMITView on GitHub
Use when reviewing a pull request or diff in a Vue project (Vue 2 or 3, Element UI/Plus, Pinia/Vuex). Enforces an intent-first pass, then correctness, security, performance, UX, maintainability and test checks, with blocker/should/nit severities and a file:line findings format.
In this repository13 other files it gives its agents.
- api-layer-axiosSkill
- element-plus-adminSkill
- nuxt3-appSkill
- pinia-stateSkill
- uni-app-cross-platformSkill
- vue2-to-vue3-migrationSkill
- vue3-compositionSkill
- vue-forms-validationSkill
- vue-i18n-setupSkill
- vue-performanceSkill
- vue-router-authSkill
- vue-testing-vitestSkill
- wechat-miniprogramSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Understand intent before judging code: Read the PR title, linked issue and the full diff once without commenting.
- Very specific: line 19
Findings are anchored: Every finding names path:line, the symptom, and a one-line fix.
- Distinctive: line 156
When the diff adds a call to an existing function, read that function.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Vue code review
This skill applies when asked to review a diff, branch or PR in a Vue codebase. "Good" is a short list of findings a developer can act on in one sitting, ordered by what would hurt in production, each anchored to a file and line with a one-line fix. It is not for reviewing formatting, import order or anything ESLint and Prettier already enforce. Skip the UX section for pure library code.
Non-negotiables
- Understand intent before judging code. Read the PR title, linked issue and the full diff once without commenting. Half of "bugs" found by reviewers who skipped this step are intended behaviour.
- Findings are anchored. Every finding names
path:line, the symptom, and a one-line fix. "Consider refactoring this" is not a finding. - Severity has thresholds.
blocker: wrong result, data loss, security hole, crash, or a race users will hit.should: correct today but will break under a foreseeable change, or costs >50 ms per interaction.nit: style and naming that lint does not cover. Do not inflate nits to look thorough. - At most ~10 findings per review. Beyond that, group and summarise; a 40-item review gets skimmed and the blocker gets lost.
- Every blocker is verified, not pattern-matched. Open the file, trace the data flow, confirm the failing input. If you cannot confirm, mark it "plausible" and say what to check.
- Do not review what the linter owns. Formatting, import order, quote
style, trailing commas, unused vars that ESLint catches. If the project
has no lint, say so once as a
shouldand move on. - Request changes only for blockers. Approve with comments when there
are only
shouldandnititems; blocking a PR over naming trains people to ignore reviews. - Praise is specific or absent. "Nice use of the sequence counter in
useList" teaches; "LGTM" does not.
Workflow
- Scope. List the files changed, group by feature. Note anything touched that the PR description does not mention; that is the first question to ask, not a finding.
- Correctness pass (one file at a time, template then script):
- Reactivity:
reactivedestructured,watchon a plain prop value,computedwith side effects, state read before async resolves. - Props mutated,
v-modelon a prop. - Cleanup: timers,
addEventListener,ResizeObserver, websocket, store subscriptions withoutonUnmounted/onScopeDispose. - Async races: list loads without a sequence guard, submit buttons
without a pending flag (double submit),
awaitinsidev-forloops. - Null paths: optional API fields used without
?.in template;[0]on possibly-empty arrays.
- Reactivity:
- Security pass:
v-htmlwith any content that was ever user input, unless it passed through a sanitizer on this code path.- Tokens:
localStorageis acceptable only if the project already does it; new code should not add a second storage. Flag tokens in URL query strings asblocker. - Request params built from
route.query/route.paramspassed straight to the API without type coercion. - Upload: file type checked by extension only, no size limit, no server-side validation mentioned.
- Secrets or internal hostnames in client code.
- Performance pass:
deep: truewatchers on objects over ~10 fields;reactive/refholding API lists over ~1k rows.v-forwithout a stablekey, orkey="index"on a list that reorders or deletes.- Scroll / resize / input handlers without throttle or debounce.
- Heavy work in
computedthat depends on a large array and runs on each keystroke. - Component imported statically on a route that is otherwise lazy.
- UX pass (pages and dialogs only):
- Loading, empty and error states exist for each request.
- Destructive actions have a confirm; the confirm names the item.
- Forms reset on dialog close; validation errors visible without scrolling; submit disabled while pending.
- Strings hardcoded where the project uses i18n.
- Maintainability pass:
- Component over ~300 lines or over ~3 unrelated state groups.
- Same API call written inline in two places instead of the api module.
- Magic strings for status / type where a dictionary or enum exists.
- New util that duplicates one in
utils/.
- Test pass. Map each behaviour change to a test. Missing test on a
blocker-class path (money, permissions, deletion) is itself ashould. Snapshot tests of whole pages count as no test. - Write the review in the format below. Order: blockers, shoulds, nits, then one line of verdict.
Patterns
Findings format
### Blockers
- `src/views/order/List.vue:84` Submit handler has no pending flag; double
click creates two orders. Fix: `if (submitting.value) return` + set flag.
### Should
- `src/composables/useList.ts:21` Response can land out of order while
typing in search. Fix: sequence counter, drop stale responses.
### Nits
- `src/views/order/Detail.vue:12` `data1` → `orderSummary`.
Verdict: request changes (1 blocker). Rest is solid, nice split of the
dialog into `OrderEditDialog.vue`.Race in a submit handler
// flagged
async function submit() {
await api.createOrder(form) // second click while awaiting → duplicate
ElMessage.success('ok')
}
// fix
const submitting = ref(false)
async function submit() {
if (submitting.value) return
submitting.value = true
try { await api.createOrder(form); ElMessage.success('ok') }
finally { submitting.value = false }
}v-html from the API
<!-- flagged: content originates from a rich-text editor filled by users -->
<div v-html="article.body" />
<!-- fix: sanitize on the way in, once, with an allowlist -->
<div v-html="sanitize(article.body)" />Server-side sanitisation is the real fix; flag the client side as
blocker only when the content path provably includes untrusted input.
Keys in reorderable lists
<!-- flagged: deleting row 2 re-renders every row below, inputs keep old values -->
<Row v-for="(r, i) in rows" :key="i" />
<!-- fix -->
<Row v-for="r in rows" :key="r.id" />Reviewing what is not in the diff
When the diff adds a call to an existing function, read that function. Reviews that stop at the diff boundary miss the majority of null-path bugs; budget ~30% of review time for the callee side.
Pitfalls
| Symptom | Cause | Fix |
| Review lists 30 items, author fixes the easy ones | No severity, no cap | Label severity, cap at ~10, group the rest |
| "Bug" turns out to be intended | Skipped reading issue and description | Intent pass first; ask before asserting |
| Blocker raised on a false positive | Pattern-matched v-html without tracing the source | Trace to origin; downgrade to "plausible" when unsure |
| Author argues about naming for two days | Nit was filed as should | Nits never block; mark them nit |
| Same comment on 12 files | Repeated instead of grouped | One finding with the file list |
| Review approves, prod double-submits | Pending flag check skipped on "simple" form | Run the correctness list on every handler that awaits |
Review flags localStorage token as blocker in a project that always did that | Project convention not checked | Match severity to the delta the PR introduces |
| Findings cite wrong line numbers | Read a stale checkout | Review the branch head; quote the line text with the number |
| Reviewer rewrites the feature in comments | Scope creep | Suggest the minimal fix; file bigger ideas as a follow-up issue |
Before you finish
- Each finding has
path:line, symptom, one-line fix, and a severity. - Every
blockerwas verified by reading the surrounding code, or is marked "plausible" with what to check. - No finding duplicates an ESLint / Prettier rule the project runs.
- At most ~10 findings; the rest grouped.
- Verdict line states approve / approve with comments / request changes and the count of blockers.
- Files touched but not described in the PR were called out as a question.
- Test coverage of money / permission / deletion paths was checked.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

