← Back to Skills Marketplace
aiswot

Vue To Umijs

by aiswot · GitHub ↗ · v0.1.0 · MIT-0
cross-platform ✓ Security Clean
28
Downloads
1
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install vue2umijs
Description
Migrate Vue 2/3 projects to React on UmiJS (@umijs/max): conventions, constraints, stack mapping, and syntax examples (single SKILL.md). Use for .vue → Umi p...
README (SKILL.md)

Vue → UmiJS + React migration

Goal: move a Vue codebase to UmiJS (@umijs/max) + React 18 + antd, with behavior parity and Umi’s routing, data flow, and folder conventions.

Document layout: rules and constraints first; Stack and Umi mapping next; Syntax examples last.

Scope

  • Source: Vue 2 / 3 (Options API, Composition API, SFC).
  • Target: Umi 4 + @umijs/max + React 18; function components and hooks; TypeScript for public APIs.
  • Default stack: antd; src/models + useModel; React Router v6 (via Umi); Less + *.module.less; pages as PageName/index.tsx + PageName/index.module.less.

Principles

  1. Parity first: routing, URL, guards, loading/errors, and UX before micro-optimizations.
  2. Single source of truth: no duplicate domain state across store and local state unless there is an explicit draft/edit buffer.
  3. Side-effect boundaries: useEffect (or Umi equivalents) for subscriptions and async with cleanup; cancel in-flight work with AbortController where needed.
  4. No Vue runtime: replace plugins, mixins, filters, and global buses with hooks, Umi models, and explicit modules.
  5. Closures and deps: dependency arrays reflect real deps; derive with render/useMemo, not effects for pure derivation.

API mapping (summary)

Area Direction
Page .vue PageName/index.tsx + index.module.less
Child .vue Foo.tsx + Foo.module.less (same folder, matching basename)
Component API defineComponentfunction Name(props: NameProps); emitonXxx
ref / reactive / computed / watch useState / useRef, useReducer, useMemo, useEffect (deps + cleanup)
Vue Router Umi config / routes; useNavigate, useParams, etc. — see Routing and data below
Pinia / Vuex src/models + useModel by domain; prefer useRequest for local fetch/cache
Element UI / Element Plus Map to antd with matching interaction and validation semantics

Constraints

  1. One router tree: use Umi nested routes/layouts; do not add a standalone BrowserRouter beside Umi; avoid full-page navigations that break SPA where the old app used in-app routing.
  2. Typing: avoid any on exported components, route params, and model shapes.
  3. Security and a11y: no untrusted dangerouslySetInnerHTML; preserve focus, labels, and keyboard behavior; env vars and URL semantics stay aligned or are explicitly documented.
  4. Styles: index.module.less next to index.tsx for pages; child components: .tsx + .module.less with the same basename.
  5. Vue-specific features: custom directives, plugins, defineExpose + parent refs must map to explicit React/Umi patterns (controlled props, forwardRef/useImperativeHandle, permission guards)—never silently drop behavior.
  6. Async and lists: clean up listeners and requests on unmount or dep changes; use stable ids for list keys, not indexes when order changes.
  7. Do not: run side effects during render; use useEffect for pure derivation; recreate EventBus / mixin / filter pipelines; mirror props to state without need; introduce a second global state stack for the same domain without a plan (prefer Umi models).

Additional constraints (often missed—verify explicitly)

  1. i18n: migrate vue-i18n keys/namespaces and locale switching to the chosen solution (including Umi locale plugins); avoid leftover hard-coded copy or mixed languages.
  2. HTTP and errors: use the shared request wrapper (and @umijs/max request APIs) so interceptors, error codes, auth headers, and global toasts match the old Vue layer; avoid ad-hoc fetch that bypasses global handling.
  3. Environment: map VITE_* / import.meta.env to Umi env / define; never ship secrets or internal-only URLs in the client bundle.
  4. Forms and tables: align Element validation rules, async validation, and blur/submit timing with antd Form; keep Table rowKey, pagination, sort, and filter params aligned with backend contracts; validate dynamic forms (Form.List, etc.) behavior-by-behavior.
  5. API scalars: keep explicit conversion between backend 0/1, stringly numbers, enums, and UI booleans—prefer normalization at submit/response boundaries to avoid silent drift.
  6. Build and deploy: publicPath / base, static asset URLs, and CDN prefixes match the old site or are documented; avoid production 404s for assets.
  7. Dev / integration: move mocks and dev proxy from the Vue setup into Umi conventions (mock/, proxy) so local and joint-debug environments stay consistent.
  8. SSR vs CSR: with Umi SSR, do not use window / document / localStorage on the server render path; with CSR-only, document any first-screen / SEO differences vs the legacy app.

