当PC端项目需要迁移到移动端时,你是否还在手动复制粘贴代码?今天分享一个我们团队自研的Vite插件,帮你实现跨仓库、跨技术栈的代码高效复用!
背景:从PC到移动端的迁移之痛
最近我们团队遇到了一个典型的企业级需求:将一个成熟的PC端医疗管理系统(MDM)迁移到移动端。听起来简单,但实际上却面临诸多挑战:
面临的挑战
-
技术栈差异:PC端使用Element Plus,移动端需要Vant
-
仓库隔离:PC端和移动端在不同的Git仓库
-
代码复用:希望复用80%的业务逻辑,但UI组件完全不同
-
维护同步:业务逻辑更新需要在两端同步
传统的解决方案要么是完全重写(成本高),要么是复制粘贴(维护噩梦),或者是Monorepo (代码和依赖放一起)。我们需要的是一种既能复用核心逻辑,代码在不同仓库维护,又能灵活定制UI的解决方案。
解决方案:vite-plugin-code-reuse
基于这个需求,我们开发了 vite-plugin-code-reuse 插件,它的核心思想是:多仓库代码复用、智能替换、无缝集成。
插件核心能力
// 插件的核心配置结构
interface PluginConfig {
repositories: RepositoryConfig[]; // 代码仓库配置
repoImportMappings: RepoImportMappings[]; // 路径映射,主要是规避不同仓库路径别名冲突问题
importReplacements: ImportReplacementConfig[]; // 导入替换
}
实战案例:医疗管理系统迁移
让我通过实际案例展示这个插件的效果。
项目背景
-
PC端项目:
xlian-web-mdm(Vue 3 + Element Plus + TypeScript)
-
移动端项目:新建的H5项目(Vue 3 + Vant + TypeScript)
-
目标:复用PC端80%的业务逻辑,100%替换UI组件
第一步:安装配置插件
npm install vite-plugin-code-reuse --save-dev
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import codeReusePlugin from 'vite-plugin-code-reuse'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
codeReusePlugin({
// 1. 引入PC端代码仓库
repositories: [
{
url: 'http://gitlab.xinglianhealth.com/web/mdm/xlian-web-mdm.git',
branch: 'master',
dir: 'mdm-pc' // 本地存放目录
}
],
// 2. 修正路径别名映射,pc和移动都配置了“@”别名,需要各自引用正确的路径
repoImportMappings: [
{
alias: '@',
repoDir: 'mdm-pc',
// PC端中的“@”别名还是引用pc端目录下的代码,但是需要排除路由、状态管理等路径,引用移动端的,因为路由和store不能存在两个
ignorePatterns: ['src/router', 'src/store', 'src/axios']
}
],
// 3. 智能导入替换,pc端的部分组件无法复用时,可以做替换
importReplacements: [
// 场景1:组件替换(Element Plus → Vant)
{
pattern: /\/views\/MasterData\/components\/UploadFile\.vue$/,
file: 'src/components/MbUpload.vue' // 移动端专用上传组件
},
{
pattern: /\/views\/MasterData\/components\/TextInput\.vue$/,
file: 'src/components/MbTextInput.vue' // 移动端输入框
},
// 场景2:复杂表单组件替换
{
pattern: /\/views\/MasterData\/components\/MasterForm\.vue$/,
file: 'src/components/MbForm.vue' // 移动端表单封装
},
// 场景3:PC端特有功能在移动端隐藏
{
pattern: /\/views\/MasterData\/components\/HeaderFilter\/HeaderFilter\.vue$/,
code: '<template></template>' // 移动端不需要复杂的表头筛选
},
// 场景4:UI库替换
{
pattern: /^@?element-plus/,
resolve: path.resolve('src/components/ElementPlus.ts') // 重定向到兼容层
}
]
})
]
})
第二步:UI组件替换
// src/components/ElementPlus.ts - UI库兼容层
import { Button, Input, Select } from './ui-adaptor'
// 创建Element Plus到Vant的映射
export {
ElButton: Button,
ElInput: Input,
ElSelect: Select,
// ... 更多映射
}
// src/components/ui-adaptor.ts - UI库适配层,以Button组件为例
<template><van-button v-bind="$attrs" /></template>
<script>
const props = defineProps({
// 对element-plus Button Props做适配,比如size不支持"medium",可以处理成其他的,相同的属性不用处理
})
</script>
第三步:复用业务逻辑组件
<!-- src/views/MasterData/PatientList.vue -->
<template>
<!-- 复用PC端的模板结构,但使用移动端组件 -->
<div class="patient-list">
<!-- 搜索框(PC端是ElInput,自动替换为Vant Field) -->
<van-field
v-model="searchKey"
placeholder="搜索患者"
@input="handleSearch"
/>
<!-- 患者列表 -->
<van-list
v-model:loading="loading"
:finished="finished"
@load="loadPatients"
>
<patient-item
v-for="patient in patients"
:key="patient.id"
:patient="patient"
@click="handlePatientClick"
/>
</van-list>
</div>
</template>
<script setup lang="ts">
// 这里直接复用PC端的业务逻辑!
import { usePatientList } from '@/mdm-pc/src/views/MasterData/composables/usePatientList'
// 完全复用PC端的逻辑,包括:
// 1. 数据获取逻辑
// 2. 搜索过滤逻辑
// 3. 分页逻辑
// 4. 事件处理逻辑
const {
patients,
loading,
finished,
searchKey,
loadPatients,
handleSearch,
handlePatientClick
} = usePatientList()
</script>
<style scoped>
/* 移动端特有的样式 */
.patient-list {
padding: 12px;
}
</style>
插件的核心实现原理
1. 代码仓库管理
vite build start开始时,自动拉取PC端仓库代码,如无更新不会重复拉取,默认只拉取一个commit,速度极快。
{
url: 'http://gitlab.xinglianhealth.com/web/mdm/xlian-web-mdm.git', //仓库地址
branch: 'master', // 仓库分支
dir: 'mdm-pc' // 本地存放目录
}

