Vue2升级Vue3

4,606 阅读2分钟

升级vue-loader后报错

  • 升级 "vue-loader": "^16.1.2"后升级后报错

 Error: Cannot find module 'vue-loader/lib/plugin'
  • 解决办法:修改webpack配置文件中的VueLoaderPlugin

修改前:

const VueLoaderPlugin = require('vue-loader/lib/plugin')

修改后:

const { VueLoaderPlugin } = require('vue-loader')

实例化Vue方式修改

修改前:

import Vue from 'vue'
new Vue({
    el: '#J_app',
    router,
    components: { Index },
    template: '<Index/>'
})

修改后:

import {createApp} from 'vue'
const app = createApp({
    router,
    components: { Index },
    template: '<Index/>'
})

app.mount('#J_app')

v-for修改

修改前:

<div v-for="(item,index) in submitData" class="item">

修改后:

<template v-for="(item,index) in submitData" :key="item.id">
    <div class="item"></div>
</template>

Module not found:Error: Can't resolve 'vue'

升级后报错:

 ERROR in ./node_modules/vue3-ts-flow-components/dist/index.js
    Module not found: Error: Can't resolve 'vue' in 'D:\code\erp\Public\Erp\node_modules\vue3-ts-flow-components\dist'

解决办法:将'vue': 'vue/dist/vue.esm.js',改为'vue': 'vue/dist/vue.esm-bundler.js'

      alias: {//resolve.alias配置项通过别名来把原来导入路径映射成一个新的导入路径。
           'vue': 'vue/dist/vue.esm-bundler.js',
           '@': path.resolve(__dirname,'../src'),
            '#': path.join(process.env.WORKDATA_PATH,'raw'),
            'jquery': path.join(commonDir,'assets/js/jquery-2.1.1.js'),
            '_': path.join(commonDir,'assets/js/lodash.js'),
     }

vue-select版本低

  • 解决办法: 下载源码,自己升级
  • 自己升级后的vue-select已经发布到npm,使用npm install vue3-select 可安装

升级vue-select: Uncaught TypeError: this.$on is not a function

  • Vue3从实例中移除了 onon,off 和 $once 方法
  • 迁移策略: 使用实现事件发射器接口的外部库来替换现有的 event hub 外部库: github.com/developit/m…

升级vue-select: Uncaught TypeError: Cannot read property '_c' of undefined

  • npm install vue@^3.1.1 -D
  • npm install vue-loader@^16.1.2 -D
  • npm install @vue/compiler-sfc -D

vue3 移除了 propsData

this.$options.propsData.hasOwnProperty('reduce')替换为Object.prototype.hasOwnProperty.call(this.$options.props, 'reduce')

v-model 变更

  • prop:value -> modelValue
  • event:input -> update:modelValue

Vue3 移除了 Vue.config.productionTip

Vue3, render 函数不再接收任何参数

升级前:

import Vue from "vue";
import Dev from "./Dev.vue";

new Vue({
  render: h => h(Dev)
}).mount('#app')

升级后:

import {createApp , h } from "vue";
import Dev from "./Dev.vue";


const app = createApp({
  render: () => h(Dev)
})

app.mount('#app')

Vue3 移除 this.$scopedSlots

迁移策略: 所有 this.scopedSlots替换为this.scopedSlots 替换为 this.slots

TypeError: Cannot read property 'subTree' of null

问题产生原因:

  1. 在setupStatefulComponent()方法中,对currentInstance赋值为instance,此时不为null

image.png

  1. 当代码执行到Vue自带组件Basetransition的setup函数时,获取instance为null
const getCurrentInstance = () => currentInstance || currentRenderingInstance;

image.png 为null的原因是1和2的代码不是同一套vue3代码中。

  • 2的代码在vue-select安装的vue3中;
  • 1的代码在erp安装的vue3中
  • vue-select是erp中安装的组件

解决问题方法

  1. 在vue-select的webpack配置文件中配置 externals

image.png

  1. 在package.json文件中配置peerDependencies,以防erp项目没有安装vue3,导致vue3-select从外部引入vue3失败
 "peerDependencies": {
    "vue": "^3.*"
  },
  • 解决的结果是vue3-select会调用erp项目下安装的vue3,即vue3-select和erp用同一个vue3。

