使用Vue3重构vue2项目(上)

简介: 使用Vue3重构vue2项目(上)

前言


2020年9月18日,vue3正式版发布了,前几天把文档整体读了一遍,感触很深,可以解决我项目中的一些痛点,于是就决定重构之前那个vue2的开源项目。


本篇文章就记录下重构vue2项目的过程,欢迎各位感兴趣的开发者阅读本文。


环境搭建


本来打算使用vite + vue3 + VueRouter + vuex + typescript来构架项目的,但是经过一番折腾后发现vite目前只对vue支持,对于vue周边的一些库还没做到支持,没法在项目中使用。


最后,还是决定使用Vue Cli 4.5来构建了。


虽然vite目前还无法正常在项目中使用,但是我也折腾了一回,就记录下在折腾时的过程以及一些报错。


使用vite构建项目


本文采用的包管理工具为yarn,将其升级至最新版本就可以正常创建vite项目了。


初始化项目


接下来,我们来看看具体步骤。


  • 打开终端,进入你的项目目录,运行命令:yarn crete vite-app vite-project,该命令用于创建一个名为vite-project的项目。


640.png


  • 创建完成后,会得到如下所示的文件。


640.png


  • 进入创建好的项目,运行命令:yarn install,该命令会安装package.json中声明的依赖。


640.png


  • 我们使用IDE打开刚才创建的项目,整体项目如下所示,vite官方为我们提供了一个简单的demo。


640.png


  • 打开package.json查看启动命令在终端运行命令:yarn run dev或者点击ide的运行图标来启动项目。


640.png


  • 大功告成,浏览器访问 http://localhost:3000/,如下所示。


640.png


集成Vue周边库


我们将Vue CLI初始化的项目文件替换到用vite初始化的项目中去,然后修改packge.json中的相关依赖,然后重新安装依赖即可。


具体过程如下:


  • 替换文件,替换后的项目目录如下所示。


640.png


  • package.json中提取我们需要的依赖,提取后的文件下。


{
  "name": "vite-project",
  "version": "0.1.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0-0",
    "vue-class-component": "^8.0.0-0",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "vite": "^1.0.0-rc.1",
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/compiler-sfc": "^3.0.0-0",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "eslint": "^6.7.2",
    "eslint-plugin-prettier": "^3.1.3",
    "eslint-plugin-vue": "^7.0.0-0",
    "node-sass": "^4.12.0",
    "prettier": "^1.19.1",
    "sass-loader": "^8.0.2",
    "typescript": "~3.9.3"
  },
  "license": "MIT"
}



640.png


8abcc9f5b934568e54c0229c6663866c


  • 启动项目,没报错,嘴角疯狂上扬。


640.png


  • 浏览器访问后,空白页面,打开console后,发现main.js 404


640.png


难搞,找不到main.js,那我把main.ts后缀改一下试试。将后缀改成js后,文件是不报错404了,但是又有了新的错误。


640.png


vite服务500和@别名无法识别,于是我打开ide的控制台看了错误,大概是scss的错,vite还没支持scss。


640.png


scss不支持,别名不识别,网上找了一圈也没找到解决方案,这些最基础的东西都无法被vite支持,那它就不能用在项目中了,于是我放弃了。


综合上述,vite要走的路还有很多,等它在社区成熟了,再将它应用到项目中吧。


使用Vue Cli构建项目


由于vite的不合适,我们还是继续选择用webpack,此处我们选择用Vue CLI 4.5来创建项目。


初始化项目


  • 在终端进入项目目录,执行命令:vue create chat-system-vue3该命令用于创建一个名为chat-system-vue3的项目。


640.png


  • 创建完成后,如下所示。


640.png


  • IDE打开项目,打开package.json文件,查看项目启动命令或者直接点编译器的运行按钮。


640.png


  • OK,大功告成,打开浏览器,访问终端的内网地址。


640.png


解决报错问题


在浏览CLI默认创建的demo时,打开main.js文件发现其中App.vue文件报类型错误,无法推导出具体的类型。


640.png


一开始,我也懵逼,想起了Vue文档所说的,启用TypeScript必须要让 TypeScript 正确推断 Vue 组件选项中的类型,需要使用 defineComponent


640.png


App.vue文件代码如下:


<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view />
</template>
<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>


观察代码后我们发现CLI生成的代码没有包含文档中所描述的代码,因此我们将其补充上,然后导出即可。


import { defineComponent } from "vue";
const Component = defineComponent({
  // 已启用类型推断
});
export default Component;


加入上述代码后,我们的代码就不报错了。


640.png


根据官网描述,我们可以在defineComponent的包裹中写组件的逻辑代码,但是我看了CIL提供的demo的Home组件后发现,他的写法如下。


export default class Home extends Vue {}


在项目的src目录下有一个名为shims-vue.d.ts的文件,它声明了所有vue文件的返回类型,因此我们可以按照上述方法来写。该声明文件代码如下。


declare module "*.vue" {
  import { defineComponent } from "vue";
  const component: ReturnType<typeof defineComponent>;
  export default component;
}


这样的写法看起来更符合TypeScript,不过这种写法写法只支持部分属性,同样的我们组件的逻辑代码写在类内部即可,那么将刚才App.vue文件中做的更改也应用到此处,如下所示。


<script lang="ts">
import { Vue } from "vue-class-component";
export default class App extends Vue {}
</script>


class写法支持的属性如下图所示:


640.png


                                       image-20201009210815033


配置IDE


此处内容仅适用于webstorm,如果编辑器是其他的可跳过本部分。


