blog
blog copied to clipboard
在一个项目中同时使用 antd3 和 antd4
Antd4 这个版本已经发布有很长时间了。但是,你应该还有些老项目依然在使用 antd3。虽然你垂涎于 antd4 的新特性,但是由于这些原因你又没办法直接升级:
- 老项目依然在更新迭代,直接升级 antd4,会导致大量代码需要重构。尤其是涉及到 Form 表单相关的代码
- 使用 antd 官方提供的升级工具。但它会生成很多冗余的胶水代码,这个对于一个代码洁癖者来说,是很难忍受的一件事情
由于这几个原因,我们走了另外一条途径,就是让项目中同时存在 antd3 和 antd4 两个版本。也就是说,将 antd 的两个版本都同时引入到项目中。不改动之前 antd3 的老代码,新的页面使用 antd4 来开发。然后在空余时间再慢慢改造老的代码,直到将 antd3 的相关代码慢慢改造干净为止
但是,将两个版本都引入进来,会存在下面几个问题:
- Antd4 和 antd3 的 js 代码暴露的全局变量都是
antd。所以,两个 js 文件如果都直接引入进来,后面版本的全局变量就会覆盖之前的
一种解决办法就是在加载完 antd4 之后,紧接着添加一行window.antd4 = antd。这样 antd4 暴露的全局变量就被缓存起来了。另外一种方式就是将官方的 antd4.js 进行重新编译,将其全局变量直接暴露为antd4,后面详说此种方式
<script src="http://unpkg.com/[email protected]/dist/antd-with-locales.min.js"></script>
<script>window.antd4 = antd</script>
<script src="http://unpkg.com/[email protected]/dist/antd-with-locales.min.js"></script>
- 页面中引入两个版本的 css 文件,样式也存在冲突,需要将 antd4.css 进行重新构建,以修改其前缀,这个后面也会详说:
<link rel="stylesheet" href="http://unpkg.com/[email protected]/dist/antd.min.css" />
<link rel="stylesheet" href="http://unpkg.com/[email protected]/dist/antd.min.css" />
- 修改 vite 或者 webpack 的
externals的依赖映射
export default defineConfig({
plugins: [
react(),
viteExternalsPlugin({
react: 'React',
'react-dom': 'ReactDOM',
antd: 'antd',
antd4: 'antd4'
}),
],
})
如此在页面中使用的时候:
import { Button } from 'antd' // 引用 antd3 的组件
import { Button } from 'antd4' // 引用 antd4 的组件
- 在你项目的入口文件中,使用
ConfigProvider修改页面中引用的组件前缀
import { ConfigProvider } from 'antd'
import { ConfigProvider as ConfigProvider4 } from 'antd4'
<ConfigProvider locale={antZhCN}>
<ConfigProvider4 prefixCls="ant4" locale={antZhCN4}>
...
</ConfigProvider4>
</ConfigProvider>
package.json中的依赖项。使用这种方式安装 antd4,可以让两个版本同时存在
{
"dependencies": {
"antd": "3.26.19",
"antd4": "npm:[email protected]",
}
}
即使上面配置了externals,也在本地进行安装。是为了可以在 ts 项目中引用其类型定义
从工程上解决上述问题
上面只是一个大概的步骤,下面详细讲一下如何使用 vite 的 lib 模式对 antd4.0 进行重新构建
这里使用 vite 创建一个新工程,并安装相关依赖:
yarn create vite antd4-build --template react-ts
yarn add vite-plugin-externals -D
yarn
- 在 src 目录下创建一个入口文件,引入 antd4.0 的相关文件。例如就叫
antd.ts
import 'antd/dist/antd.less' // 引入其 less 文件
// 引入中英两种语言包。antd.js 中包含了太多的语言包,其实我们大多数都用不到。这里都将其排除出去
// 其实英文语言包,可能很多系统也用不到,这里为了保险,就将包含进来了
import zh_CN from 'antd/lib/locale/zh_CN'
import en_US from 'antd/lib/locale/en_US'
const locales = {
zh_CN,
en_US
}
// 将 antd.js 直接引入进来,并导出去
export * from 'antd'
// 导出语言包
export { locales }
- 在 vite 配置文件中添加
lib配置。构建之后,暴露的全局变量就变成了antd4 - vite 会默认将 css 分离出来,但其生成的文件名称为
style.css。rollupOptions的配置就是为了将其重新命名为antd4.css
export default defineConfig({
build: {
lib: {
entry: './src/antd.ts',
name: 'antd4',
fileName: 'antd4',
},
outDir: 'dist',
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
if (assetInfo.name == 'style.css'){
return 'antd4.css'
}
return assetInfo.name
}
}
}
},
})
- 修改 antd.css 的前缀:
export default defineConfig({
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
'ant-prefix': 'ant4', // 这里最重要
'form-item-margin-bottom': '14px',
// 'iconfont-css-prefix': 'ant4icon'
}
}
}
}
})
- 添加时间戳和版本号,以方便查看:
export default defineConfig({
plugins: [
Banner(`${new Date().toLocaleString('en-US', {hour12: false})} antd@${packageJson.dependencies.antd}`)
],
})
- 对 antd 的三个依赖库进行外置,否则会和引入的项目产生冲突
export default defineConfig({
plugins: [
react(),
viteExternalsPlugin({
react: 'React',
'react-dom': 'ReactDOM',
moment: 'moment'
}),
],
})
- 最后执行
yarn vite build,会生成三个文件:
antd4.es.js
antd4.umd.js
antd4.css
将其放到自己的项目中,或者公司的 cdn 中直接引用就行了
完整 vite 配置:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import Banner from 'vite-plugin-banner'
import packageJson from './package.json'
import { viteExternalsPlugin } from 'vite-plugin-externals'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
viteExternalsPlugin({
react: 'React',
'react-dom': 'ReactDOM',
moment: 'moment'
}),
Banner(`${new Date().toLocaleString('en-US', {hour12: false})} antd@${packageJson.dependencies.antd}`)
],
server: {
port: 5000,
},
build: {
lib: {
entry: './src/antd.ts',
name: 'antd4',
fileName: 'antd4',
},
outDir: 'dist',
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
if (assetInfo.name == 'style.css'){
return 'antd4.css'
}
return assetInfo.name
}
}
}
},
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
'ant-prefix': 'ant4',
'form-item-margin-bottom': '14px',
// 'iconfont-css-prefix': 'ant4icon'
}
}
}
}
})
👏👏👏