使用 antd 按需加载和自定义主题遇到的问题?

367 阅读4分钟

按需加载

antd 按需引入 css

spug 中使用的是 ​​react-app-rewired​​,而 myspug 使用的是 react-scripts。

react-app-rewired 是一个对 create-react-app 进行​​自定义配置​​的社区解决方案。

react-app-rewired 的引入是作为 antd 按需引入 css 解决方案的一部分。

步骤如下:

安装 react-app-rewired

 npm i react-app-rewired  && yarn add react-app-rewired 

安装 customize-cra

 npm i customize-cra  && yarn add customize-cra

安装 babel-plugin-import

 npm i babel-plugin-import && yarn add babel-plugin-import

修改 package.json,通过 ​​react-app-rewired​​ 来启动、打包和测试

/* package.json */
"scripts": {
-   "start": "react-scripts start",
-   "build": "react-scripts build",
-   "test": "react-scripts test",
+   "start": "react-app-rewired start",
+   "build": "react-app-rewired build",
+   "test": "react-app-rewired test",
}

项目根目录创建一个 ​​config-overrides.js​​(内容请看链接) 用于修改默认配置 修改 App.js 用于验证 antd 样式按需引入是否生效

import { Button } from 'antd';

export default function App() {
    return (
        <div className="App">
            <Button type="primary">Primary Button</Button>
        </div >
    );
}

最后启动服务 ​​npm run start​​​,浏览器访问 ​​http://localhost:3000/​​,看见一个蓝色按钮说明成功。

packages.json


{  
"name": "spug_web",  
"version": "3.0.0",  
"private": true,  
"dependencies": {  
// icon  
"@ant-design/icons": "^4.3.0",  
// 图表相关  
"@antv/data-set": "^0.11.8",  
// Ace 是一个用 JavaScript 编写的代码编辑器。 (不用)  
"ace-builds": "^1.4.13",  
// ui  
"antd": "^4.19.2",  
// http  
"axios": "^0.21.0",  
// 图表  
"bizcharts": "^3.5.9",  
// 小型功能路由器,通过搜索 `Enroute({` 发现只在 Test.js 中使用,应该是用于测试(不用)  
"enroute": "^1.0.1",  
// 路由相关  
"history": "^4.10.1",  
// jquery (不用)  
"jquery": "^3.6.0",  
"lodash": "^4.17.19",  
// 状态  
"mobx": "^5.15.6",  
"mobx-react": "^6.3.0",  
// 日期库  
"moment": "^2.24.0",  
// 数字  
"numeral": "^2.0.6",  
"react": "^16.13.1",  
// 与 ace Editor 相关(不用)  
"react-ace": "^9.5.0",  
// react  
"react-dom": "^16.13.1",  
// 路由  
"react-router-dom": "^5.2.0",  
"react-scripts": "3.4.3",  
// 浏览器中使用终端(不用)  
"xterm": "^4.6.0",  
"xterm-addon-fit": "^0.5.0"  
},  
// 本地启动、打包  
"scripts": {  
"start": "react-app-rewired start",  
"build": "react-app-rewired build",  
"test": "react-app-rewired test",  
"eject": "react-scripts eject"  
},  
// eslint 相关。查找并修复JavaScript代码中的问题。  
"eslintConfig": {  
"extends": "react-app"  
},  
// 编译后的源码支持的浏览器。不用动  
"browserslist": {  
"production": [  
">0.2%",  
"not dead",  
"not op_mini all"  
],  
"development": [  
"last 1 chrome version",  
"last 1 firefox version",  
"last 1 safari version"  
]  
},  
  
"devDependencies": {  
// 用于支持 es6 中装饰器的语法  
"@babel/plugin-proposal-decorators": "^7.10.5",  
"anywhere": "^1.5.0",  
"bx-tooltip": "^0.1.6",  
// 新的 react-app-rewired@2.x 版本的关系,你还需要安装 customize-cra  
"customize-cra": "^1.0.0",  
// http 代理中间件  
"http-proxy-middleware": "0.19.2",  
"less": "^3.12.2",  
"less-loader": "^7.1.0",  
"mockjs": "^1.1.0",  
// 一个对 create-react-app 进行自定义配置的社区解决方案  
"react-app-rewired": "^2.1.6"  
}  
}

对比我的 packages.json

