手动搭webpack + React Hooks + TypeScript + Antd(一)
手动搭webpack + React Hooks + TypeScript + Antd(二)
手动搭webpack + React Hooks + TypeScript + Antd(三)
yarn add antd
antd引入一般需要做按需加载,如果不按需加载那么js css过大,如果不按需加载那么打包的结果大小👇
安装babel-plugin-import
yarn babel-plugin-import -D
babel.config.js plugin 配置添加
const plugins = [
['react-hot-loader/babel'],
+ ['import',
+ {
+ libraryName: 'antd',
+ style: true,
+ }
+ ]
];
src/pages/about/index.tsx
+ import { Button } from 'antd';
...
+ <Button type="primary">primary</Button>
+ <Button>Button</Button>
...
run的时候报错,因为style配置为true的时候会将antd的css一并引入
但是我们在配置less loader的时候并没有配置node_modules中的less
build/webpack.dev.js
MiniCssExtractPluginmodule: {
rules: [
...
+ {
+ test: /\.less$/,
+ include: /node_modules/, // antd less和主题不进行module
+ use: [
+ MiniCssExtractPlugin.loader,
+ "css-loader",
+ {
+ loader: "less-loader",
+ options: {
+ lessOptions: {
+ javascriptEnabled: true,
+ },
+ },
+ },
+ ],
+ },
...
]
}
antd主题适配
分为静态适配和动态主题设置
- 静态适配很简单
在lessOptions中加入modifyVars 具体颜色适配、主题变量见antd官网
build/webpack.dev.js
lessOptions: {
javascriptEnabled: true,
+ modifyVars: {
+ '@primary-color': '#1DA57A',
+ },
},
方法二(不推荐) 新建一个less引入官方提供的 less 样式入口文件
在assets下新建style文件夹,新建theme文件夹,里面新建 blue.variables.less red.variables.less之类的文件 然后分别写入各自的主题变量
src/assets/style/theme/red.variables.less
@import '~antd/dist/antd.less'; // 引入官方提供的 less 样式入口文件
@primary-color: #f00; // 全局主色
// ...
import '@assets/style/theme/red.variables.less';
(注意此种方法不能按需加载,配置了babel-plugin-import的style也没用)那为什么要在这里大费周章的探索多主题适配,是因为我们甲方爸爸要做多主题适配...
注意:如果在样式less里面引入antd一定不要将其module了,不然antd组件样式无效而且就算是分开配置其css-loader也无效,因为在src的less中引入的antd不会走webpack中css-loader的include:/node_modules/这个配置
build/webpack.dev.js
include: /node_modules|variables\.less/, // antd less和主题不进行module
多主题配置因为主题是后台配置,需要发送请求才能知道当前用户配置的主题颜色,所以需要将所有主题以及antd先全部打包出来,获取到用户配置主题后通过link标签append的方式引入
去掉babel-plugin-import的style配置,因为完全打包所以按需加载没用
build/config.js 写入所有主题配置文件
const THEMES_PATH = {
'theme.blue': './src/assets/style/theme/blue.variables.less',
'theme.red': './src/assets/style/theme/red.variables.less',
// ...
};
module.exports = {
cssLoaderConfig,
+ THEMES_PATH,
};
build/webpack.common.js 修改entry入口
entry: {
main: './src/index.tsx',
...config.THEMES_PATH, // 将antd css主题全部打包 再通过append style标签
},
页面中也不需要引入antd.css或者less了,直接引入需要的组件即可,babel.config.js中的style也注释掉
less-loader中的modifyVars也去掉,也无效了,手写的主题颜色已经将其覆盖了
然后run start,发现页面有antd的样式
查看页面才发现把blue和red的css全引入了,生成的样式js也全引入了,这还得了!!
new HtmlWebpackPlugin加入下面代码,不自动引入打包的样式css和js
+ const config = require('./config');
new HtmlWebpackPlugin({
template: 'public/index.html',
+ excludeChunks: [...Object.keys(config.THEMES_PATH)],
}),
要手动引入主题,需要将其打包出的css, run build试试
HtmlWebpackPlugin加入templateParameters在html中查看所有打包的内容
...
template: 'public/index.html',
excludeChunks: [...Object.keys(config.THEMES_PATH)],
+ templateParameters(compilation, assets, options) {
+ return {
+ compilation,
+ webpack: compilation.getStats().toJson(),
+ htmlWebpackPlugin: {
+ files: assets,
+ options,
+ },
+ };
},
...
在html中使用ejs语法
<div id="root"></div>
<p></p>
<div style="border: 1px solid #f00">
<% for(var key in webpack) { %>
<span style="margin-right: 10px;"><%= key %></span>
<% } %>
</div>
<div style="border: 1px solid #000">
<P><span style="color: #f00;">publicPath:</span> <%= JSON.stringify(webpack.publicPath) %></P>
<P><span style="color: #f00;">outputPath: </span><%= JSON.stringify(webpack.outputPath) %></P>
<P><span style="color: #f00;">assetsByChunkName: </span><%= JSON.stringify(webpack.assetsByChunkName) %></P>
<P><span style="color: #f00;">hash: </span><%= JSON.stringify(webpack.hash) %></P>
<P><span style="color: #f00;">entrypoints: </span><%= JSON.stringify(webpack.entrypoints) %></P>
<P><span style="color: #f00;">namedChunkGroups: </span><%= JSON.stringify(webpack.namedChunkGroups) %></P>
<P><span style="color: #f00;">filteredModules: </span><%= JSON.stringify(webpack.filteredModules) %></P>
</div>
重新run start在页面中可以看到所有的webpack的内容
那么在这里我们需要assetsByChunkName
在html中添加如下代码
public/index.html
....
<div id="root"></div>
<script type="text/javascript">
(function() {
var assetsByChunkNameString = '<%= JSON.stringify(webpack.assetsByChunkName) %>';
var assetsByChunkName = JSON.parse(assetsByChunkNameString);
var THEME = {};
for(var key in assetsByChunkName) {
if (/theme/.test(key)) {
var theme = key.replace(/theme\.(\w+)/, '$1');
if (Object.prototype.toString.call(assetsByChunkName[key]) === '[object Array]') THEME[theme] = assetsByChunkName[key][0];
else if(typeof assetsByChunkName[key] === 'string') THEME[theme] = assetsByChunkName[key];
}
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function handleDone() {
if (xhr.readyState === XMLHttpRequest.DONE) {
var theme = 'orange';
if (xhr.status === 200) {
var res = JSON.parse(xhr.responseText || '{}');
theme = {
'0': 'red',
'1': 'blue',
}[res.data] || theme;
}
var cssUrl = THEME[theme];
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.type='text/css';
link.rel = 'stylesheet';
link.href = cssUrl;
head.appendChild(link);
link = null;
}
};
xhr.open('GET', 'urlxxxxx', true);
xhr.send();
})();
</script>
...
run build 后打开也没有问题