vue2项目迁移到 vite2(分享遇到的问题)

3,345 阅读5分钟

背景

项目本身是vue2全家桶,代码差不多一年前,涉及到的库不是很多,比较标准的后台admin项目

天天看着都说vite好vite快,有的文章甚至达到了开发环境10倍,然后看文章变更的也不多,内心蠢蠢欲动0 0

今年这段时间正好有空,正好也是vite升级到了2代目,脱离了vue3的强依赖,于是尝试下非主流程公司业务从vue-cli迁移到vite

题外

看大家帖子都说多简单,变更的就那么多点,是我们的项目太奇怪了?

在过程中基本是一步一个坑,果然还是自己太菜了TT

迁移过程

1.配置文件与处理vue

配置文件和webpack一样,在根目录下创建 vite.config.ts

npm i -D vite

配置文件长的也很像vue.config

import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    // ...
  ],
})

awesome-vite插件地址 在这边找到vue的对应插件vite-plugin-vue2

npm i -D vite-plugin-vue2
。。。
plugins: [
    createVuePlugin({
      jsx: true,//这个我感觉没用?还是我的使用方式有问题
    }),
  ],
。。。
Q1:vue插件的这个jsx是怎么生效能处理哪几个问题,看起来是通过babel-preset-jsx?处理的

2.入口与 HTML 文件

这里和webpack有些不同了,vite同样需要入口文件,但是使用的方式是从html进入

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=1024,initial-scale=1.0" />
  <title>嘻嘻嘻</title>
</head>

<script>
  window.process = {}; //这里解决了path引入报错的问题
</script>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
  <!-- built files will be auto injected -->
</body>

</html>

因为原有项目html文件是在public文件架下,而且是多入口,所以配置文件要修改 对应的入口

 build: {
    rollupOptions: {
      input: {
        main: path.resolve(__dirname, 'public/index.html')
      },
    },
  }

诶,没想到吧,不行!好奇为什么。虽然最后还是乖乖把主index放到了根目录

Q2:这个问题晚点也要研究下
Q3:window.process = {};不加这个我的path会报错 没有process

3.环境变量

webpack为我们提供了process.env去访问环境变量,区分各个环境

const PRO_HOST = process.env.PRO === 'xxx'
  ? 'aaa'
  : 'bbb';

vite 仍然支持环境变量的使用,但是提供了另一套import.meta.env来代替process.env去访问环境变量: 也提供了根目录下.env文件去增加额外环境变量

4.替换 CommonJS 以及各种引入问题

1.替换commonJs 这一块是参考掘金另一个老哥的,说白了是require换成import

2.样式引入的替换

@import '~@/styles/mixin.scss';
@import '~@/styles/variables.scss';
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";

直接写成@import '@/styles/variables.scss';就可以了,不再需要波浪号

$--font-path: 'element-ui/lib/theme-chalk/fonts';
@import "element-ui/packages/theme-chalk/src/index";

3./deep/的支持

vite对css预处理器提供了插件的支持,但是需要安装预处理器。所以原有的sass-loader就不需要了,只需要装个sass的预处理器就可以,安装最新的后发现不支持/deep/,那就按照最新的::v-deep走呗。顺带对这个vue专属语法有了根深一层的认识

4.Glob 导入 (在这边遇到很多坑)

说到这,是为了解决路由和store的问题,处于webpack的方便,之前路由的写法是按照文件夹自动导入的,如下代码:

