vue2 组件可以在 vue3 中使用么?
问题描述
我目前有一个封装好的Vue2组件库A,通过npm repo在几个项目中使用。现在基于Vue3的项目也要接入组件A,我要怎样通过一套代码发布,就可以同时在基于Vue2和Vue3版本的项目中使用?
自己尝试过哪些方法
临时解决方案是分为两个分支,一个分支依赖"vue": 2.x,一个分支依赖"vue": 3.x,每次有改动需要修改发布两次,维护两个分支。
相关代码
package.json
{ "name": "xxx",
"version": "4.0.1",
"description": "xxx",
"private": false,
"main": "xxx",
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack --progress"
},
"dependencies": {
"vue": "^2.6.11"
},
"devDependencies": {
"@babel/core": "^7.16.12",
"@babel/preset-env": "^7.16.11",
"@babel/preset-stage-3": "^7.8.3",
"@babel/runtime": "^7.16.7",
"babel-loader": "^8.2.3",
"cross-env": "^7.0.3",
"css-loader": "^6.5.1",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"postcss-loader": "^6.2.1",
"style-loader": "^3.3.1",
"svg-sprite-loader": "^6.0.11",
"vue-loader": "^15.9.8",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.67.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.3"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
webpack.config.js
var path = require('path')var webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
function resolve(dir) {
return path.join(__dirname, dir);
}
const NODE_ENV = process.env.NODE_ENV
module.exports = {
entry: NODE_ENV == 'development' ? './examples/main.js' : './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'xxx.js',
library: 'xxx', // 指定的就是你使用require时的模块名
libraryTarget: 'umd', // libraryTarget会生成不同umd的代码,可以只是commonjs标准的,也可以是指amd标准的,也可以只是通过script标签引入的
umdNamedDefine: true //
},
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
],
},
{
test: /\.less$/,
use: [
'vue-style-loader',
'postcss-loader',
'css-loader',
'less-loader'
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: [
['@babel/preset-env', { targets: "defaults" }]
]
}
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/navigation/icons')],
options: {
symbolId: 'icon-[name]'
}
},
{
test: /\.(png|jpg|gif|svg|woff2?|eot|ttf|otf)$/,
type: 'asset',
exclude: [resolve('src/navigation/icons')]
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
historyApiFallback: true,
allowedHosts: 'all',
host: 'localhost',
compress: true,
port: '8002',
client: {
overlay: true
}
},
performance: {
hints: false
},
devtool: 'eval-source-map',
plugins: [
// make sure to include the plugin!
new VueLoaderPlugin()
]
}
导出组件
// 导入导航组件import xxx from './xxx'
// 存储组件列表
const components = [
xxx
]
// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
const install = function (Vue) {
// 判断是否安装
if (install.installed) return
// 遍历注册全局组件
components.map(component => Vue.component(component.name, component))
}
// 判断是否是直接引入文件
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default {
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
install,
// 以下是具体的组件列表
xxx
}
打包后部分代码
!function(V,l){"object"==typeof exports&&"object"==typeof module?module.exports=l():"function"==typeof define&&define.amd?define("xxx",[],l):"object"==typeof exports?exports["xxx"]=l():V["xxx"]=l()}(self,(function(){return function(){var __webpack_modules__={482:function(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval('// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n "default": function() { return /* binding */ src; }\n});\n\n;// CONCATENATED MODULE: ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/x/x.vue?vue&type=template&id=862ecfc0&\nvar render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c(\'div\',{staticClass:"xxx",class:[_vm.transparent ? \'transparent\' : \'\', _vm.themeClass]}
报错位置
var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h
项目结构
.vue,.less,.js,font,svg,png
期待的结果和实际看到的错误信息
期望组件只用维护一套代码。目前在Vue3上使用报错信息如下:
我大概了解是因为Vue单文件template模板编译不兼容导致的,但是实在不知道怎么解决。
解决方案:最终采用卡卡军的方法
- 增加一个package.json和对应打包配置
- 增加postinstall配置,用来下载时自动切换版本,内容copy的卡卡军的,然后同时构建生成两个版本
感觉如果不想构建两个版本的,只能在最初就全部用render(h)的形式写,(或者打包时不编译.vue?这种不会)
回答:
这个问题,我已经找到解决方法了,使用vue-demi, 但前提是封装好的组件需要重新用vue3书写, 然后打包成vue2和vue3都适用的版本, 但维护只需要维护一套,具体操作查看我写的这篇文章
https://juejin.cn/post/705526...
发布到npm的demo插件
https://github.com/kakajun/vu...
回答:
同时兼容 2 & 3 的话需要用到 vue-demi: https://github.com/vueuse/vue...
具体用法可以自己搜索了解一下。
以上是 vue2 组件可以在 vue3 中使用么? 的全部内容, 来源链接: utcz.com/p/937575.html