antd+react+webpack往往是以react技术栈为主的前端项目的标准组合,三者都有成熟的生态和稳定的表现,但随着前端圈的技术不断革新,号称下一代构建平台vite2的发布,webpack似乎不那么香了,为什么这么说呢,因为vite太快了。经过一段时间的尝试,决定在项目中把webpack替换成vite试试,遂写成本文分享给大家。

Vite是什么

作为本文的主角,首先简单介绍一下vite这个构建工具,该工具是尤雨溪推出的【下一代前端开发和构建工具】,vite其实也不是一个新的工具,早在一年多以前,就已经推出了很多版本,直到2.x版本的推出,在前端圈引起了足够大的震动,标志着vite的成熟和强大,这里并不打算详细介绍vite,大家可以参考官网https://cn.vitejs.dev/ 了解。

迁移过程

了解了vite这款工具之后,我们就可以着手准备做迁移工作了;

1.安装vite依赖

npm i vite antd-vite-import-plugin @vitejs/plugin-react-refresh vite-plugin-html -D

2.更新项目原有依赖项

这里我们项目使用的是dva+antd3.x作为基础的开发框架,这里我将系统的主要依赖项都升级到了最新的版本,比如dva我用的2.6.0-beta.22版本,其他附带的react、react-dom、react-router-dom及@babel/plugin-transform-runtime等相关依赖项都更新了(antd还是3.x版本,暂未更新到4.x的大版本),这一块取决于自己的实际需求;

3.项目根目录添加vite.config.js配置文件

和webpack的配置文件比起来,vite的简单了许多,而且很多功能都是内置的,比如对静态资源的处理,功能开启也比较简单,具体如下:

  1. import { defineConfig } from 'vite';
  2. import vitePluginHtml from 'vite-plugin-html';
  3. import reactRefresh from '@vitejs/plugin-react-refresh';
  4. export default defineConfig({
  5. css: {
  6. preprocessorOptions: {
  7. less: {
  8. javascriptEnabled: true,
  9. },
  10. }
  11. },
  12. publicDir: './src/configs',
  13. plugins: [
  14. reactRefresh(),
  15. antdViteImportPlugin(),
  16. vitePluginHtml({
  17. minify: true,
  18. inject: {
  19. injectData: {
  20. title: 'vite-react-example',
  21. injectScript: '<script src="/configs.js"></script>', // publicDir作为根目录
  22. },
  23. injectOptions: {
  24. filename: './index.html', // 模板页
  25. }
  26. },
  27. }),
  28. ],
  29. server: {
  30. open: true,
  31. port: 10010,
  32. }
  33. });

这里我们使用了vite-plugin-html插件作为html-webpack-plugin的替代方案,其中需要注意injectData和injectOptions选项,injectData可以方便的往我们的模板页中插入自定义数据,injectOptions可以指定模板页,还有其他配置项可以参考https://www.npmjs.com/package/vite-plugin-html 。相应的需要改造index.html页面:

  1. <!DOCTYPE html>
  2. <head>
  3. <meta charset="utf-8">
  4. <title><%- title %></title>
  5. ......
  6. </head>
  7. <body>
  8. <div id="app"></div>
  9. <script>
  10. var global = globalThis || window; // 防止启动报错
  11. </script>
  12. <%- injectScript %>
  13. <script type="module" src="/src/index.jsx"></script>
  14. </body>
  15. </html>

和webpack有差异的是,这里我们需要手动指定一下入口文件,script的标签type为module。

4.修改文件后缀

这里的文件是以js作为后缀的react组件,在webpack构建平台下,js(x)ts(x)都是没啥问题的,但如果使用vite的话,那么最好是tsjsxtsx 的后缀文件,关于这个问题,可以看下这个issue:https://github.com/vitejs/vite/issues/1552 ,最后作者发出批量改个后缀有这么难的吐槽,算了,还是改吧,如果觉得手动改麻烦,写个脚本也不是啥难事。

5.添加启动脚本

  1. "scripts": {
  2. "dev": "vite",
  3. "build": "vite build",
  4. ......
  5. }

到这里应该就差不多了吧,但是情况却不是那么顺利,项目居然跑不起来,好吧,没有那么一帆风顺的事情,接下来我们来看下遇到的问题吧。

遇到的问题

1.decorators not support

