Ant Design V4 升级之旅

2020-11-13  本文已影响0人  卓派前端工作志

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

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

开始之前

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

为什么要升级?

为什么现在升级?

变更要点一览

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

准备升级

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

开始升级

核心思路

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

通过运行命令:

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

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

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

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

升级详情

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

@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组件, 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选项与Select一致,需要使用options代替dataSource

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

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

// Type 'Moment | undefined' is not assignable to type 'Moment | null | undefined'. // Type 'Moment' is missing the following properties from type 'Moment': isoWeeksInISOWeekYear, tz
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...

本地无法启动

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

经常确认是升级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失败,经查主要是以下两个原因导致:

+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 | 知乎 | 掘金 | 简书

如果觉得本文对你有帮助的话,快来关注我们吧!

上一篇 下一篇

猜你喜欢

热点阅读