export const basicRoutes = require
  .context('@/views/basic', true, /\/index\.vue$/)
  .keys()
  .map(url => url.replace(/^\.\//, '').replace(/\/index\.vue$/, ''))
  .map(pathName => {
    return {
      path: `/${pathName}`,
      name: pathName,
      component: () =>
        import(/* webpackChunkName: "[request]" */ `@/views/basic/${pathName}/index.vue`),
    };
  });

从webpack切换到vite后,require.context不能再用了,于是看文档找到import.meta.globEager这个vite提供的导入方案,分为glob和globEager异步和同步两种

依旧是先看代码后说问题

let files = import.meta.globEager('/src/views/division/*/index.vue');
export const divisionRoutes = Object.keys(files)
  .map(url =>
    url
      .replace(/\/index\.vue$/, '')
      .replace(/src([a-zA-Z\_]*\/)*/, '')
      .replace(/\//, '')//原谅我丑陋的正则
  )
  .map(pathName => {
    return {
      path: `/${pathName}`,
      name: pathName,
      component: files[`/src/views/division/${pathName}/index.vue`].default,
    };
  });

这里一共遇到了2个问题,应该有更好的解决方案,但是出于先解决问题只是勉强能用

  1. import.meta.globEager('/src/views/division/*/index.vue')的引入是modules组成的对象,和原来的路径不太一样
  2. 这里component的导入,一开始用的是import导入,然后遇到问题

image.png 安装@rollup/plugin-dynamic-import-vars插件后 在

import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';

 plugins: [
    createVuePlugin({
      jsx: true,
    }),
    injectHtml({
      injectData: {
        title: '用户管理系统',
      },
    }),
    dynamicImportVars(),
  ],

结果反而报错。由于报错在vite,于是想着引入的直接是modules,干脆直接引入算了,于是就有了上面的代码,成功解决问题

component: files[`/src/views/division/${pathName}/index.vue`].default,
Q4: 这里的解决方案有待商榷,待学习后尝试解决

5.jsx的问题

vue-cli是自动引入的babel的,所以在里面jsx是可以直接用的,比如下面的代码

vnodes.push(<svg-icon icon-class={icon} />);

但是这在vite当中就不识别了

image.png

没有转换成功 开篇提到了引入的vue2插件,发现里面有jsx options但是打开后没有用 ,可能是我打开方式不对吧

createVuePlugin({
   jsx: true,//这个我感觉没用?还是我的使用方式有问题
}),

最后是通过改为createElement方法去解决的

render(h, context) {
    const { icon, title } = context.props;
    const vnodes = [];

    if (icon) {
      const elHtml = h('svg-icon', {
        attrs: {
          'icon-class': icon,
        },
      });
      vnodes.push(elHtml);
    }

    if (title) {
      const elHtml = h(
        'span',
        {
          attrs: {
            slot: title,
            class: 'system-menu-title',
          },
        },
        title
      );
      vnodes.push(elHtml);
    }
    return vnodes;
  },
Q5: 晚点试试看通过rollup-plugin-babel外加@vue/babel-preset-jsx通过插件的方式支持jsx

6.方法上的装饰器的使用

原有项目为了实现一些控制请求重复提交和其他的一些需求,通过装饰器的方式写了一些方法,用到的时候方法上直接加上就好了

但是在vite中遇到了问题,查了相关资料也改了build.target发现还是不行,现在只好先注释掉处理其他问题

Q6.装饰器的使用
@debounceDecorator()
async getSearchList() {}

5.alias

话不多说,vite提供的配置,按照要求加上就好

  resolve: {
    alias: {
      '@': path.resolve(__dirname, '/src'),
    },
  },

7.生产环境

等待更新ing

8.babel plugin

打算下尝试下插件方式解决上面的一些问题

image.png

结果

差不多到现在能用了,还有一些样式覆盖的都是小问题了,检查了下基本功能都在,明天着重解决装饰器和jsx的问题

总体来说,使用体验上没啥大的区别,编译速度确实是快了很多, 但是默认的提示语里reload不包含时间,后面加xN代表数量,只有一句话,而且闪动的很快,还不太习惯

image.png 初始的编译

image.png 对比原来差不多七八秒是快了很多,

浏览器连接时间:

image.png

暂时看,嗯,很香0 0,在报错和异常上再挖掘下不是不可以作为生产用