| name | refactor-to-runelight-vue |
| description | Refactor existing Vue 3 TypeScript SFCs into production .g.vue UI models without preview wrappers. |
Refactor Existing Vue SFCs To Runelight
Convert existing Vue 3 TypeScript components into .g.vue UI models.
Read First
- This skill owns the Vue refactor workflow and decision gates.
- For concrete
.g.vue writing patterns, route to authoring-runelight-vue and read Authoring Reference.
If the project isn't wired for Runelight yet, follow the Runelight setup playbook first.
Invariant
.g.vue owns the real SFC template, script, styles, and enumerable visual states. Not a wrapper around an old component.
Workflow
- Inspect the target SFC and its rendered children.
- Apply decision gates: does it render visible DOM? Own visual states? Can those states be represented by props, frame scope, or injection values? Would
.g.vue just wrap the old SFC?
- Choose action:
- migrate — pure or mostly local visual SFC, move into
.g.vue, add <g:frames>
- scope — template depends on composables, stores, queries, or local script state; keep production script and supply template-visible state through frame
scope
- descend — orchestration, inspect children instead
- skip — too risky or no visual surface
- For
descend: keep reading until finding real visual surfaces.
- For
migrate: move the real template, script, styles, props, and helpers into Component.g.vue, add frames, update imports.
- For
scope: identify every non-prop template value that affects branch shape or visible state, then add static scope values for each important frame.
- For native injection-dependent UI, import the same injection key in
<g:frames>, use providers: [[key, value]], and mark meaningful finite axes with GVueProviderFrame.
- Keep structural template branches inspectable:
v-if, v-else-if, v-show, v-for, and dynamic :is should depend directly on props, scope, or injected frame values.
- Update imports from
./Component.vue to ./Component.g.vue. Preserve barrels.
- Run
runelight check + project typecheck. Render preview if available, defaulting to the nearest covered app/screen/parent entry that contains the migrated surface. Use runelight containing-frames <entry#default> --json to find those top-level contexts. Use isolated preview only when no covered parent exists or when debugging the component's own frame contract.
CLI Reference
For the packaged command reference and workflow prompts, read node_modules/@runelight/skills/references/cli.md.
Never
.g.vue that only renders the old component
- A separate preview wrapper SFC
scope values that contain old component nodes
- Runelight-ifying route/provider/layout orchestration
- Bulk-generating
.g.vue for every file in a directory
- Preserving old paths by adding wrappers; update imports or use barrels
- Hiding template branch reachability behind helper predicates or uninspectable computed state
- Using
bindings; Vue frames use props, scope, and providers
Done When
.g.vue owns the migrated template and styles
- Frames describe meaningful visual states, happy-path first
- Stateful frames use concrete
scope values
- Injection frames use
providers and, when variant axes matter, GVueProviderFrame
- Old
.vue no longer owns migrated visual branches
- Preview observation uses the app/screen/parent entry that shows the migrated surface in real layout context when such coverage exists
runelight check passes
- Project typecheck passes, or unrelated failures are reported