Pre-release checklist

  • Routing, query, and auth behavior matches the legacy app (or differences are documented).
  • useEffect deps are complete; async work is cancelled or ignored when stale.
  • Pages include index.tsx + index.module.less; child style files match basename.
  • Custom directives/plugins/exposed methods have a mapped implementation or migration note.
  • Request layer, env vars, and deploy paths checked against Additional constraints.
  • Sample pass on critical forms/tables and i18n paths vs legacy behavior.

Style and structure

  • Prefer function components and hooks; emitonXxx.
  • Keep feature boundaries similar to the Vue repo; page folder naming: see Vue SFC styles → Umi components below.

Stack and Umi mapping

Umi/antd APIs follow the official docs.

Target stack

Layer Choice
App framework @umijs/max (Umi 4)
UI Ant Design (antd)
Global state Umi data flow: src/models + useModel
Runtime React 18
Routing React Router v6 (via Umi; configure in config + routes)

Styling: Less + CSS Modules (*.module.less). Pages: PageName/index.tsx + PageName/index.module.less.

Routing and data (Umi)

Typical Vue pattern Umi + React
Fetch in onMounted after navigation useRequest, useModel, or useEffect + project request in page/layout
beforeEach auth access, route wrappers, or layout-level guards (see Umi docs)
Navigation / URL params useNavigate, useParams, useSearchParams, useLocation from @umijs/max or umi

Do not add a second standalone BrowserRouter root outside Umi.

Pinia / Vuex → Umi data flow

Vue Umi
Modular store src/models split by domain + useModel
Getters / derived Logic in models or useMemo in components
Async actions Model effects, or useRequest in pages then update model

Prefer useRequest for local request/cache when global state is not needed.

Vue SFC styles → Umi components

Vue React (Umi)
Page \x3Cstyle scoped> PageDir/index.tsx + index.module.less, import styles from './index.module.less'
Child scoped Foo.tsx + Foo.module.less in the same folder
\x3Cstyle lang="less"> Same content in the matching *.module.less

For HTTP, i18n, env, deploy, and mock constraints, see Additional constraints above.

Syntax examples

Vue vs React syntax; use @umijs/max, antd, and the rules above in real pages.

1. Counter

Vue 3 (\x3Cscript setup>)

\x3Cscript setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
function inc() {
  count.value++
}
\x3C/script>
\x3Ctemplate>
  \x3Cbutton type="button" @click="inc">{{ count }}\x3C/button>
\x3C/template>

React

import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)
  return (
    \x3Cbutton type="button" onClick={() => setCount((c) => c + 1)}>
      {count}
    \x3C/button>
  )
}

2. Conditional list

Vue

\x3Ctemplate>
  \x3Cul v-if="items.length">
    \x3Cli v-for="item in items" :key="item.id">{{ item.name }}\x3C/li>
  \x3C/ul>
  \x3Cp v-else>No data\x3C/p>
\x3C/template>

React

return items.length ? (
  \x3Cul>
    {items.map((item) => (
      \x3Cli key={item.id}>{item.name}\x3C/li>
    ))}
  \x3C/ul>
) : (
  \x3Cp>No data\x3C/p>
)

3. Controlled input

Vue

\x3Cinput v-model="text" />

React

const [text, setText] = useState('')
\x3Cinput value={text} onChange={(e) => setText(e.target.value)} />

4. Child events (emit)

Vue

\x3Cscript setup lang="ts">
const emit = defineEmits\x3C{ (e: 'update', v: number): void }>()
function notify() {
  emit('update', 1)
}
\x3C/script>

React

type Props = { onUpdate: (v: number) => void }
export function Child({ onUpdate }: Props) {
  function notify() {
    onUpdate(1)
  }
}

5. computed and watch

Vue

const doubled = computed(() => count.value * 2)
watch(count, (v) => console.log(v))

React

const doubled = useMemo(() => count * 2, [count])
useEffect(() => {
  console.log(count)
}, [count])

6. Provide / inject

Vue

provide('theme', 'dark')
const theme = inject('theme')

React

import { createContext, useContext, useMemo, useState } from 'react'

type Theme = 'light' | 'dark'
type ThemeContextValue = {
  theme: Theme
  setTheme: (v: Theme) => void
}

const ThemeContext = createContext\x3CThemeContextValue | null>(null)

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState\x3CTheme>('light')
  const value = useMemo(() => ({ theme, setTheme }), [theme])
  return \x3CThemeContext.Provider value={value}>{children}\x3C/ThemeContext.Provider>
}

