vue2迁移vite

1,629 阅读6分钟

vite发布前:学不动了。。

vite使用后:真香!!ESM YYDS!

前言

为什么选vite

在浏览器支持 ES 模块之前,我们见证了诸如 webpackRollup 和 Parcel 等工具的变迁,它们极大地改善了前端开发者的开发体验。然而,当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 —— 使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。

Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。

迁移前后对比

类别迁移前webpack4使用vite后
启动4分钟2秒
热更新3秒毫秒级
打包4分钟1.5分钟

可以看到,这个提升是巨大的,之前启动项目以及打包的时间非常长。当我们开发多个项目,同时另一个项目需要修改或者定位一个紧急的bug时,而当前的项目开发又比较紧急;这个时候启动项目需要好几分钟是非常操蛋的。

提升性能后,不管是对于开发体验,还是提高开发效率,都有很大的帮助。

迁移流程

安装依赖

npm i vite vite-plugin-vue2 vite-plugin-svg-icons @originjs/vite-plugin-commonjs -D

vite:代替webpack的打包工具

vite-plugin-vue2:支持vue2语法的插件

vite-plugin-svg-icons:批量处理svg的插件,替换webpack的svg-sprite-loader

@originjs/vite-plugin-commonjs:兼容处理commonjs模块

文件迁移

  1. 将index.html从public迁移到根目录下,并删除webpack设置,如<%= webpackConfig.name %>等 添加script标签type="module",并引入src下的main.js

    index.png

  2. 修改package.json中的scripts,启动和打包方式使用vite

    "serve": "vite",

    "build": "vite build",

  3. 添加vite.config.js配置文件

    不知道具体怎么配置的可以参考官方文档vitejs.cn/config/

    你也可以把vue.config.js直接改名vite.config.js,并在此基础上做修改,导出语法修改成export default,同时对里面的webpack的配置做删减,只有一小部分的可以复用。

    添加plugins配置

    首先导入我们上面安装的依赖插件,并放入到plugins的配置里面

    plugin.png

    如果你的项目中使用了vue中的jsx语法,需要在createVuePlugin方法中传入{ jsx: true },同时在对应的模块中的script标签添加lang="jsx",否则会报错。

    还有,如果你使用了vite-plugin-svg-icons插件,还需要在main.js中加入 import "virtual:svg-icons-register";

    添加resolve配置

    在这里我们需要把别名的配置放在这里,以及导入时想要省略的扩展名列表(vite默认可忽略的扩展名是'.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'),如果不加入扩展名的配置,vite将不会识别引入'xx/index'的vue文件

    resolve.png

    添加css配置

    我的项目里只用到了css预处理,如果你的项目中还用到了CSS modules或者postcss的配置,可以参考官方文档。

    css.png 这里提一嘴,有的文件中引入了scss文件,使用了~前缀,而vite解析不了,所以没有找到对应的文件。那我们要做的就是把~前缀删除掉,同时确保路径的正确性。

    开发服务器配置

    这里可以把vue.config.js中的devServer直接复制过来,放到server里。当然也不只是名字变了一下,当然大部分的配置还是很相似,直接拿过来用也不会出什么问题。

    server.png

OK,那我们启动项目吧

好的,我们命令行输入npm run serve,等待项目启动。在这个过程中,我们先去抽根烟吹个比吧。纳尼???启动好了???仿佛失去了一个可以划水的理由,手动狗头。

先别偷着乐,启动后你可能会看到控制台报了错,比如使用了require语法,或者是一些遗漏没有修改的模块。

那现在,我们需要把之前没修改的文件修改好,还有把require语法替换成em的import语法require.context替换成vite提供的import.meta.glob方法。

如果你的项目对一些ui框架中的某个组件做了定制化(复制了出来,单独做了修改),你可能还会发现引入路径的问题。貌似扩展名配置没起作用,当然这个不是你的问题。那我们现在应该怎么办呢?如果你是全局引入,那我们就不需要在手动引入组件了,直接删掉就ok;如果你是按需引入,直接在main.js里引入或者在当前文件,从模块中引入而非路径中。

打包

如果你解决了以上的报错问题,恭喜你。可以愉快的开发了。

接着我们在试着打包一下,命令行输入npm run build,如果你没有报错,也打包成功了,那恭喜你。

当然,这里还没有结束。因为我们知道,目前还有很多的npm包还是使用的commonjs规范。如果你的项目中有这样的情况,打包是失败的。

这时,我们需要告诉vite,其实是rollup。这些文件中含有commonjs模块。 我们需要在vite.config.js中加入打包的配置。

build.png 接着我们再试着打包。

ok,打包完成。

总结

现在vite的生态也日趋成熟,已经可以满足于大部分业务场景了,不过在迁移前还是尽量要做下调研,看目前vite生态是否满足本项目中一些定制化或者特殊的场景。

本文记录了楼主在项目迁移过程中遇到的问题,遇到的问题肯定只是webpack迁移vite的部分问题,以后在迁移其他项目时候遇到新的问题也会补充进来。

本次迁移最终vite配置

import { createVuePlugin } from 'vite-plugin-vue2'
import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

import path from 'path'

function resolve(dir) {
  return path.join(__dirname, dir)
}

const port = process.env.port || process.env.npm_config_port || 9528 // dev port

export default {
  base: '/',
  lintOnSave: false,
  productionSourceMap: false,
  build: {
    commonjsOptions: { include: ['.cjs', 'node_modules/**/*'] },
    outDir: 'dist',
    assetsDir: 'static',
    sourcemap: true
  },
  server: {
    port: port,
    open: true,
    proxy: {
      '/v1': {
        target: 'https://111.111.111.111',
        ws: true,
        secure: false,
        changeOrigin: true,
        pathRequiresRewrite: {
          '^/v1': '/'
        }
      }
    }
  },
  plugins: [
    createVuePlugin({ jsx: true }),
    viteCommonjs(),
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), 'src/icons')],
      // 指定symbolId格式
      symbolId: 'icon-[dir]-[name]',

      /**
       * 自定义插入位置
       * @default: body-last
       */
      inject: 'body-first',

      /**
       * custom dom id
       * @default: __svg__icons__dom__
       */
      customDomId: '__svg__icons__dom__'
    })
  ],
  resolve: {
    alias: [
      { find: '@', replacement: resolve('src') },
      { find: '@json', replacement: '/json/' },
      { find: '@assets', replacement: '/src/assets/' },
      { find: '@com', replacement: '/src/components/' },
      { find: '@api', replacement: '/src/api/' },
      { find: '@store', replacement: '/src/store/' },
      { find: '@views', replacement: '/src/views/' },
      { find: '@utils', replacement: '/src/utils/' }
    ],
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.cjs']
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/base/_variables.scss";`
      }
    }
  }
}