{
  "name": "antd-demo-ts",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^29.4.0",
    "@types/node": "^18.14.6",
    "@types/react": "^18.0.28",
    "@types/react-dom": "^18.0.11",
    "antd": "^4.0.0",
    "babel-plugin-import": "^1.13.6",
    "customize-cra": "^1.0.0",
    "react": "^18.2.0",
    "react-app-rewired": "^2.2.1",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.9.5",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

解决问题

image.png

点击antd.css(@import '~antd/dist/antd.css';)报错,怀疑包下载有问题,最后卸载 antd,再次安装 antd@4即可。

"antd": "^4.19.2",  
 npm i antd@4.19.2 && npm i and@4.0.0

自定义主题

按照 配置主题 的要求,自定义主题需要用到 less 变量覆盖功能。我们可以引入 customize-cra 中提供的 less 相关的函数 addLessLoader 来帮助加载 less 样式,同时修改 config-overrides.js 文件如下。

- const { override, fixBabelImports } = require('customize-cra');
+ const { override, fixBabelImports, addLessLoader } = require('customize-cra');

module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
-   style: 'css',
+   style: true,
  }),
+ addLessLoader({
+   javascriptEnabled: true,
+   modifyVars: { '@primary-color': '#1DA57A' },
+ }),
);
  • 这里利用了 less-loader 的 modifyVars 来进行主题配置,变量和其他配置方式可以参考 配置主题 文档。

  • 修改后重启 yarn start,如果看到一个绿色的按钮就说明配置成功了。

  • 如果提示错误缺少 less-loader

image.png

安装: less less-loader

yarn add less less-loader

image.png

  • 如果还报错 解决办法:将package.json中,"typescript": "~3.7.5"版本,更新ts到"typescript": "^3.8.3"

安装: typescript

yarn add typescript@3.8.3 -S

发现还是不行

什么情况呀?? 但是作为程序员解决问题我们必须要做的那就解决他.

63e91ebb6b5010ef73a50187644ccf7.png

这是什么问题呀?

刚刚我们安装了 less less-loader 造成的问题是这样&& 也许会碰到上面的那个问题

bec02ed2fe3651f15a5408e941b5119.png

匹配版本less less-loader

现在来匹配一下版本:

  npm i less@2.7.3  less-loader@4.1.0 post-loader3.0.0 --save-dev  
  
  yarn add less@2.7.3  less-loader@4.1.0 post-loader3.0.0 -D

运行之后发现 咦 不报错了, 但是按需加载的Button 不能全局自定义主题

46694c9180ed9e2aa46e138963a3556.png

import logo from './logo.svg';
import { Button } from 'antd'
import './App.css';
import '../src/assets/index.less'
import Home from './views/Home'

function App() {
  return (
    <div className="app">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
      <Home/>
      <span className='box'>我是谁!</span>
      <Button type="primary" danger>
      Primary
    </Button>
    <Button danger>Default</Button>
    <Button type="dashed" danger>
      Dashed
    </Button>
    <Button type="text" danger>
      Text
    </Button>
    <Button type="link" danger>
      Link
    </Button>
      <Button type="dashed">Danger Default</Button>
    </div>
  );
}

export default App;

好现在发现 不是less的问题, 也和antd的版本无关, 那是啥子问题呢,头大 那就是config-overrides他的问题了,

1678350718733.png

关于这个 rewired 有空再细说

现在先解决如何实现 antd 自定义主题的问题

config-overrides 改成 craco.config

首先我们把config-overrides 改成 craco.config

然后 使用 @craco/craco

 npm i @craco/craco -D

配置 package.json

 "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test"
  },

用于处理less

npm i craco-less -D //less处理插件

按需加载 babel-plugin-import

npm i babel-plugin-import -D

创建 craco.config.js

const CracoLessPlugin = require('craco-less');
 
module.exports = {
    babel: {//支持装饰器
        plugins: [
            [
                "import",
                {
                    "libraryName": "antd",
                    "libraryDirectory": "es",
                    "style": true //设置为true即是less 用css写'css'
                }
            ]
        ]
    },
    plugins: [
        {
            plugin: CracoLessPlugin,
            options: {
                lessLoaderOptions: {
                    lessOptions: {
                        modifyVars: {
                            '@primary-color': 'red', // 全局主色
                        },
                        javascriptEnabled: true,
                    },
                }
            },
        },
    ],
};

解决

import logo from './logo.svg';
import { Button } from 'antd'
import './App.css';
import '../src/assets/index.less'
import Home from './views/Home'

function App() {
  return (
    <div className="app">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
      <Home/>
      <span className='box'>我是谁!</span>
      <Button type="primary" danger>
      Primary
    </Button>
    <Button danger>Default</Button>
    <Button type="dashed" danger>
      Dashed
    </Button>
    <Button type="text" danger>
      Text
    </Button>
    <Button type="link" danger>
      Link
    </Button>
      <Button type="dashed">Danger Default</Button>
    </div>
  );
}

export default App;

image.png