我们在项目中集成了eslintprettier,默认情况下webstorm是没有启用这两个东西的,需要我们自己手动开启。


  • 打开webstorm的配置菜单,如下所示


640.png


                                   image-20201006153458084


  • 搜索eslint,按照下图所示进行配置,配置完成后点APPLYOK即可。


640.png

                                image-20201006153031544


  • 搜索prettier,按照下图所示进行配置,配置完成后点APPLYOK即可。


640.png

                              image-20201006153654226


配置完上面的内容后,还有一个问题,在组件上用v-ifv-for等vue指令时没有提示,这是因为webstorm没法正确读取node_modules包,按照下述操作即可解决这一问题。


640.png

                               image-20201006154114315


执行上述操作后,等待时间根据cpu性能而定,届时电脑会发热。这都是正常现象


640.png

                           image-20201006154306682


成功后,我们发现编辑器已经可以正常识别v-指令了,并且给了相应的提示。


640.png

                                 image-20201006154454592


项目目录对比


按照上述步骤,即可创建一个vue3的项目,接下来我们将需要重构的vue2项目的目录与上面创建的项目进行下目录对比。


  • 如下所示,为vue2.0项目的目录


640.png

                             image-20201006162826706


  • 如下所示,为vue3.0项目的目录


640.png

                                image-20201006162936370


仔细观察后,我们发现在目录上并没有什么大的区别,只是多了typescript的配置文件和项目内使用ts的时辅助文件。


项目重构


接下来,我们来一步步把vue2项目的文件迁移到vue3项目中,修改不合适的地方,让其适配vue3.0。


适配路由配置


我们先从路由配置文件开始适配,打开vue3项目的router/index.ts文件,发现有一个报错,报错如下。


640.png

                            image-20201006215331894


错误信息是类型没被推导出来,我看了下面路由的写法后,盲猜它需要用函数返回,于是试了下,还真就是这样,正确的路由写法如下。


{
    path: "/",
    name: "Home",
    component: () => Home
  }


整体的路由配置文件代码如下:


import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import Home from "../views/Home.vue";
const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    name: "Home",
    component: () => Home
  },
  {
    path: "/about",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue")
  }
];
const router = createRouter({
  history: createWebHashHistory(),
  routes
});
export default router;


我们再来看看vue2项目中的路由配置,为了简单起见我摘抄了部分代码过来,如下所示。


import Vue from 'vue'
import VueRouter from 'vue-router'
import MsgList from '../views/msg-list'
import Login from "../views/login"
import MainBody from '../components/main-body'
Vue.use(VueRouter);
const routes = [
    {
        path: '/',
        redirect: '/contents/message/message',
    },
    {
        name: 'contents',
        path: '/contents/:thisStatus',
        // 重定向到嵌套路由
        redirect: '/contents/:thisStatus/:thisStatus/',
        components: {
            mainArea: MainBody
        },
        props: {
            mainArea: true
        },
        children: [
            {
                path: 'message',
                components: {
                    msgList: MsgList
                }
            }
        ],
    },
    {
        name: 'login',
        path: "/login",
        components: {
            login:Login
        }
    }
];
const router = new VueRouter({
    // mode: 'history',
    routes,
});
export default router


经过观察后,它们的不同点如下:


  • Vue.use(VueRouter)这种写法被移除
  • new VueRouter({})写法改为了createRouter({})
  • hash模式和history模式声明由原先的mode选项变更为了createWebHashHistory()createWebHistory()更加语义化了
  • 声明路由时多了ts的类型注解Array<RouteRecordRaw>


知道它们的区别后,我们就可以对路由进行适配和迁移了,迁移完成的路由配置文件:router/index.ts


这里有个小坑,路由懒加载的时候必须给他返回一个函数。例如:component: () => import("../views/msg-list.vue")。不然就会报黄色警告。


640.png

                              image-20201015223425458


640.png

                           image-20201015223525227


适配Vuex配置


接下来我们来看看两个版本在vuex使用上的区别,如下所示为vue3的vuex配置。


import { createStore } from "vuex";
export default createStore({
  state: {},
  mutations: {},
  actions: {},
  modules: {}
});


我们再来看看vue2项目中的vuex配置,为了简洁起见,我只列出了大体代码。


import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})


经过对比后,我们发现的不同点如下所示:


  • 按需导入import { createStore } from "vuex",移除了之前的整个导入import Vuex from 'vuex'
  • 移除了Vue.use(Vuex)的写法
  • 导出时丢弃之前的new Vuex.Store写法,改用了createStore写法。


知道上述不同点后,我们就可以对代码进行适配和迁移了,迁移完成的vuex配置文件:store/index.ts

相关文章
|
1天前
|
JavaScript API UED
Vue3中的Suspense组件有什么用?
Vue3中的Suspense组件有什么用?
15 6
|
1天前
|
JavaScript 前端开发 索引
Vue3基础之v-if条件与 v-for循环
Vue3基础之v-if条件与 v-for循环
5 0
|
1天前
|
JavaScript
Vue3基础之v-bind与v-on
Vue3基础之v-bind与v-on
8 0
|
1天前
|
JavaScript 测试技术 API
Vue3中定义变量是选择ref还是reactive?
Vue3中定义变量是选择ref还是reactive?
11 2
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
17 1
|
1天前
|
JavaScript 前端开发
vue2升级到vue3的一些使用注意事项记录(四)
vue2升级到vue3的一些使用注意事项记录(四)
12 0
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
13 0
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable多租户机制
ruoyi-nbcio-plus基于vue3的flowable多租户机制
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
|
JavaScript Java 物联网
现有vue项目seo优化
现有vue项目seo优化