前端工程化--十万行项目从Webpack5迁移到Vite2

4,015 阅读6分钟

前不久内推了一位朋友进虾皮,顺便发一下他求职成功的敲门砖

前言

在互联网呆了一年多,发现从普通的工程师进阶为高级的工程师需要在技术上有所突破,加上在年后听了一位大佬的分享,感觉Vite会是今年的技术热点,于是从年后就一直捣鼓,学以致用地用工作上的项目试用了一下,不得不说es build真是太快太酸爽啦。在九月份的时候,给shopee投了简历,就因为这段vite实践的经历,拿到了四十万的offer,在这里分享给大家。

PS 卖个小广告,可以帮助内推虾皮,一旦转正可以对半分内推费,虾皮的内推费有一万五呢,此外每年有15天带薪年假,可香了,欢迎有跳槽需要的朋友

关于Vite的介绍可以看我之前的这篇文章,里面对Vite的各种能力做了简单介绍。

配置Vite

主要就是配置路径映射、css模块路径映射,修改入口html文件、配置热更新插件等

//import fs from 'fs'
import * as path from 'path';
import pkg from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
const { defineConfig } = pkg;

const SRC_PATH = path.resolve(__dirname, './src');
export default defineConfig({
  root: SRC_PATH,
  css: {
    modules: {
      globalModulePaths: [`${SRC_PATH}/styles/common/`],
    },
    preprocessorOptions: {
      scss: {
        includePaths: [`${SRC_PATH}/styles/common/`],
      },
      sass: {
        includePaths: [`${SRC_PATH}/styles/common/`],
      },
    },
  },
  resolve: {
    dedupe: [path.resolve(__dirname, './node_modules/react-pdf')],
    alias: [
      {
        find: 'assets/',
        replacement: `${SRC_PATH}/assets/`,
      },
      {
        find: 'components/',
        replacement: `${SRC_PATH}/components/`,
      },
      {
        find: 'consts/',
        replacement: `${SRC_PATH}/consts/`,
      },
      {
        find: 'data/',
        replacement: `${SRC_PATH}/data/`,
      },
    ],
  },
  plugins: [reactRefresh()],
});

修改环境变量

主要的问题有两个:

1.vite要求环境变量存储在".module.env"的环境变量文件中;而目前存储在json中,通过const env = require(${env}.json);的方式调用

2.vite对环境变量的访问需要通过import.meta.环境变量名来访问,而目前对环境变量的访问主要通过env对象

因此,可以把envs的路径别名指向新的envs文件,在文件使用import.meta.env读出全部的环境变量封装为新的env对象,再export给外部调用,从而避免修改环境变量的调用处。

新的env.js文件

export const ENV_VAR = import.meta.env.VITE_ENV_VAR;
export default {
    ENV_VAR,
}

这里主要是把webpack的环境变量适配成vite的环境变量

修改文件后缀

项目中有很多在js文件中使用jsx的情况,使用esbuild的话会报错,因此需要手工把报错文件的后缀修改(升级ts时同样需要进行该工作)。可以考虑用vscode的快捷修复功能修复该问题。

这里暂时没有想到好的自动化解决方案。

修改样式

主要的问题如下

  1. vite只支持对className属性,而目前项目中写的是styleName,然后通过babel转成className,因此需要把全部styleName都改成className,共计1100多处。其中有大概100处需要手动修改,其他均可以通过简单的正则替换。(升级ts时同样需要进行该工作)

附上我用的正则 /styleName='([a-zA-Z0-9-_]*)'$/

  1. vite需要把样式文件后缀加上.module,如*.module.scss,需要使用脚本替换文件后缀,并替换代码中引用的地方
  2. 由于公共样式的文件名也会被修改,因此.scss文件中对公共样式文件的引用也需要修改

修改路由

由于项目中使用的是React.lazy + import()引入文件,已经实现了懒加载,而且React中没法只用es module 的import()导入组件(会报错),因此对于路由的代码并没有作出修改。

适配依赖库

项目依赖中有部分缺乏维护的个人项目,这些项目中会存在部分不符合es module的语法,vite运行时会报错,因此需要对依赖库进行适配。

有三种做法

  1. 可以使用monorepo的方式,把依赖库的代码fork到项目中,成为一个子工程,在子工程中对代码做适配,然后作为项目源码链接到主项目中。
  2. 直接把库的代码复制到项目中,但是可能由于依赖发生变化而导致行为异常
  3. 替换为知名度高、大团队维护的库,并修改对库的调用

修改项目代码

这里主要是处理一下代码中的required,比如

const request = require(../request);

改成

import request from '../request';

主要看项目运行时的报错,面向报错编程

部署

这里有两种方案:

  • 第一种方案: 仅在本地开发环境使用vite 如果采取这种方式,则改造已经完成了。目前这也是业内比较多的一种做法,好处是改动小,且vite不支持webpack打包,而rollup在代码分割等一些生产上的特性不如webpack,因此生产上打包还是采用webpack更好。

  • 第二种方案: 本地和线上都采用vite

我们知道vite只是一个代码加载的工具,但是它不能打包代码,vite官方推荐是采用rollup进行打包,那么从webpack到rollup的配置修改要如何处理呢wp2vite这个工具能根据webpack配置生成rollup的配置

其次,对于部分webpack的插件,也要寻找替代的方案,比如webpack中的@sentry/webpack-plugin插件,该插件用于打包时上传sourcemap,可以在打包过程中使用shell脚本完成sourcemap的上传。

此外还有fork-ts-checker-webpack-plugin插件,该插件用于把ts编译错误显示到屏幕上。由于vite使用esbuild完成ts的转译,虽然速度快但是失去了类型判断的能力。

  1. 可以要求成员的vscode安装插件,高亮ts类型错误

  2. 在git pre-commit钩子中拒绝带ts类型错误的提交。

  3. 配置live环境打包时遇到错误终止构建

考虑到单词改造的代码量非常大,可能引入bug,因此建议单次仅改造一个web项目,并采用灰度发布的方式,尽可能降低引入bug的危害

对改造过程不感兴趣的朋友可以直接看结尾

在互联网公司混了整整一年,不得不说互联网公司也没有想象中的纯粹,想要长远的发展,除了技术能力之外人际关系也不容忽视。

所谓技术,我觉得有以下三个阶段

  1. 写业务,把业务写好,减少自己的bug,增加稳定性等,这对应的是初级的工程师
  2. 参照业界主流的技术,引入到自己工作的项目中,比如我就把vite应用到了工作中,这里就算是高级工程师了
  3. 寻找工作中的需求,比如我们熟悉的antd、git、腾讯会议这种,都是工作中的需求,但是挖掘出来并发展成一个可以养活一个部门甚至养活一个公司的产品,但是这种难度非常高,到这个阶段基本都是管理层