vue2项目 vue-cli-service转vite

551 阅读4分钟

vue2 转 vite 流程

目前负责的后台系统项目由老的vue2项目拆出,因为在其他项目中开发环境使用过vite,效率很高,考虑将此项目开发和生产都转为vite。

安装

安装 vite : yarn add vite

安装支持vue2所需的插件:yarn add vite-plugin-vue2

新建vite.config.js

import { createVuePlugin } from 'vite-plugin-vue2'
import { defineConfig, loadEnv } from "vite";
import { resolve } from 'path'
export default ({ command, mode }) => {
    return defineConfig({
        base: './',
        plugins: [
            createVuePlugin()
        ],
        resolve: {
            alias: [{ find: '@', replacement: resolve(__dirname, 'src') },
            { find: '@assets', replacement: resolve(__dirname, 'src/assets') },
            { find: '@utils', replacement: resolve(__dirname, 'src/utils') },
            { find: '@plugs', replacement: resolve(__dirname, 'src/plugs') },
            { find: '@theme', replacement: resolve(__dirname, 'src/theme') },
            { find: '@pages', replacement: resolve(__dirname, 'src/pages') },
            { find: '@constants', replacement: resolve(__dirname, 'src/constants') },
            { find: '@components', replacement: resolve(__dirname, 'src/components') }],
        },
        // css预处理器配置
        css: {
            preprocessorOptions: {
                less: {
                    javascriptEnabled: true
                },
            }
        },
        // 预览配置
        preview: {
            open: true, // 在服务器启动时自动在浏览器中打开应用程序
            host: '0.0.0.0',
            port: '4888'
        },
        // 本地运行配置,及反向代理配置
        server: {
            open: true, // 在服务器启动时自动在浏览器中打开应用程序
            host: '0.0.0.0',
            port: '3888',
            proxy: {
                '/hqrs': {
                    target: 'http://10.181.24.54:9610',
                    changeOrigin: true
                }
            }
        },
    })
}

新建index.html

vue-cli默认入口文件是放在public目录下面,vite是在根目录,所以要在根目录新建,或者修改vite.config的root。

index.html添加<script type="module" src="/src/main.js"></script>

项目启动

现在可以修改启动项为'serve': 'vite'执行yarn serve 发现报错

问题1:环境变量

这是项目内部封装的请求库,使用了.env环境变量文件配置一些域名、鉴权信息,但是vite项目内获取环境变量是用import.meta.env.VITE.XXX的方式,所以需要在配置文件中使用vite的loadEnv获取环境变量 并用 define 配置做替换, 另外就是环境变量一定要是VITE_前缀的才能被获取

import { defineConfig, loadEnv } from "vite";
export default ({ command, mode }) => {
    let env = loadEnv(mode, process.cwd())
    env = Object.keys(env).reduce((pre,cur)=>{
        pre[cur.replace('VITE_', '')] = env[cur]
        return pre
    },{})
    return defineConfig({
        define: {
            'process.env': env
        },
        ...
    })
})

问题2:cjs改为esm

这个原因是webpack使用的CommonJS模块化,可以使用require。vite使用的ESM,所有require注入的地方都要修改,上图报错的位置在路由

new VueRouter({
  routes:[{
    title: '登录',
    path: '/login',
    name: 'login',
    component: resolve => require(['../pages/login/index.vue'], resolve)
  },
  ...]
})

改为

new VueRouter({
  routes:[{
    title: '登录',
    path: '/login',
    name: 'login',
    component: resolve => import('../pages/login/index.vue')
  },
  ...]
})

问题3:.vue后缀

经过上面的修改,项目启动成功,但是部分页面报错

vite不推荐.vue后缀省略 原本项目大部分都不会加 很头疼 可以在vite.config resolve配置中添加extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']配置解决此问题,但貌似不是所有版本支持,我的vite版本为2.9.5 可以使用。

兼容ie11

vite使用的esbuild构建,构建出来的文件模块也是esm的,只能支持现代浏览器,需要支持ie的需要使用官方提供的插件 @vitejs/plugin-legacy

开发环境就算了啊,没法兼容的,开发咱就用正常浏览器就可以了。

安装 yarn add @vitejs/plugin-legacy

修改vite.config.js

import legacy from '@vitejs/plugin-legacy'
export default ({ command, mode }) => {
    return defineConfig({
        ...,
        plugins: [
            ...,
            legacy({
                targets: ['ie >= 11'],
                additionalLegacyPolyfills: ['regenerator-runtime/runtime']
            })
        ],
        ...
    })
})

插件改写

至此项目开发环境就完全跑通了,但是原项目发布是项目内开发了一个插件,会在webpack编译完成后执行发布流程。

那现在生产环境想要使用vite必须将此插件改为vite版本的,了解了下 修改的东西其实不多 vite的插件是rollup的扩展有一些自己内置的钩子 我这边也用不到

vite插件就是导出一个函数 函数返回插件对象,包括name、enforce,apply和一些钩子,enforce可以控制插件顺序我这边也用不到,apply是指定开发环境的,因为我这边插件是用来发布代码的,所以指定为build才执行。

一开始查阅资料是没有报错的情况下 buildEnd就会是最后一个钩子 实际使用会在rendering chunks前执行 这个时候文件还没有生成,所以改用了closeBundle,可以保证是最后执行。又大概查了下 buildEnd是在执行generate或者write之前被调用,这块确实不熟悉,但目前使用没啥问题。

export default function XXX() {
    return {
        name: 'xxx',
        apply: 'build',
        closeBundle(err) {
          // 发布流程代码
          ...
        }
    }
}

这里执行又出现问题,发布的时候也会使用环境变量文件配置的环境变量,但是vite并没有给process.env注入,上面说到的使用define做替换只是在项目层面做了静态替换,不影响插件的,所以这里需要处理。

一开始我是考虑直接把使用loadEnv获取到的环境变量直接传参给插件,但总觉得有些别扭,突然想到可以了解下vue-cli是如何读取环境变量文件的,经过查阅,了解到可以使用dotenv读取.env并注入process,这样连.env内数据的VITE_前缀都不用加了

安装dotenv后 将vite.config修改

import dotenv from 'dotenv'
dotenv.config({ path: '.env.development' });
export default ({ command, mode }) => {
    return defineConfig({
        define: {
            'process.env': process.env
        },
        ...
    })
})

最后

至此,老项目迁移vite也就算是成功了,难度不算大,但中间还是被一些问题牵制了很长时间。成果还是挺显著的,尤其在开发环境,效率提高很多