在业务代码中,我们使用了dva提供的connect来绑定状态,形如:

  1. @connect(state =&gt; state.foo)
  2. class Foo extends React.PureComponent {
  3. ....
  4. }

但是decorators语法居然不被vite支持,关于这个问题,也有一个issus:https://github.com/vitejs/vite/issues/2349 ,目前没有一个好的解决办法,只好去掉decorators,改用常规的函数绑定了。

2.antd Unknown theme type: undefined, name: undefined

我们项目目前还是使用的antd的3.x版本,在启动时就出现了这个错误,其实主要是antd组件初始化的时候,加载了antd/es/icon/index.js文件:

  1. import * as allIcons from '@ant-design/icons/lib/dist';
  2. ......
  3. ReactIcon.add.apply(ReactIcon, _toConsumableArray(Object.keys(allIcons).map(function (key) {
  4. return allIcons[key];
  5. })));
  6. ......

'@ant-design/icons/lib/dist'导出的对象是{ default: {...} },要正确访问的形式是allIcons.default,而不是allIcons,因此导致获取不到icon的正确导出对象,关于这个问题,大家可以看下这个issue:https://github.com/ant-design/ant-design/issues/19002 ,这里要说明的一点是antd4.x版本不会出现,但是对于我们的项目来讲,目前还不会升级到4这个大版本,那么怎么解决呢,其实只要引用antd/lib下的组件,就没有这个问题了,我们可以看下antd/lib/icon/index.js:

  1. ......
  2. var allIcons = _interopRequireWildcard(require("@ant-design/icons/lib/dist"));
  3. function _interopRequireWildcard(obj) { if (obj &amp;&amp; obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" &amp;&amp; typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(); if (cache &amp;&amp; cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty &amp;&amp; Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc &amp;&amp; (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  4. ......

这里_interopRequireWildcard方法帮我们处理了导出的问题,那么修改一下babel-plugin-import的配置不就好了么,好吧,没有那么容易的,vite对babel-plugin-import支持不那么好,首先还是去vite的issues里面找找看,有一个类似的提问:https://github.com/vitejs/vite/issues/1389 ,看了下,并没有解决我的问题,里面提到的几个插件倒是给我了思路,那就自己写个vite插件去实现我们的需求呗。插件的思路很简单,就是将antd组件的引入方式进行统一的修改:

  1. ---修改前---
  2. import { Button } from 'antd';
  1. ---修改后---
  2. import Button from 'antd/lib/button';
  3. import 'antd/lib/button/style/index.css';

这里需要说明的是css样式的引入,如果引入style/index或者style/css,会出现require is not defined的问题,因为这两个js文件中使用了require,但是vite在预编译时不是node环境,当然就报错了。

关于这个插件的使用,可以参考https://www.npmjs.com/package/antd-vite-import-plugin 。

3.'default' is not exported

有时候三方依赖项加载会出错,例如'default' is not exported等,这里可以参考https://github.com/vitejs/vite/issues/2679

在实际开发过程中,还是难免遇到一些奇怪的问题,这都是尝鲜的代价。

速度之争

vite的一个优势就是快,那么和webpack相比,到底有多大的差距呢,这里我们用webpack和vite分别启动同一个本地项目:

构建工具 启动时间(ms)
vite 702ms
webpack 7093ms

这里只是一个粗略的对比,从数据上看有十倍之差,单从速度上讲,vite是很快了,根据官网的解释,Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

最后

经历过一番折腾后,觉得vite2的成熟度有所欠缺,在一些小项目中可以试试。对我而言还是决定先用webpack吧,毕竟webpack经过这么多年的发展,坑很少,而目前vite对于react来说还是不那么完美。

福禄ICH·架构组
福袋

antd+react项目迁移vite的解决方案的更多相关文章

  1. 七天接手react项目 系列 —— 尾篇(antd 和 mobx)

    其他章节请看: 七天接手react项目 系列 尾篇 前面我们依次学习了 react 基础知识.react 脚手架创建项目.react 路由,已经花费了不少时间,但距离接手 spug_web 项目还有一 ...

  2. react项目中antd组件库的使用需要注意的问题

    antd是蚂蚁金服推出的ui组件库,给我们在react项目开发中提供了大大的便利.但在使用的过程中,或多或少的会遇到一些问题,毕竟,用的是别人的东西,就得遵守别人的规则嘛!官方文档:https://a ...

  3. 使用create-react-app+react-router-dom+axios+antd+react-redux构建react项目

    1.安装.构建 # 全局安装 npm install -g create-react-app # 构建一个my-app的项目 npx create-react-app my-app cd my-app ...

  4. react项目使用antd

    在开始实践之前要确保搭建React单页面开发环境,如果还没有搭建好开发环境的朋友请移步到如何搭建React单页面开发环境. 首先在命令行模式下创建一个React项目(项目名使用小写字母命名):(win ...

  5. react项目中使用less并修改antd主题样式

    一.react项目中使用less 1. 安装配置 npm i -D less less-loader 2. 查看webpack配置 npm run eject 此操作不可逆,生成新的目录. 3. 修改 ...

  6. idea ssm项目迁移到另一台机器上时出现不能正常启动项目的解决方案

    首先右下角提示关联spring文件,关联之,然后启动,发现项目无法启动,然后开始排错 首先从这个日志里发现了这么一条提示信息 然后百度了一下,答案都是说 web.xml 之类的 spring拦截器问题 ...

  7. (转)react 项目构建

    原文:https://segmentfault.com/a/1190000016342792 写在前面 每次构建react项目的时候都会配置一大堆东西,时间久了就会忘记怎么配置.为了方便自己记忆也为了 ...

  8. react项目结合echarts,百度地图实现热力图

    一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...

  9. 《Node+MongoDB+React 项目实战开发》已出版

    前言 从深圳回长沙已经快4个月了,除了把车开熟练了外,并没有什么值得一提的,长沙这边要么就是连续下一个月雨,要么就是连续一个月高温暴晒,上班更是没啥子意思,长沙这边的公司和深圳落差挺大的,薪资也是断崖 ...

随机推荐

  1. 让 gRPC 提供 REST 服务

    让 gRPC 提供 REST 服务 Intro gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计. gRPC 基于 HTTP/2 标准设计,带来诸如双向流.流控.头部 ...

  2. std::unordered_map与std::map

    前者查找更快.后者自动排序,并可指定排序方式. 资料参考: https://blog.csdn.net/photon222/article/details/102947597

  3. 翻译:《实用的Python编程》02_01_Datatypes

    目录 | 上一节 (1.7 函数) | 下一节 (2.2 容器) 2.1 数据类型和数据结构 本节以元组和字典为代表介绍数据结构. 原始数据类型 Python 有一些原始数据类型: 整数 浮点数 字符 ...

  4. MySQL5.7.29 和 Navicat ===> windows窗口式按装和使用

    MySQL windows窗口式按装下载方法:官网: https://www.mysql.com/ ==> DOWNLOADS ==> MySQL Community (GPL) Down ...

  5. Redis缓存中的常见问题

    缓存穿透:是指查询一个Redis和数据库中都不存在的数据. 问题:查询一个Redis和数据库中都不存在的数据,大量请求去访问数据库,导致数据库宕机. 解决办法: 1.根据id查询,如果id是自增的,将 ...

  6. selenium之元素定位的方法(二)

    XPath定位是XML Path的缩写,称为XML路径语言,是在XML文档中查找信息的一种语言,可用来再XML文档中对元素和属性进行搜索.XPath使用路径表达式来选取XML文档中的节点或节点集. X ...

  7. 通过序列号Sequence零代码实现订单流水号

    序列号管理 本文通过产品编码和订单流水号介绍一下序列号(Sequence)在crudapi中的应用. 概要 序列号 MySQL数据库没有单独的Sequence,只支持自增长(increment)主键, ...

  8. CNN结构演变总结(二)轻量化模型

    CNN结构演变总结(一)经典模型 导言: 上一篇介绍了经典模型中的结构演变,介绍了设计原理,作用,效果等.在本文,将对轻量化模型进行总结分析. 轻量化模型主要围绕减少计算量,减少参数,降低实际运行时间 ...

  9. 使用css3和javascript开发web拾色器实例

    本实例中的web拾色器功能使用css3实现页面效果,即在页面上显示的元素用css3样式来实现的.再使用js生成拾色器颜色数据,并控制各元素的鼠标事件.当事件作为反应时,获取到对应的数据并显示颜色值. ...

  10. JMeter扩展Java请求实现WebRTC本地音视频推流压测脚本

    WebRTC是Web Real-Time Communication缩写,指网页即时通讯,是一个支持Web浏览器进行实时语音或视频对话的API,实现了基于网页的视频会议,比如声网的Agora Web ...