export function useTheme() {
  const ctx = useContext(ThemeContext)
  if (!ctx) throw new Error('useTheme must be used within ThemeProvider')
  return ctx
}

// usage:
// const { theme, setTheme } = useTheme()

7. Cleanup

Vue

onUnmounted(() => window.removeEventListener('resize', onResize))

React

useEffect(() => {
  window.addEventListener('resize', onResize)
  return () => window.removeEventListener('resize', onResize)
}, [])

8. Scoped slot → render prop

Vue

\x3CChild v-slot="{ row }">
  \x3Cspan>{{ row.name }}\x3C/span>
\x3C/Child>

React

\x3CChild renderRow={(row) => \x3Cspan>{row.name}\x3C/span>} />

9. Route params

Vue

const route = useRoute()
const id = route.params.id as string

Umi (same as React Router v6)

import { useParams } from '@umijs/max'
// or import { useParams } from 'umi'

const { id } = useParams\x3C{ id: string }>()

10. React mental model: closure and deps

Common but not recommended

// stale closure: interval always sees initial count
useEffect(() => {
  const timer = setInterval(() => {
    setCount(count + 1)
  }, 1000)
  return () => clearInterval(timer)
}, []) // count is missing

Recommended

// use functional update to avoid stale closure
useEffect(() => {
  const timer = setInterval(() => {
    setCount((c) => c + 1)
  }, 1000)
  return () => clearInterval(timer)
}, [])

Common but not recommended

// derives data via effect + extra state
const [fullName, setFullName] = useState('')
useEffect(() => {
  setFullName(`${user.firstName} ${user.lastName}`)
}, [user.firstName, user.lastName])

Recommended

// derive directly in render / useMemo
const fullName = useMemo(
  () => `${user.firstName} ${user.lastName}`,
  [user.firstName, user.lastName]
)
Usage Guidance
This skill appears safe as a documentation-only migration aid. As with any coding assistant guidance, review generated code changes before applying them, especially changes involving routing, authentication headers, environment variables, and build/deployment settings.
Capability Analysis
Type: OpenClaw Skill Name: vue2umijs Version: 0.1.0 The skill bundle provides legitimate instructions and syntax mappings for migrating Vue 2/3 projects to UmiJS and React. It includes security-conscious constraints, such as avoiding 'dangerouslySetInnerHTML' and ensuring environment secrets are not exposed in client bundles (SKILL.md). No evidence of malicious intent, data exfiltration, or prompt injection was found.
Capability Assessment
Purpose & Capability
The stated purpose—helping migrate Vue 2/3 projects to React on UmiJS—is coherent with the SKILL.md content, which provides conventions, constraints, mappings, and examples.
Instruction Scope
The instructions are scoped to source-code migration practices and include safety-oriented constraints such as avoiding untrusted dangerouslySetInnerHTML and not shipping client-side secrets.
Install Mechanism
There is no install spec, no binaries, and no executable setup. README.md describes manual skill installation methods only.
Credentials
The skill declares no required environment variables, credentials, config paths, or OS-specific access. Environment guidance is limited to migration documentation.
Persistence & Privilege
No persistence, background workers, account privileges, credential access, or autonomous runtime behavior are present in the artifacts.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install vue2umijs
  3. After installation, invoke the skill by name or use /vue2umijs
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v0.1.0
Initial release of vue-to-umijs migration guide. - Provides detailed conventions, constraints, and mappings for migrating Vue 2/3 projects to UmiJS with React 18 and antd. - Outlines API and syntax migrations from Vue (including SFC, router, and state patterns) to Umi’s folder, routing, and data conventions. - Includes tables for key stack and behavior mappings (e.g., component structure, router, state, UI libraries). - Emphasizes parity, typing, cleanup, and accessibility requirements. - Lists additional migration gotchas (i18n, requests, environment, forms/tables, API normalization, deployment, mocks). - Supplies a pre-release checklist to ensure completeness and alignment with legacy behavior.
Metadata
Slug vue2umijs
Version 0.1.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is Vue To Umijs?

Migrate Vue 2/3 projects to React on UmiJS (@umijs/max): conventions, constraints, stack mapping, and syntax examples (single SKILL.md). Use for .vue → Umi p... It is an AI Agent Skill for Claude Code / OpenClaw, with 28 downloads so far.

How do I install Vue To Umijs?

Run "/install vue2umijs" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Vue To Umijs free?

Yes, Vue To Umijs is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Vue To Umijs support?

Vue To Umijs is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Vue To Umijs?

It is built and maintained by aiswot (@aiswot); the current version is v0.1.0.

💬 Comments