坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.6.5

前言

我工作不饱和(误),所以找点事做,俗称没事找事~

其实是早有预谋,选在这个时机是我怕以后没机会了


当前配置

该项目是基于vue-cli创建的webpack-vue2的开发环境,package.json配置如下:

由于代码是公司的资产,所以这里简单的说下配置(vue.config.js + babel.config.js):

  1. 使用html-webpack-plugin,插入动态内容到模板里,比如开发环境引用的资源是src,生产环境得是min
  2. 配置devServer代理部分接口
  3. 配置css.loaderOptions.postcssautoprefixer兼容css
  4. 配置css.less,覆盖组件库lib_b定义的主题色变量(lib_b是用less预处理样式)
  5. 定义一些alias
  6. 由于项目中包含一些ts文件,所以使用babel-loader + @babel/preset-typescript处理
  7. 配置pages,多页面应用
  8. 使用transpileDependencies帮忙处理一些自行封装的第三方库
  9. babel.config.js中配置@vue/cli-plugin-babel,和vue-cli绑定的babel-preset版本

这里还是贴demo代码,避免大家仅看文字看不太明白:

vue.config.js

babel.config.js

ok,基本就介绍到这里,下面开始我们的改造流程。


引入

注意:此时的nodejs版本切换至v18.8.0

vite-plugin-vue2

vitejs/vite-plugin-vue2: Vite plugin for Vue 2.7 (github.com)

因为我们的vue2.6.14,所以我们不能用@vitejs/plugin-vue,又因为我们只能使用vite-plugin-vue2

vite

Vite

因为我们只能使用vite-plugin-vue2,而这个依赖仅支持vite5以下的环境,所以这里选择vite4.5.3

注意此时node版本至少要v18

vite-plugin-html

vite-plugin-html

这个包对标html-webpack-plugin,主要用来实现多页面 + 动态模板

vite-plugin-require

vite-plugin-require

因为项目中大量使用了webpackrequire,要手动改挺累的,所以找了这个包用来支持这种写法。

dart-sass + sass

由于生产环境机子nodejs版本过低,所以连带着本机也只能在这个版本上下徘徊,对于sass处理器也只能使用node-sass,这货有多坑爹,相信大家都清楚。

因为要用vite4的要求之一就是nodejs版本要高于18,所以这货是肯定不能用了,自然需要平替。

这里采用dart-sasssass用来平替。

整理


配置

首先我们先去到package.json中,新增指令:

  • IS_VITE环境变量用来区分当前是什么环境。注意你一定要同步这个配置项到vue.config.js中的全局变量注册IS_VITE: false,因为生产环境还是使用的webpack编译,如果少了这个变量就会直接报错卡住。

找好依赖并安装之后,我们开始配置vite.config.js

说一下里面的一些点:

  • 之前我们通过html-webpack-plugin注入的模板数据,现在我们使用vite-plugin-html里的injectOptions.data注入,每个key对应html文件中的<%- key %>
  • define:这里用来定义业务代码中要用到的环境变量,比如我们等会要用IS_VITE区分部分业务代码(登录跳转逻辑)
  • less配置注意去掉了lessOptions的外层
  • optimizeDepsexclude对应前面的externalsinclude对应前面的transpileDependencies
  • '~': resolve(NODE_PATH),'~@': resolve(NODE_PATH),alias中多了这俩玩意儿,因为代码中存在一些样式文件是这样引入的:@import url('~@/styles/xxx.src.css'),所以需要额外再补充。
  • proxy的规则,viteproxy是基于http-proxy封装的,它里面的选项可见:https://github.com/http-party/node-http-proxy#options。和之前`vue.config.js`中的写法差不多,但是`router`变成`target`,`pathRewrite`变成`rewrite function`。
  • babel:你可以看到我这没有再配置babel,因为vite自带了babel,包括对ts的处理,所以我们并不需要额外引入。

然后是babel.config.js,由于我们是vite环境,所以不能使用@vue/cli-plugin-babel/preset,我们直接基于环境变量IS_VITE区别即可。

另外别忘了在你的.eslintrc中将IS_VITE定义为全局变量

这么配置就完成了,然后来说一些兼容性的问题。


兼容性问题

require

虽然我们用了vite-plugin-require作为替代,但该插件并不是完全支持webpack require的写法,比如:

需要调整为:

另外如果传入一个变量是绝对不行的(包括webpack require),比如:

因为require.context实际上是创建一个执行上下文,执行时再去找,如果传入一个变量,压根找不到。

The arguments passed to require.context must be literals!

文件找错问题

之前有些不规范写法,将js命名和vue文件命名写成一样的,比如:

然后在B中引入时不带后缀:

这种是webpack可行但vite不行的操作。因为webpack底层做了额外操作用来试错,而vite讲究的是原生

module.exports

业务代码中存在module.exports的导出方式,改成export default即可,webpack自身也支持这种写法。

public/index.html重命名

为啥要这么做,因为viteindex.html视作是源码,所以默认情况下会去找根文件夹里的index.html,整个服务器也是基于根目录。

当然,这不是不可以调整的。然而我们用了vite-plugin-html,这玩意儿bug还挺多,作者也没空改。。。。所以在经过一些列无意义调整后,还是采用重写public里的index.htmlpreview.html_index.html以及_preview.html

同时在根目录里新增index.htmlpreview.html以及login.html

import Vue from vue

前面说过项目中有俩vue,一个是node_modules里的,另一个是public/lib里通过script引入的。因为我们配置了externals,所以生产环境是使用lib下的,不过我发现在开发环境下,原来的配置也是用的lib下的,也就是node_modules里的vue压根没用上。

但是到了vite里,我发现它被导入了,也就是说vite先找的node_modules里的而不是script的。

因此原本代码中存在import Vue from 'vue'的写法就都需要去掉,为什么呢?因为lib_c也是要用到这个script版本的vue,然后往Vue.prototype里注入了一些内容。而业务代码中又有用到这玩意儿,所以如果不去掉就会导致找不到global vue prototype里被注入的内容。

跳转登录逻辑

原来多页面配置是基于vue-cli提供的配置项来配置的,貌似会被整合到路由里。但是通过vite-plugin-html的不行,所以我们需要调整原来的逻辑,这里采用前面全局注入IS_VITE区分

不过跳回index.html倒是不需要改,因为访问路径没有index.html也会跳到那里去。


未解决的问题

当前有一个无法解决的问题:生产环境node版本太低,连带着sass预处理器的依赖也只能是node-sass

也是因为这个问题,我们不能光明正大的添加vite依赖。

以这也导致当前接入实际开发变得有些儿戏,一旦注入了vite,也就意味着得删掉node-sass,一旦删掉node-sass,你的package.json就不能提交到本地了,会直接让生产环境编译失败。

那要怎么办呢?

复杂的操作:

  1. 在注入vite之前,备份当前package.jsonlock文件
  2. 切换node到v18,注入vite依赖,移除node-sass,添加dart-sass,也做备份
  3. 如果涉及到包更新,切换package.jsonlock文件,切换node版本,然后更新提交到本地
  4. 重复步骤1

难顶

分支

这里推荐开本机分支,平时业务代码可以在vite分支里编写,提交时合并即可(反正一般改动较大的需求也都是开分支,相信大家轻车熟路)。

一旦涉及到依赖更新,切换到master分支即可。

分支注意不要有对应的远程分支,本机即可。

但是这个方案需要考验你的git熟悉度,你不能再像平时那样add .了。

分支衍生

依旧是开分支,前面操作不变,然后把分支的package.jsonlock文件都给添加到.gitignore里,这样你又可以愉快的add .了。

目前着实没有好的方案。。


总结

本次迁移不难,难的是nodejs环境问题。