当前位置: 首页>编程语言>正文

Ant Design V4 升级之旅

Ant Design V4 升级之旅,第1张

注:本篇旨在记录并回顾团队项目进行Ant Design V4版本升级的全过程,及过程中所遇到的一些问题,不涉及深入的技术分析,以期为面对类似情况的开发者提供一些思路及参考。

今年(2020年)年初,Ant Design发布了4.0大版本更新。新的V4版本带来了许多值得关注的优化及改变,如升级调整后的设计规范、全局范围的性能优化、顺应潮流引入的暗黑主题等等。经过社区半年多的实践反馈,也该是时候让我们的项目踏上V4升级之旅了。

开始之前

在决定实施升级之前,我们需要先(针对我们团队的前端项目)解答以下两个问题:

为什么要升级?

  • Ant Design仍然是我们团队的前端项目(以下简称"项目")中使用最广泛的UI库;

  • V4版本对项目目前经常使用的一些组件进行了重构,修复了遗留问题,并带来了性能优化;

  • V4版本提供了一些新的功能,这些功能对我们来说很有引入的价值;

  • V4版本开始使用React Hooks来重写部分组件,这与项目目前的代码风格趋势一致。

为什么现在升级?

  • 项目一直使用在使用V3版本,但社区对V3的维护已于2020年6月停止,继续使用一个废弃的版本,风险不言而喻;

  • V4发布的时间已经足够长,大部分的基础问题都已得到解决,不需要担心踩坑的危险;

  • 团队计划对项目网站的UI风格进行统一和优化,先进行升级便于协调后续安排。

变更要点一览

关于Ant Design V4的升级详情,大家可以参考官网文档,以下是部分要点概括,便于大家了解概况:

  • 设计规范调整:包括基础风格和样式的调整,以及新的暗色主题效果、无边框风格组件;

  • 兼容性调整:涉及对IE的兼容性调整,更需要关注的是V4版本更多的使用了Hooks来简化代码;

  • 移除废弃的API:移除了一些在V3版本中提示Warning信息的废弃API;

  • 图标升级:通过引入SVG图标,减少了antd的默认包大小;

  • 组件重构:主要包括对FormDate Picker组件的重写,以及新的TreeSelectTreeSelectAutoComplete组件,同时,引入虚拟滚动,优化了承载大量选项/项目组件的渲染性能。

准备升级

为了使升级尽可能的简单平滑,Ant Design V4已尽可能保证了最大程度的兼容性,但仍有一些问题需要特别处理,其中涉及到一些准备工作:

  • 升级antd版本:需要先将antd的版本升级到3.26.18(3.x的最新版本),并根据控制台的Warning信息删除/修改相关API。

  • 确认React版本:文档建议的版本是16.12.0以上,而项目目前使用的版本是16.9.0,理论上需要升级,但考虑到antd仍能够支持16.9.0版本,为了减少升级的工作量,避免引入更多的风险,我们决定暂不升级React。

开始升级

核心思路

首先,我们尝试使用Ant Design团队提供的codemod cli工具(@ant-design/codemod-v4)进行迁移,其可以帮助我们解决大多数基础问题。

通过运行命令:

npx -p @ant-design/codemod-v4 antd4-codemod src

工具可以自动完成部分迁移,并对不能自动迁移的部分进行提示说明。

而后,根据提示逐一手动迁移不能自动完成的部分,待这些提示部分手动迁移完成后,再次执行上述命令重新确认。

如此循环往复,直到完成所有的迁移工作。

升级详情

以下为项目在升级过程中涉及到的一些代码变更示例:

  • Icon

@ant-design/icons中引入特定icon

-  import  { Icon }  from  'antd'  
+  import  { ExclamationCircleFilled }  from  '@ant-design/icons'  

-  <Icon type="exclamation-circle" theme="filled"  />  
+  <ExclamationCircleFilled />

@ant-design/icons中引入Icon组件,以构建自定义图标

-  import  { Icon }  from  'antd'  
+  import Icon from  '@ant-design/icons'  <Icon component={svg}  />
  • Select

对于Select组件, filterOption第二个参数直接返回原数据,不在需要通过option.props.children来进行匹配。 Optionvalue属性改为必传参数。

<Select
     showSearch
     style={{ width:  200  }} 
     placeholder="Select a person"
     optionFilterProp="children"
     onChange={onChange}
     onFocus={onFocus}
     onBlur={onBlur}
     onSearch={onSearch}
     filterOption={(input, option)  =>  
-    option.props.children 
+    option.children
          .toLowerCase()
          .indexOf(input.toLowerCase())  >=  0
     }
>
     <Option 
+       value="jack"
     > 
        Jack
     </Option>  
</Select>
  • AutoComplete

AutoComplete选项与Select一致,需要使用options代替dataSource

<AutoComplete 
-   dataSource={this.state.loadOptions} 
+   options={this.state.loadOptions}
    onSelect={this.onSelect}
    onChange={this.triggerSearch}
    optionLabelProp={'value'}
    placeholder="Search by Name" 