### 2. 智能导入替换,支持三种替换方式,任意选择
```typescript
interface ImportReplacementConfig {
/**
* 匹配模式(正则表达式字符串)
*/
pattern: RegExp;
/**
* 替换方式:代码字符串
*/
code?: string;
/**
* 替换方式:文件路径
*/
file?: string;
/**
* 替换方式:重定向路径
*/
resolve?: string;
}
3. 别名路径冲突映射修正,将被引用的仓库内部别名指向仓库内部,规避和外层别名的冲突
interface RepoImportMappings {
/**
* 路径别名
*/
alias: string;
/**
* 冲突的仓库目录
*/
repoDir: string;
/**
* 忽略列表(路径匹配时跳过),使用外出仓库别名解析
*/
ignorePatterns?: string[];
}
实际效果对比
迁移前(传统方式)
├── 移动端项目
│ ├── src
│ │ ├── views
│ │ │ ├── PatientList.vue ← 需要重写
│ │ │ ├── DoctorList.vue ← 需要重写
│ │ │ └── ... (20+个页面)
│ │ └── components
│ │ ├── MbForm.vue ← 需要重写
│ │ └── ... (50+个组件)
└── 工时:3-4人月
迁移后(使用插件)
├── 移动端项目
│ ├── mdm-pc/ ← 自动引入的PC端代码
│ ├── src
│ │ ├── views
│ │ │ ├── PatientList.vue ← 直接引用PC端PatientList组件,只对样式做适配覆盖
│ │ │ ├── DoctorList.vue ← 直接引用PC端DoctorList组件,只对样式做适配覆
│ │ │ └── ... (复用80%)
│ │ └── components
│ │ ├── MbUploader.vue ← 无法复用的组件,用移动端专用文件组件做替换
│ │ └── ... (只需写30%的组件)
└── 工时:1-1.5人月(节省60%+)
高级应用场景
场景1:多项目共享工具库
// 多个项目共享工具函数
codeReusePlugin({
repositories: [
{
url: 'git@github.com:company/shared-utils.git',
branch: 'main',
dir: 'shared-utils'
},
...
],
importReplacements: [
{
pattern: /^@shared\/utils/,
resolve: path.resolve('shared-utils/src')
},
...
]
})
场景2:主题系统切换
// 根据环境切换主题
codeReusePlugin({
importReplacements: [
{
pattern: /\/themes\/default/,
file: process.env.NODE_ENV === 'mobile'
? 'src/themes/mobile.vue'
: 'src/themes/pc.vue'
}
]
})
场景3:A/B测试版本
// A/B测试不同版本的组件
codeReusePlugin({
importReplacements: [
{
pattern: /\/components\/CheckoutButton\.vue$/,
file: Math.random() > 0.5
? 'src/components/CheckoutButtonVariantA.vue'
: 'src/components/CheckoutButtonVariantB.vue'
}
]
})
总结
vite-plugin-code-reuse 插件为我们解决了跨项目代码复用的核心痛点:
🎯 核心价值
-
大幅提升开发效率:节省60%+的开发时间
-
保证代码一致性:业务逻辑完全一致,减少BUG
-
降低维护成本:一处修改,多处生效
-
灵活定制:UI层完全可定制,不影响核心逻辑
🚀 适用场景
- PC端到移动端的项目迁移
- 多项目共享组件库
- 微前端架构中的模块复用
- A/B测试和实验性功能
如果你也面临类似的多项目代码复用问题,不妨试试这个插件。项目已在GitHub开源,欢迎Star和贡献代码!
GitHub地址:vite-plugin-code-reuse
让代码复用变得简单,让开发效率飞起来! 🚀