Vue 2 在 2023 年 12 月 31[1] 日已经中止官方支持,由于 Vue 2 跟 Vue 3 之间比较多的不兼容,导致代码迁移比较困难,现在 Vue 2 的使用群体仍然占据主流。
不过,随着 Vue 2 结束支持,迁移 Vue 3 以及面向 Vue 3 开发已经是大势所趋,特别是在 Vue 2.7 内置了 Composition API[2] 支持之后。
关于项目迁移,大家可以参考官方《迁移指南》[3]对项目进行逐步迁移。而对于广泛地基于 Vue 2 代码库的迁移,现在有了 antfu 大佬开源的 vue-demi 包[4]后,会方便很多。
接下里就来介绍它的简单使用。
安装
npm install vue-demi
# or
pnpm install vue-demi
在你库的 package.json 文件添加 vue
和 @vue/composition-api
作为 peer 依赖。
{
"dependencies": {
"vue-demi": "latest"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^2.0.0 || >=3.0.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
},
"devDependencies": {
"vue": "^3.0.0" // or "^2.6.0" base on your preferred working environment
},
}
vue-demi 使用使用最新版本,避免使用本地的缓存版本。另外,实际开发中使用的 vue 版本,可以根据你的工作环境决定,这里使用了 Vue 3。
接下来,直接从 vue-demi 中引入 API 进行开发就 OK 了。
import { ref, reactive, defineComponent } from 'vue-demi'
下面我们来举一个案例说明 vue-demi 的使用。
案例
我们会创建一个 useMouse
的 composition api,返回当前鼠标光标在页面种的坐标位置。
首先,创建项目 vue-use-mouse。
$ mkdir vue-use-mouse
$ cd vue-use-mouse
$ code . # code use VS Code
$ pnpm init
向 package.json 文件中添加 vue
和 @vue/composition-api
作为 peer 依赖。
{
// ...
"dependencies": {
"vue-demi": "latest"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^2.0.0 || >=3.0.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
},
"devDependencies": {
"vue": "^3.0.0" // or "^2.6.0" base on your preferred working environment
},
}
还要安装 typescript
依赖,因为我们的源代码是 TS 文件,待会打包也是用 tsc
。
$ pnpm install typescript
源代码位于 src/index.ts
,很简单。
import { ref, onMounted, onUnmounted } from 'vue-demi'
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return {
x,
y
}
}
向 package.json
文件中添加构建脚本。‘
{
// ...
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/esm/index.d.ts",
"scripts": {
"build": "pnpm run build:esm && pnpm run build:cjs",
"build:esm": "tsc src/index.ts --module es2015 --moduleResolution node --lib "es2015, dom" --outDir dist/esm -d",
"build:cjs": "tsc src/index.ts --module commonjs --moduleResolution node --lib "es2015, dom" --outDir dist/cjs"
},
// ...
}
我们最终会将源代码打包成 esm 和 cjs 两种格式供调用方使用。这样,我们就完成了 use-mouse
的开发。
package.json
的最终内容如下:
{
"name": "vue-use-mouse",
"version": "1.0.0",
"description": "",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/esm/index.d.ts",
"scripts": {
"build": "pnpm run build:esm && pnpm run build:cjs",
"build:esm": "tsc src/index.ts --module es2015 --moduleResolution node --lib "es2015, dom" --outDir dist/esm -d",
"build:cjs": "tsc src/index.ts --module commonjs --moduleResolution node --lib "es2015, dom" --outDir dist/cjs"
},
"dependencies": {
"typescript": "^5.3.3",
"vue-demi": "latest"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^2.0.0 || >=3.0.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
},
"devDependencies": {
"vue": "^3.0.0"
},
"keywords": [],
"author": "",
"license": "ISC"
}
内部实现
在 vue-demi 包中,package.json
中导出的文件是位于 lib/
目录下的。
{
"main": "lib/index.cjs",
"module": "lib/index.mjs",
"exports": {
".": {
"types": "./lib/index.d.ts",
"require": "./lib/index.cjs",
"import": "./lib/index.mjs",
"browser": "./lib/index.mjs"
},
},
}
lib/
之下还有 3 个目录。
这 3 个目录主要做的事情:一是为了弥合各版本之间差异,提供统一的 Composition API 支持(Vue 2.6- 会自动提醒你安装 @vue/composition-api
依赖);二是你使用 Vue 2 中弃用、但在 Vue 3 中新增的功能时,会给你提示说不能用,否则无法同时兼容两个版本。
vue-demi 包的 package.json
文件中,还定义了 postinstall
脚本。
{
"scripts": {
"postinstall": "node ./scripts/postinstall.js",
},
}
在宿主库安装完 vue-demi 后,会触发这个 hook,进而调用 postinstall.js
脚本。内容如下:
const { switchVersion, loadModule } = require('./utils')
const Vue = loadModule('vue')
if (!Vue || typeof Vue.version !== 'string') {
console.warn('[vue-demi] Vue is not found. Please run "npm install vue" to install.')
}
else if (Vue.version.startsWith('2.7.')) {
switchVersion(2.7)
}
else if (Vue.version.startsWith('2.')) {
switchVersion(2)
}
else if (Vue.version.startsWith('3.')) {
switchVersion(3)
}
else {
console.warn(`[vue-demi] Vue version v${Vue.version} is not suppported.`)
}
switchVersion()
函数的内部代码如下:
function switchVersion(version, vue) {
copy('index.cjs', version, vue)
copy('index.mjs', version, vue)
copy('index.d.ts', version, vue)
if (version === 2)
updateVue2API()
}
总结下来,会检查宿主项目中安装的 Vue 版本,再根据版本把 lib/
对应目录下的文件(v2.7、v2、vue3)复制到 lib/
根目录下,这样在宿主项目中就能引入正确的版本了。
总结
本文我们介绍了如何使用 vue-demi 来完成同时支持 vue 2 和 vue 3 的版本包的开发。同时,也介绍了 vue-demi 内部的实现原理。
希望对你能有所帮助,感谢阅读,再见。
参考资料
2023 年 12 月 31: https://blog.vuejs.org/posts/vue-2-eol
[2]Composition API: https://vuejs.org/guide/extras/composition-api-faq.html
[3]《迁移指南》: https://v3-migration.vuejs.org/
[4]antfu 大佬开源的 vue-demi 包: https://antfu.me/posts/make-libraries-working-with-vue-2-and-3
原文始发于微信公众号(写代码的宝哥):vue-demi:编写同时适配 Vue 2 和 3 的公共库
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/243640.html