安装postcss-loader最新版本报错

 ERROR in ./packages/Toast/src/index.vue?vue&type=style&index=0&id=2b2a0962&lang=css (./node_modules/css-loader/dist/cjs.js??ref--1-1!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??ref--1-2!./node_modules/vue-loader/dist??ref--9-0!./packages/Toast/src/index.vue?vue&type=style&index=0&id=2b2a0962&lang=css)
    Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
    TypeError: this.getOptions is not a function
        at Object.loader (D:\code\flow-component\node_modules\postcss-loader\dist\index.js:40:24)

解决办法: 安装低版本的postcss-loader

npm uninstall postcss-loader
npm install postcss-loader@'^4.3.0' -D

postcss-loader报错

ERROR in ./packages/Toast/src/index.vue?vue&type=style&index=0&id=2b2a0962&lang=css (./node_modules/mini-css-extract-plugin/dist/loader.js??ref--1-0!./node_modules/css-loader/dist/cjs.js??ref--1-1!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??ref--1-2!./node_modules/vue-loader/dist??ref--9-0!./packages/Toast/src/index.vue?vue&type=style&index=0&id=2b2a0962&lang=css)
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'plugins'. These properties are valid:
   object { postcssOptions?, execute?, sourceMap?, implementation? }
    at validate (D:\code\flow-component\node_modules\schema-utils\dist\validate.js:104:11)
    at Object.loader (D:\code\flow-component\node_modules\postcss-loader\dist\index.js:43:29)
    at D:\code\flow-component\node_modules\webpack\lib\NormalModule.js:316:20
    at D:\code\flow-component\node_modules\loader-runner\lib\LoaderRunner.js:367:11
    at D:\code\flow-component\node_modules\loader-runner\lib\LoaderRunner.js:233:18
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
 @ ./packages/Toast/src/index.vue?vue&type=style&index=0&id=2b2a0962&lang=css 1:0-372 1:0-372
 @ ./packages/Toast/src/index.vue
 @ ./packages/Toast/src/toast.ts
 @ ./packages/Toast/index.ts
 @ ./packages/index.ts

报错前的配置:

 {
                    test : /\.css$/,
                   // exclude: /node_modules/,
                    use : [
                        {
                            loader: ExtractCssPlugin.loader,
                            options:{
                                publicPath: '../'
                            }
                        },
                        {
                          loader: 'css-loader',
                          options: { importLoaders: 1 }
                        },
                        {
                          loader: 'postcss-loader',
                          options: {
                            plugins: (loader) => [
                              require('autoprefixer')()
                            ]
                          }
                        }
                    ]

                },

报错后的配置:

{
                test : /\.css$/,
               // exclude: /node_modules/,
                use : [
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                        {
                          loader: 'postcss-loader',
                          options: {
                            postcssOptions: {
                              plugins: [
                                  (loader)=>require('autoprefixer')()
                              ],
                            },
                          },
                        }
                ]

            },

.vue文件重的css打包至单独的.css文件

  • 安装并引入mini-css-extract-plugin包
npm install mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  • 配置 webpack的plugins
 new MiniCssExtractPlugin({
        filename: "index.css"
    }),
  • 配置 webpack的rules
{
   test : /\.css$/,
       use : [
             {
                loader: MiniCssExtractPlugin.loader,
             },
      ]
  }

css文件打包至js文件中

{
                test : /\.css$/,
               // exclude: /node_modules/,
                use : [
                    'style-loader', //style-loader是关键
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                              plugins: [
                                  (loader)=>require('autoprefixer')()
                              ],
                            },
                        },
                    }
                ]
            },

vue-router升级

升级前:

  • "vue-router": "^3.5.1",
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
    routes: [
        {
            path:'/uploadFile',
            name:'UploadFile',
            component:UploadFile
        },
        {
            path:'/importExcel',
            name:'ImportExcel',
            component:ImportExcel
        },
       
    ]
})

const app = createApp({
    router,
    components: { Index },
    template: '<Index/>'
})

升级后:

  • npm uninstall vue-router
  • npm install vue-router@4.0.0-beta.13 -D
import { createRouter, createWebHashHistory} from 'vue-router'

export default createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            path: '/',
            redirect: '/uploadFile'
        },
        {
            path:'/uploadFile',
            name:'UploadFile',
            component:UploadFile
        },
    ]
})

const app = createApp({
    components: { Index },
    template: '<Index/>'
})

app.use(router)