/> 
  • Pagination

Pagination4.1.0版本起,会默认将showSizeChanger参数设置为true ,因而在数据条数超过50时,pageSize切换器会默认显示。这个变化同样适用于Table组件。

<Pagination 
+   showSizeChanger={false}  
/>

类名变化

通常来说,开发工作并不需要太关注类名变化,但由于我们的Cypress Testing脚本在定位DOM节点时大量使用了antd类名,对于一些重构后的组件,我们详细对比了更改前后的类名变化,此处不再赘述。

样式变化

由于项目前期在使用antd组件时,或多或少地使用了:global()对默认样式进行了重写,导致部分页面同类型组件却出现了不同样式,为了便于升级时调试,也为了之后能够进行进一步的全站样式统一优化,我们去掉了大部分的样式重写,与antd的默认样式保持一致。

主要涉及:InputDropdownSelectCalendarTimePickerDatePicker

? height: 42px、44.8px、48px -> 40px
? font-size: 14px -> 16px
? margin-bottom: 15px、16px、30px -> 16px

问题回顾

ESlint

  • moment:在升级antd之后,我们发现部分类型报错,经查确认是moment版本问题导致,最低支持的版本为2.25.3
// Type 'Moment | undefined' is not assignable to type 'Moment | null | undefined'. // Type 'Moment' is missing the following properties from type 'Moment': isoWeeksInISOWeekYear, tz
  • @types/react、@types/react-dom:同时我们也发现很多难以定位的类型问题,在尝试升级@types/react@types/react-dom后,问题得到解决。
src/lib/components/Icons/index.tsx:147:8 
    -error TS2741: Property 'translate' is missing in type '{children?: ReactNode; color?: string | undefined; component: FC<{}>; className: string;}' but required in type 'Pick<IconComponentProps, "max" | "required" | ... 350 more ... | “onTransitionEndCapture">'. 
147 <Icon...

本地无法启动

升级后,项目在本地开发环境无法启动,控制台出现报错:

Ant Design V4 升级之旅,第2张

经常确认是升级moment版本导致,修改webpack.config.js配置,移除moment.js设置后问题解决。

module:  {  
//  noParse: /moment\.js/,  
}

功能失效

PopoverTooltip组件在升级后报类型错误,经查确认为antd bug,于是在Github创建了issue,该问题在antd最新的release已经得到修复。

<Popover
  trigger="hover"
  placement="bottomLeft" 
>
  <WarningOutlined className={warningIconClass} />
  <WarningOutlined className={warningIconClass} />
</Popover>  

// This JSX tag's 'children' prop expects a single child of type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | undefined', but multiple children were provided.

单元测试失败

目前,我们的项目主要使用react-testing-library编写进行单元测试,在升级后,部分UT失败,经查主要是以下两个原因导致:

  • 类名改变,选择器失效无法定位元素,导致断言失败;(修改选择器修复)

  • 由于因加入的虚拟滚动功能,Select, Dropdown, AutoComplete 等组件在获取下拉菜单选项时,无法获取当前未在屏幕上显示的元素,导致断言失败;(修改逻辑,先输入操作保证元素显示后再获取元素,修复)

+function doSelectDropdownOption( 
+  labelText: string, 
+  selectOption: string 
+) { 
+  const selectLabel = getByLabelText(labelText) 
+  fireEvent.click(selectLabel) 
+  act(() => { 
+    fireEvent.input( 
+      selectLabel.parentElement?.querySelector('input')!, 
+      { 
+        target: { value: selectOption }, 
+      } 
+    ) 
+  }) 
+  fireEvent.click(getDocTypeMenuItem(selectOption)!) 
+}  

it('test', () => {
  fireEvent.click(getByText('Upload Document'))
  const uploadBtn = getByText('Upload')
  // The upload button should be disabled until we have chosen a load
  expect(uploadBtn).toBeDisabled()
  doSelectFile()
  // Select a document type 
+ doSelectDropdownOption('Document Type', 'Other (Load)')
  expect(uploadBtn).toBeDisabled()
})

升级完成

至此,升级工作就算是告一段落了,但对我们来说,后续要做的事情还有很多,如升级React到推荐版本16.12.0、规范并统一组件风格样式、完善组件库/文档等等。整个升级过程虽然不存在太高的技术难度,但却是一份非常费时费力的工作,我们不得不踩入团队自己挖下的坑,因此,为了避免重蹈覆辙,我们在代码规范上又加上了两条:

  • 保持对第三方依赖库的规律性升级;

  • 保证项目中页面的自定义样式尽可能一致。

这也算是另一个收获了。

“卓派前端工作志,聚焦实用前端技术,让编程更有趣!”

前端技术组 @ 西安卓派科技 NEXT Trucking — 拉勾 | Boss | 知乎 | 掘金 | 简书


https://www.xamrdz.com/lan/5tj1994123.html

相关文章: