Ant-design: Svg icons make bunlde size too large

Created on 3 Sep 2018  ·  223Comments  ·  Source: ant-design/ant-design


Issuehunt badges

  • [ ] I have searched the issues of this repository and believe that this is not a duplicate.

Version

3.9.0

Environment

webpack4

Reproduction link

https://zlab.github.io/report.html

Steps to reproduce

webpack build

What is expected?

icon 按需打包, js文件拆分

What is actually happening?

打包到chunk-vendors里去了




IssueHunt Summary

vagusx vagusx has been rewarded.

Backers (Total: $203.00)

Submitted pull Requests

- #18217 use ant design icons 4.0

Tips

IssueHunt has been backed by the following sponsors. Become a sponsor


Rewarded on Issuehunt Inactive IssueHuntFest ❓FAQ 🗣 Discussion

Most helpful comment

💢 脑壳痛。。。。大爷的。。。

All 223 comments

Translation of this issue:


antd svg package size is too large, it is recommended @ant-design/icons package on demand

  • [ ] I have searched the issues of this repository and believe that this is not a duplicate.

Version

3.9.0

Environment

Webpack4

Reproduction link

https://zlab.github.io/report.html

Steps to reproduce

Webpack build

What is expected?

Icon Pack as needed, js file split

What is actually happening?

Packed into chunk-vendors

我只用到了几个icon

image

<Icon /> 默认全量引入了图标库。因为不知道你会引入何种图标进行运行时引入。之前图标托管在 iconfont.cn 所以打包无感知。

这需要深入讨论
临时方案见 https://github.com/ant-design/ant-design/issues/12011#issuecomment-420038579

cc @yesmeck

需要提供一个可以按需加载的方式,antd 组件内部也用这个方式。

import Star from 'antd/icons/star';

<Star />

但是这样做的话,以前的写法无法兼容

<Icon type="star" /> // should import star icon first

不能按需打包, 异步加载也好啊,

之前使用iconfont就是页面内容会先出来, 图标会慢慢加载出来

<Icon.Star />

但是这样做的话,以前的写法无法兼容

不会的,只要不用 <Icon /> 就不全量打包进来。

有些场景不能按需打包, 比如设置menu的图标, 如果可以后台配置, 这样前端是无法预知会设置成什么图标的,
异步加载比较适合, 把@ant-design/icons打成一个chunk就好

实际上内置使用了 <Icon /> 的组件例如 <DatePicker />, <Select /> 等,用到也会全量引入。

如果可以后台配置, 这样前端是无法预知会设置成什么图标的,异步加载比较适合

我们做的后台系统的menu就是配置的,图标异步加载真的很需要,全量打包实在太大了。

感觉异步比较好。
想按需打包估计得写个像 babel-plugin-importbabel 插件了。

analyzer

实际上内置使用了 <Icon /> 的组件例如 <DatePicker />, <Select /> 等,用到也会全量引入。

内部的写法都改掉

项目中有type是个变量,是只能引入全量了吗?
<Icon type={icon} />
这种有没有可以部分引入的?

另外 @ant-design/icons 内应该直接构建好 dist 包来用,直接依赖浅编译的源码并无必要。

+1 ,确实包大了一倍

💢 脑壳痛。。。。大爷的。。。

最骚的是带了很多 SourceMappingUrl

搞得我都退到 3.8.2版本了

https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo (umi project)

Here is a solution that use resolve.alias in webpack to reduce the bundle size.
We plan to design new APIs that allow import the icons in need in the furture.
Note that you should also import the icons used in antd component, such as loading, close-circle and so on.


https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo (umi 项目)
这里有一个临时的解决方案:配置webpack 的 resolve.alias 字段。
未来应该会想办法设计新的图标API来方便按需加载图标的使用。
注意按需的图标中也要包括 antd其他组件使用的图标,例如 loading, close-circle 等等。

@HeskeyBaozi 首先你的感谢辛勤付出!我现在时间是9:29,看到你提交的时间是6 hours ago,兄弟真的够拼!点赞:thumbsup::thumbsup::thumbsup:

我的理解是,单独列一份项目要用的icon,包括antd要用到的icon

@ChiaJune antd 组件中完整用到的图标列表,若有遗漏我可以补充
https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo/blob/master/src/icons.js#L10-L100

可以參考一下fontawsome的做法

A

import { library } from "@fortawesome/fontawesome-svg-core";
import faCalendar from "@fortawesome/free-solid-svg-icons/faCalendar";

library.add(faCalendar); // Load icon once

...

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
<FontAwesomeIcon icon="calendar" />

B

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import faCalendar from "@fortawesome/free-solid-svg-icons/faCalendar";

<FontAwesomeIcon icon={faCalendar} /> // Import directly or any svg

Preserve the old usage and add warning & migration message in console.

import { Icon } from 'antd';
<Icon type="star" />

Provider new API like:

import Star from 'antd/icons/Star';
import Setting as SettingIcon from 'antd/icons/Setting';

<Star />
<SettingIcon />

And treeshaking-able way too:

import { Icon: { Star, Setting } } from 'antd';

<Star />
<SettingIcon />

@HeskeyBaozi @yesmeck

https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo (umi project)

Here is a solution that use resolve.alias in webpack to reduce the bundle size.
We plan to design new APIs that allow import the icons in need in the furture.
Note that you should also import the icons used in antd component, such as loading, close-circle and so on.

https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo (umi 项目)
这里有一个临时的解决方案:配置webpack 的 resolve.alias 字段。
未来应该会想办法设计新的图标API来方便按需加载图标的使用。
注意按需的图标中也要包括 antd其他组件使用的图标,例如 loading, close-circle 等等。

@HeskeyBaozi Great solution!! (until antd cleans this up and allows singular importing of icons) I have been making some attempts at using resolve.alias to fix this issue, but this hit the nail on the head. Thank you!

keep an eye on this, since we are using this version as well.

cc @jameswhf @xcqwan

Same for me. Importing separately does not cover all usage scenarios so fixing treeshaking is necessary. Please check here

@serayuzgur
I use webpack.alias and it works for me. Maybe it can help you : )
image
my repo's antd-icon-tree-shaking branch ( Webpack4 + Babel 7.0 )

This also causes issues if all I have is a Button in a bundle (probably since it supports icons). Any workaround to reduce the bundle size if all I'm using is a Button?

image

(In the screenshot - I just have a Button component but the icons bloats up the bundle primarily)

Temporary Solution that worked for me until it will be fixed (antd >= 3.9)

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

I think a better api would be if we could set the icon by passing some JSX that way I could simply import the needed icon only and pass that to the button. Also would make it simple to work with third party icons (or any svg).

<Button icon={<Icon type="search" />}>Search</Button>

Just my personal preference :)

For people using create-react-app via react-app-rewired.

config-overrides.js

const path = require('path');

/* config-overrides.js */
module.exports = function override (config, env) {
  let alias = (config.resolve.alias || {});
  alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, "./src/icons.js");

  config.resolve.alias = alias;

  return config;
}

icons.js gist

For people using create-react-app via react-app-rewired.

config-overrides.js

const path = require('path');

/* config-overrides.js */
module.exports = function override (config, env) {
  let alias = (config.resolve.alias || {});
  alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, "./src/icons.js");

  config.resolve.alias = alias;

  return config;
}

icons.js gist

Doing this method removes compatibility of twoToneColor.
<Icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
<Icon type="close-circle" theme="twoTone" twoToneColor="#f73131" />
results in:
image

Hi,
The cause of this problem is the ability to use icons like <Icon type="check-circle". This api needs every icon to be included so it can provide whatever you give as type.

This also gives us ability to decide icons at runtime and it is valuable for me. So according to me API should stay same but Icon component should support loading icons by the given type on demand.

Perhaps using dynamic import (depends on #12235 - upgrading to Webpack 4) or through a Webpack 3 library such as react-loadable

Based on this comment go further temprory solution:

$ yarn add purched-antd-icons
// webpack.config.js
module.exports = {
  // other configs
  resolve:{
    // other configs
    alias:{
      "@ant-design/icons":"purched-antd-icons"
    }
  }
}

the purched-antd-icons package removes all icons not been used by antd's official components. For my condition, Icomoon is the project icon system provider.

Here is an ejected create-react-app bundle analysis comparing.

webpack output
output

bundle analysis
comparing

在官方给出异步加载的方案前可以将@ant-design/icons/lib/dist.js 这个文件导入dll文件做长期缓存

before:

image

after:

image

workaround from @tobiaslins is not working for me, it says Module not found: Error: Can't resolve '@ant-design/icons/lib/dist' in '/Users/fede/Projects/despe/deliveries/node_modules/antd/es/icon' can anyone point me how to fix it? Thanks

@marcosfede I had the same issue as you. The alias is not working properly.

Check if you have __dirname set in path.resolve(__dirname, "./src/icons.js")

If you're using the create-react-app via react-app-rewired alternative you can do:

3.9 upgrade increased our bundle 700kb (23%). Whilst we love the new implementation, the increased bundle size was a big surprise. The increase is offset due to not including 'iconfont'. We will implement @Obooman solution which will still see our overall footprint increase, however not enough to warrant us freezing at 3.8.4.

purched-antd-icons package implementation leaves our project with many missing icons.

@michaelpeterlee purched-antd-icons only provides icons official components need, we use it as we are not using other icons in antd. for more customization, you'll have to manage your icons manually or choose font icon generators like icomoon or iconfont as your icon system provider.

@marcosfede I had the same issue as you. The alias is not working properly.

Check if you have __dirname set in path.resolve(__dirname, "./src/icons.js")

If you're using the create-react-app via react-app-rewired alternative you can do:

this was useful, thanks. I've had ejected the project so I had __dirname point to the config folder where the webpack files are located instead of the root folder

Maybe AntDesign team should consider to come back to the previous way (before 3.9). Is the better way, the wise way.

@marcosfede I had the same issue as you. The alias is not working properly.
Check if you have __dirname set in path.resolve(__dirname, "./src/icons.js")
If you're using the create-react-app via react-app-rewired alternative you can do:

this was useful, thanks. I've had ejected the project so I had __dirname point to the config folder where the webpack files are located instead of the root folder

It works for me, thanks!

Here are the changes we'll make in next release to solve the problem of bundle size.

Create a separated component for every single icon

import StarFilled from 'antd/icons/StarFilled';

<StarFilled />

Deprecate reference a icon as a string

A deprecated warning will show when you reference an icon as a string in the following components:

<Icon type="star" />
<Alert iconType="success" />
<Avatar icon="star" /> 
<Button icon="star" /> 
Modal.confirm({ iconType: 'star' })

For compatibility, we'll load an SVG sprite on demand when you reference an icon as a string.

Instead of referencing an icon as a string, you should pass ReactNode explicitly to these props:

import StarFilled from 'antd/icons/StarFilled';

<Avatar icon={<StarFilled />} /> 

@yesmeck A good solution that introduces tree shake and no addIcon method at the same time!

A question. What if we have CSS styles on these icons and need to change icons' type dynamically? Do we have to pass styles to all of the substitution icons?

@michaelpeterlee rc-calendar didn't depend on antd and @ant-design/icons, so it's not supposed to "load the whole icon library". You can create a issue in https://github.com/react-component/calendar/issues with a reproduce demo.

My mistake. I've deleted my irrelevant comment. It must be the DatePicker component that introduces the icon:
image

My point being, I am not importing antd icons anywhere in my project, but some antd components are importing Icon from antd. It would be good if those components could only import the icons they need, instead of the whole icon library.

Here are the changes we'll make in next release to solve the problem of bundle size.

@yesmeck

Do you mean 3.11.x? It does not seem to be included in 3.10.4.

@johnernaut #12888

暂时退回到v3.8.4,3.9.0+的版本打包后体积太大,上面大神们说的版本只是临时解决方案,期待下个版本能异步加载icon

Thanks @yesmeck, I look forward to the next version.

I also wanted to mention that I've published an Ant Design plugin for create-react-app v2 and craco. Here is the craco-antd plugin on GitHub

I've just added a Large Bundle Size from Ant Design Icons section to the README, and I will keep an eye on this issue (and the PR.) Thanks for the tip @sunel (and others). I've included a link to your comment about setting up an alias.


For those who would like to bundle ng-zorro-antd to webpack dll and in turn find that the whole 500KB @ant-design/icons-angular is bundled, if you are not using any ant-design icons in the project, (that is, the project does not depend on @ant-design/icons-angular), here is a tip to have webpack do the tree shaking for you:

module.exports = {
  resolve: {
    alias: {
      "@ant-design/icons-angular/icons": "/path/to/node_modules/@ant-design/icons-angular/esm2015/icons/ant-design-icons-angular-icons.js"
    }
  }
}

I draft a reproduction repository showcasing this issue. The webpack configuration is modified from the original ng-zorro-antd integration example in here and it seems that the DllPlugin render tree-shaking in the flattened ES Module useless.

It does work as expected if the DllPlugin is absent.

Here are some historical backgrounds about that webpack does not do tree-shaking on flatten es modules. I believe what they refer have been mostly fixed in recent release except some edge cases of DllPlugin.

Interestingly it is not until May that webpack supports tree shaking on DllPlugin, I have aded entryOnly: true but no luck. I would draft a more isolated example and raise an issue to webpack.

Edits: Added reproduction repository and historical issues.

The end of story: it is here that renders reproduction repository falsy. The webpack 3.5.6 is too aged without entryOnly: true support. That is why fesm5 modules are not tree-shaken.

For those who would like to bundle ng-zorro-antd to dll vendors

  • If you have webpack >=4.9.0, add entryOnly: true to your DllPlugin configuration.
  • Otherwise, add this setting to your webpack config
module.exports = {
  resolve: {
    alias: {
      "@ant-design/icons-angular/icons": "/path/to/node_modules/@ant-design/icons-angular/esm2015/icons/ant-design-icons-angular-icons.js"
    }
  }
}

@issuehuntfest has funded $200.00 to this issue. See it on IssueHunt

字体文件能不能别参与打包,自己本地引入?太大了

官方有计划优化这个问题吗?能否提供本地svg方案,类似3.8以前版本?

期待改进

Is there an official solution?

@fuhaiwei Until the next version, check this comment for a workaround by exporting icons directly https://github.com/ant-design/ant-design/issues/12011#issuecomment-423173228

目前我使用 webpack.resolve.aliasantd/es/icon 替换成一个自定义组件。
该组件会将 <Icon />props.typeprops.theme 发送给指定的 API。
这样一来在页面测试时可以记录下所有使用的 Icon 数据。
然后根据数据和 https://github.com/ant-design/ant-design/issues/12011#issuecomment-423173228 自动生成icons.js
希望能找到更好的解决方法。


Currently I am using webpack.resolve.alias to replace antd/es/icon with a custom component.
That component will send props.type and props.theme of <Icon /> to the specified API.
This allows you to record all of the Icon data used during the page test.
Then generate icons.js automatically, based on the data and https://github.com/ant-design/ant-design/issues/12011#issuecomment-423173228.
Hope to find a better solution.

3个月过去了,官方找到按需加载的方法了吗

image

感觉最好的还是从引入方式入手,像material那样所有组件都单独引用多好。。现在只有那些可能用到内置Icon的组件,都把图标全部打包出来了。。

没有用到 Icon 组件也会加载 @ant-desigin/icons 这个包

没有用到 Icon 组件也会加载 @ant-desigin/icons 这个包

datepicker此类的也用到了,看下代码里有没有此类。menu也会用到吧

500多KB 实在太大了

期待ing,本来换到最新版了,一看打包出来那么大,吓得我又回退回去了

不想用SVG格式的,可以灵活配置吗?配置使用还是不使用svg

可以提供一个仅引用单个图标的方式,并且 antd 所有内部组件全部更新为使用这种方式:

import Search from 'antd/icons/Search";

<Search />

对于现有项目的兼容,依旧保留 import { Icon } from 'antd';,但是只要使用 import { Icon } from 'antd'; 就是全量图标导入。

同意楼上

mark 等待完美解决的方法

500k的icons , 有解决方案了?

Can some one update me on this in English? The 500kb is a quarter of my bundle. I am using webpack and importing the Icons like so:

import Icon from 'antd/lib/icon';
<Icon type="logout" />

I have tried various ways of importing them and even removing the icon imports all together, but it seems like whatever I do the 500kb stays. I am using webpack, and was able to properly tree shake the icons using parcel's experimental-scope hoisting feature, but I can't use that since it breaks my app in 20 other places.

How are people handling this issue? Is everyone here just shipping their projects with an extra 500kb or is their some obvious workaround I am ignoring?

Does importing like so work with a standard webpack build?

import Star from 'antd/icons/star';
If anyone could update me, I'd really appreciate it.

@ApolloGun The workaround has been referenced several times in this thread, everything is in this comment: https://github.com/ant-design/ant-design/issues/12011#issuecomment-423173228

The way it works is by telling Webpack to resolve the icons from a different location, specifically a new file where you export exactly the icons you want to use. After doing that the icons will work as normal, nothing else has to change in the components.

I am not using any Icons but still get that huge file. Maybe, the components in antd are using it internally. How do I figure the icons which are used by components. This seems to be a good method to replace Antd icons by custom icons for things like Select, Dropdown, etc.

I am not using any Icons but still get that huge file. Maybe, the components in antd are using it internally. How do I figure the icons which are used by components. This seems to be a good method to replace Antd icons by custom icons for things like Select, Dropdown, etc.

@HeskeyBaozi created a list of the icons used in antd components, using webpack alias:
https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo/blob/master/src/icons.js#L10-L100
Please read the entire issue discussion to understand this method.

@ApolloGun There is currently no official solution.
The pull request: #12888 is still working in progress.

@yesmeck , @afc163 Any plans to close this soon?

@HeskeyBaozi @afc163 ,请问要如何使用你们新写的这个??

@HeskeyBaozi May I ask why you guys are not working on this? It's been over five months. Do you guys consider this a low priority?

@HeskeyBaozi May I ask why you guys are not working on this? It's been over five months. Do you guys consider this a low priority?

Agree, it's really annoying =(

After inspecting the code of antd, I'm seeing that a component such as Button imports Icon, which in turn imports (according to the generated code)

// import everything here
import * as allIcons from '@ant-design/icons/lib/dist';

//...

// use everything here :(
ReactIcon.add.apply(
  ReactIcon,
  _toConsumableArray(
    Object.keys(allIcons).map(function(key) {
      return allIcons[key];
    })
  )
);

which causes treeshaking to fail, and thus importing all icons. Please consider pointing the import to @ant-design/icons/lib/index.es.js and not performing operations on all icons until needed. Also, check out the history of this line: https://github.com/ant-design/ant-design/blob/master/components/icon/index.tsx#L3 It's been changing a bit over time.

这直接导致整个项目不能用 好吗

@poorel

<Icon /> 默认全量引入了图标库。因为不知道你会引入何种图标进行运行时引入。之前图标托管在 iconfont.cn 所以打包无感知。

这需要深入讨论
临时方案见 #12011 (comment)

这个方案还是可以用的,我测试过了,但是你要整理出来你项目中有哪些icon,就这个略麻烦些

但是你要整理出来你项目中有哪些icon...

之前试着看了, 发现 icon 的引用很多是 antd 自带组件做的, 而且数量也不小. 自己在业务直接引用的虽然很小, 但是考虑组件可能引用到的, 数量也不好统计了.

@chenyong 额,那蛋疼了。。。

@aryzing Your approach sounds appealing. Will it result in less effort than #12888 ? That PR involves too many breaking changes, probably it's part of the reason why it's still not finished after months.

@zachguo I looked through #12888, and I couldn't really understand what was going on. After some thought on the matter, I'm not sure we can successfully tree shake the icons because the a dynamic apis used by some components to render icons are clashing with the static nature of ES imports used for tree shaking.

The icon used in some antd components is dynamically rendered (i.e. determined at runtime) based on a prop. For example, take a look at Button's api:

<Button icon="search">Search</Button>

In order for this component to render correctly, the Button component (or the underlying Icon component used) must have access to (at run-time) all icons, and doesn't allow for tree shaking.

The solution would be to have an API such as

import { 
  SearchIcon // not sure if this actually exists
} from '@antd/some-icons-package';

<Button icon={SearchIcon}>Search</Button> {/* option 1 - component */}
<Button icon={() => <SearchIcon />}>Search</Button> {/*option 2 - render prop */}

In this scenario, you're only importing what you need, and tree shaking can kick in and drop all unused exports from the example @antd/some-icons-package.

这个问题已经超过半年了,仍然没有官方的解决方案。目前我使用的解决方案是采用 import() 进行异步加载。
This problem has been more than half a year, and there is still no formal solution. The solution I'm currently using is to use import() for asynchronous loading.

使用到 React 官方文档中的推荐的 Loadable Components
Use the Loadable Components recommended in the official React documentation.

import React from 'react';
import ReactDOM from 'react-dom';
import { Icon } from 'antd';

ReactDOM.render(
  <Icon type="github" />,
  document.getElementById('root')
);

image

image

  • 第一步,安装依赖项:@loadable/component@babel/plugin-syntax-dynamic-import
    The first step is to install dependencies: @loadable/component and @babel/plugin-syntax-dynamic-import.
  • 第二步,在项目根目录创建一个文件夹 icons,并使用脚本将 @ant-design/icons 中的所有图标进行导出:
    The second step is to create a folder icons in the project root and export all the icons in @ant-design/icon using a script:

    #!/usr/bin/env node
    const fs = require('fs');
    const path = require('path');
    const util = require('util');
    const icons = require('@ant-design/icons');
    
    const fsMkdir = util.promisify(fs.mkdir);
    const fsWriteFile = util.promisify(fs.writeFile);
    
    // https://github.com/ant-design/ant-design-icons/blob/master/packages/icons-react/src/utils.ts#L94-L108
    const mapping = {
    fill: 'fill',
    outline: 'o',
    twotone: 'twotone',
    };
    const saveFlag = { encoding: 'utf8', mode: 0o644, flag: 'w' };
    
    (async () => {
    const dir = path.join(__dirname, 'icons');
    await fsMkdir(dir, 0o755);
    const processes = Object.values(icons).map(value => {
      if (value && value.name && value.theme) {
        // https://github.com/ant-design/ant-design-icons/blob/master/packages/icons-react/src/components/Icon.tsx#L38-L42
        const file = path.join(dir, `${value.name}-${mapping[value.theme]}.js`);
        const data = `export default ${JSON.stringify(value)}`;
        return fsWriteFile(file, data, saveFlag);
      }
    });
    await Promise.all(processes);
    })();
    

    直接在项目下使用 node 执行此脚本即可将 @ant-design/icons 中导出的所有图标存储到 icons 目录中。
    Execute this script directly under the project using the node to store all the icons exported from @ ant-design/icons in the icons folder.

  • 第三步,复制 Antd 代码仓库中的 components/icon/index.tsx 到项目根目录,命名为 Icon.jsxIcon.js,然后将代码中的 TypeScript 类型定义删除以得到纯 JavaScript 代码。(如果你的项目使用 TypeScript,也可以直接命名为 Icon.tsxIcon.ts,也就不用再删类型定义了)
    In the third step, copy components/icon/index.tsx in the Antd code repository to the project root, and named to Icon.jsx or Icon.js, then remove the TypeScript type definition in the code to get pure JavaScript code. (If your project uses TypeScript, you can also name it directly as Icon.tsx or Icon.ts, so you don't have to delete the type definition)
    然后修改这个代码文件,使用 import() 配合 @loadable/component 来按需加载图标文件。
    Then modify the code file and use import() with @loadable/component to load the icon file as needed.

    diff -- a/Icon.tsx b/Icon.jsx
    --- a/Icon.tsx
    +++ b/Icon.jsx
    @@ -1,70 +1,29 @@
    import * as React from 'react';
    import classNames from 'classnames';
    -import * as allIcons from '@ant-design/icons/lib/dist';
    +import loadable from '@loadable/component';
    import ReactIcon from '@ant-design/icons-react';
    -import createFromIconfontCN from './IconFont';
    +import createFromIconfontCN from 'antd/es/icon/IconFont';
    import {
    svgBaseProps,
    withThemeSuffix,
    removeTypeTheme,
    getThemeFromTypeName,
    alias,
    -} from './utils';
    +} from 'antd/es/icon/utils';
    -import warning from '../_util/warning';
    +import warning from 'antd/es/_util/warning';
    -import LocaleReceiver from '../locale-provider/LocaleReceiver';
    +import LocaleReceiver from 'antd/es/locale-provider/LocaleReceiver';
    -import { getTwoToneColor, setTwoToneColor } from './twoTonePrimaryColor';
    +import { getTwoToneColor, setTwoToneColor } from 'antd/es/icon/twoTonePrimaryColor';
    +
    +const AllIcons = loadable.lib(props => import(
    +  /* webpackChunkName: "icons/icon-" */
    +  `./icons/${props.type}.js`
    +));
    
    // Initial setting
    -ReactIcon.add(...Object.keys(allIcons).map(key => (allIcons as any)[key]));
    setTwoToneColor('#1890ff');
    -let defaultTheme: ThemeType = 'outlined';
    +let defaultTheme = 'outlined';
    -let dangerousTheme: ThemeType | undefined = undefined;
    +let dangerousTheme = undefined;
    -
    -export interface TransferLocale {
    -  icon: string;
    -}
    -
    -export interface CustomIconComponentProps {
    -  width: string | number;
    -  height: string | number;
    -  fill: string;
    -  viewBox?: string;
    -  className?: string;
    -  style?: React.CSSProperties;
    -  spin?: boolean;
    -  rotate?: number;
    -  ['aria-hidden']?: string;
    -}
    -
    -export type ThemeType = 'filled' | 'outlined' | 'twoTone';
    -
    -export interface IconProps {
    -  tabIndex?: number;
    -  type?: string;
    -  className?: string;
    -  theme?: ThemeType;
    -  title?: string;
    -  onKeyUp?: React.KeyboardEventHandler<HTMLElement>;
    -  onClick?: React.MouseEventHandler<HTMLElement>;
    -  component?: React.ComponentType<CustomIconComponentProps>;
    -  twoToneColor?: string;
    -  viewBox?: string;
    -  spin?: boolean;
    -  rotate?: number;
    -  style?: React.CSSProperties;
    -  prefixCls?: string;
    -  role?: string;
    -}
    -
    -export interface IconComponent<P> extends React.SFC<P> {
    -  createFromIconfontCN: typeof createFromIconfontCN;
    -  getTwoToneColor: typeof getTwoToneColor;
    -  setTwoToneColor: typeof setTwoToneColor;
    -  unstable_ChangeThemeOfIconsDangerously?: typeof unstable_ChangeThemeOfIconsDangerously;
    -  unstable_ChangeDefaultThemeOfIcons?: typeof unstable_ChangeDefaultThemeOfIcons;
    -}
    -
    -const Icon: IconComponent<IconProps> = props => {
    +const Icon = props => {
    const {
      // affect outter <i>...</i>
      className,
    @@ -107,7 +66,7 @@
      [`anticon-spin`]: !!spin || type === 'loading',
    });
    
    -  let innerNode: React.ReactNode;
    +  let innerNode;
    
    const svgStyle = rotate
      ? {
    @@ -116,7 +75,7 @@
        }
      : undefined;
    
    -  const innerSvgProps: CustomIconComponentProps = {
    +  const innerSvgProps = {
      ...svgBaseProps,
      className: svgClassString,
      style: svgStyle,
    @@ -165,12 +124,19 @@
        dangerousTheme || theme || defaultTheme,
      );
      innerNode = (
    -      <ReactIcon
    -        className={svgClassString}
    -        type={computedType}
    -        primaryColor={twoToneColor}
    -        style={svgStyle}
    -      />
    +      <AllIcons type={computedType}>
    +        {({ default: loadedIcon }) => {
    +          ReactIcon.add(loadedIcon);
    +          return (
    +            <ReactIcon
    +              className={svgClassString}
    +              type={computedType}
    +              primaryColor={twoToneColor}
    +              style={svgStyle}
    +            />
    +          );
    +        }}
    +      </AllIcons>
      );
    }
    
    @@ -181,7 +147,7 @@
    
    return (
      <LocaleReceiver componentName="Icon">
    -      {(locale: TransferLocale) => (
    +      {locale => (
          <i
            aria-label={type && `${locale.icon}: ${type}`}
            {...restProps}
    @@ -196,7 +162,7 @@
    );
    };
    
    -function unstable_ChangeThemeOfIconsDangerously(theme?: ThemeType) {
    +function unstable_ChangeThemeOfIconsDangerously(theme) {
    warning(
      false,
      'Icon',
    @@ -206,7 +172,7 @@
    dangerousTheme = theme;
    }
    
    -function unstable_ChangeDefaultThemeOfIcons(theme: ThemeType) {
    +function unstable_ChangeDefaultThemeOfIcons(theme) {
    warning(
      false,
      'Icon',
    
  • 最后一步,配置 Webpack:
    The final step is to configure Webpack:
    ```diff
    diff -- a/webpack.js b/webpack.js
    --- a/webpack.js
    +++ b/webpack.js
    @@ -1,4 +1,5 @@
    const path = require('path');
    +const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const TerserPlugin = require('terser-webpack-plugin');

    @@ -33,12 +34,16 @@
    plugins: [
    new HtmlWebpackPlugin({
    title: 'Awesome Page',
    template: path.join(__dirname, 'public/index.html'),
    meta: {
    viewport: 'width=device-width, initial-scale=1',
    },
    hash: true,
    }),

    • new webpack.NormalModuleReplacementPlugin(
    • /node_modules\/antd\/es\/icon\/index.js/,
    • path.resolve(__dirname, 'Icon.jsx')
    • ),
      ],
      resolve: {
      modules: ['node_modules'],
      @@ -56,13 +61,14 @@
      use: [{
      loader: 'babel-loader',
      options: {
      presets: [
      ['@babel/preset-env', { targets: '> 2.486%, not dead' }],
      '@babel/preset-react',
      ],
      plugins: [
    • ['@babel/plugin-syntax-dynamic-import'],
      ['@babel/plugin-proposal-class-properties'],
      ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }],
      ],
      },
      }]

      ```

这个解决方案的优点是,你可以保留所有图标,在可配置后台管理系统中也可以任意修改图标而不用担心缺少图标;并且图标是按需加载的,只有开始渲染特定页面的图标时才会加载对应的图标文件。必须加载的只有打包后的 index 中有 50K 左右的图标列表数据(在 Icon.jsx 中的 webpack 魔术注释中指定更短的名字可以缩小这个体积)。
The advantage of this solution is that you can keep all the icons, you can also modify icons in the configurable background management system without worrying about the missing icons, and the icons are loaded on demand, only the icons needed to be rendered will be loaded when you start rendering a specific page. The packaged index file which must be loaded has only about 50K of icon list data (specifying a shorter name in the Webpack magic comment in Icon.jsx can reduce this size).

这个方案的缺点是,每一个图标都包含了除图标内容以外的额外的 Webpack 模块信息,因此可以看到 icons 文件夹的大小比之前整体打包的单文件大小要大很多,加上 index 中的 50K 图标列表数据,实际打包下来的尺寸接近 3M。但是由于实际上能使用到的图标来来回回也就那么几个、十几个,所以用户浏览器下载的数据量不会太大,并且由于是异步加载,只要单页面同时显示的图标数不多,对加载速度影响也就不大。
The downside of this solution is that each icon contains Webpack module information in addition to the icon content, so you can see that the size of the icons folder is much larger than the size of the single file packaged before, and 50K of icon list data in the index file, the actual packaged size is close to 3M. However, because the icons that can actually be used are only a few or a dozen, the amount of data downloaded by the user's browser is not too large, and since it is asynchronously loaded, as long as the number of icons displayed on a single page is not more, the impact on the loading speed is not large.

@jinliming2 很酷炫的修改,才发现webpack的import其实可以传变量的

Fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information. This is because foo could potentially be any path to any file in your system or project. The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.

居然只要有一个目录的前缀就可以了,之前以为是不行的。
话说回来,antd用户也不是只用webpack,这就有点尴尬了。

@aryzing It seems the option 1 of your proposed APIs are actually what #12888 is trying to achieve. A lot of breaking changes would be involved, so probably we still need to wait for Ant Design team to finish it.

may consider using xhr to load svg asynchronously?
archer-svgs

由于ant deisgn本身组件会使用到较多的图标,所以是否考虑将图标文件改为异步加载方案,这样就不用占用主文件体积,可以参考下这个:

Since ant deisgn itself will use more icons, so consider changing the icon file to an asynchronous loading scheme, so that you don't need to occupy the main file size, you can refer to this:

webpack-ant-icon-loader

@rororofff has funded $2.00 to this issue.


For anyone who is intimidated by the length of this conversation and just wants to use create-react-app and ant-design, I created a boilerplate project here https://github.com/AustinGreen/cra-antd-starter

This includes a fix for the icon bundle size problem, and a custom webpack config without ejecting. Thanks to @ndbroadbent, @patricklafrance, and the whole ant-design team for all their hard work.

For anyone who is intimidated by the length of this conversation and just wants to use create-react-app and ant-design, I created a boilerplate project here https://github.com/AustinGreen/cra-antd-starter

This includes a fix for the icon bundle size problem, and a custom webpack config without ejecting. Thanks to @ndbroadbent, @patricklafrance, and the whole ant-design team for all their hard work.

How can I use it in Nextjs app?

@AustinGreen I tried your example.

image

For an app with sidebar and one button to have a size of ~100kB Gzipped is still way too much.

@anjmao if there is a way to further reduce the bundle size please let me know and I'll add it in. If you're building an enterprise web application, ~100kB Gzipped for a front-end framework, ~5 components (from a comprehensive component library), icons, and other utilities is pretty standard.

@anjmao if there is a way to further reduce the bundle size please let me know and I'll add it in. If you're building an enterprise web application, ~100kB Gzipped for a front-end framework, ~5 components (from a comprehensive component library), icons, and other utilities is pretty standard.

https://github.com/ant-design/ant-design/issues/12011#issuecomment-420038579 . Here's a good solution

@Oscar-ren the project is already using an alias for icons (which is why the bundle size is only ~100kB and not ~400kB)

@tobiaslins have you changed your workaround since your last comment?
When I use this in a Nuxt project the client and serverside rendering get out of sync:
The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

Just FYI, a Vue's version to reduce bundle size using webpack alias:
https://github.com/atjason/ant-design-vue-demo

Refer:
https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo

Package size of Hello World:

image

由于ant deisgn本身组件会使用到较多的图标,所以是否考虑将图标文件改为异步加载方案,这样就不用占用主文件体积,可以参考下这个:

Since ant deisgn itself will use more icons, so consider changing the icon file to an asynchronous loading scheme, so that you don't need to occupy the main file size, you can refer to this:

webpack-ant-icon-loader

For posterity, this only works for React.

Hello, when is the @jinliming2 solution going to be released?
The webpack-ant-icon-loader does not work for me.

Hi, can you provide information about using
webpack-ant-icon-loader with you?
Let me see if I can help solve it.

Hello @beven91!

I have done previously some tests and did not work and I was not able to
figure why. However your question made me to isolate the case on a
dedicated project I did create a sample test for you to show you and this
time it did work! I am saving constantly 1.21 Mb from the resulted bundle
which fantastic from both the demo project and the one working on
commercially.

I am posting here the example project in case someone else has the same
problems:
https://github.com/vladimirmoushkov/ant-icons-webpack-loade-test/#readme

Without the webpack-ant-icon-loader I get the following result:
bundle.development.js 4.59 MiB app [emitted] app

With webpack-ant-icon-loader I get:
../../index.html 555 bytes [emitted]
0.bundle.development.js 1.21 MiB 0 [emitted]
bundle.development.js 3.41 MiB app [emitted] app

Couple of notes:

  • think will be better if you delete 0.bundle.development.js produced
    artefact.
  • the icons disappears from the final product, ie they are not visible on the page. I saw your umirc.js config but I am using react-router. How can I make them re-appear?

On Fri, Apr 5, 2019 at 2:38 PM beven91 notifications@github.com wrote:

Hi, can you provide information about using
webpack-ant-icon-loader with you?
Let me see if I can help solve it.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/ant-design/ant-design/issues/12011#issuecomment-480244343,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AUPfoCCVrb5j4s8Qleju8LvdPsxC02FFks5vdzW7gaJpZM4WW7EA
.

https://github.com/AustinGreen/cra-antd-starter

@AustinGreen just curious, how is your solution different than the Ant documented react-app-rewired and babel-plugin-import method documented here - https://ant.design/docs/react/use-with-create-react-app ?

GitHub
boilerplate for using create react app and ant design - AustinGreen/cra-antd-starter
An enterprise-class UI design language and React-based implementation with a set of high-quality React components, one of best React UI library for enterprises

@annjawn as of create-react-app 2.0, react-app-rewired is no longer maintained, so my project uses craco + craco-antd which were created to replace react-app-rewired for CRA 2.0.

@Beven91 could you help with this part of my previous comment please?

  • the icons disappears from the final product, ie they are not visible on the page. I saw your umirc.js config but I am using react-router. How can I make them re-appear?

I mean its great there is separation between the icons in the whole bundle but the used icons still remain part of the separated bundle, so to use them would mean it include it as separate bundle that makes the separation pointless.

@annjawn as of create-react-app 2.0, react-app-rewired is no longer maintained, so my project uses craco + craco-antd which were created to replace react-app-rewired for CRA 2.0.

@AustinGreen makes sense, but it's fundamentally the same thing using CRACO. Btw, I am also going to use react-loadable to do code splitting and I am thinking your method + modular imports + async component load should provide significant bundle size reduction.

@vladimirmoushkov
Sorry be late,i will try to resolve it。

Hello @vladimirmoushkov

You can see the details here. ant-icons-webpack-loade-test#1

Temporary Solution that worked for me until it will be fixed (antd >= 3.9)

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

This isn't working for ant components that use icons. for example, alert component uses check and close icons but aren't visible with this solution

@Venugopal46 you can add those icons (that are used by ant components) to your icons.js as well.
Works fine for me.

Looks like we are close to a solution; To finish, we could craft a util that auto-generates icons.js as part of the build process.

How can you know precisely which icons are being imported through ant's own components, so as to put them in your icons.js?

For me the above hack:

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

And use of the following generateIconsList.sh file to generate src/icons.js:

grep -iR \<Icon\  ./src/ | cut -d: -f2 | sed -e s/.*\<Icon\ //g | sort | uniq | while read icon; do 
    theme='Outline';
    themelowercase="outline";
    if [[ $icon =~ ^.*twoTone.*$ ]]; then
        theme="TwoTone";
        themelowercase="twotone";
    fi
    if [[ $icon =~ ^.*fill.*$ ]]; then
        theme="Fill";
        themelowercase="fill";
    fi
    icon=$(echo $icon | sed -e 's/type\=\"//g'| sed -e 's/\".*//g' | sed -e 's/\-/ /g')
    icon=$(python -c "print('"$icon"'.title())")
    icon=$(echo $icon | sed -e 's/ //g')
    core_path="@ant-design/icons/lib/"$themelowercase"/"$icon$theme
    search_path="node_modules/"$core_path".js"
    if [ -e $search_path ]; then
        echo "export { default as "$icon$theme" } from \""$core_path"\";"
    fi
done | sort | uniq

by running generateIconsList.sh 2>/dev/null >src/icons.js from the project root - does the job!.
The script is ugly hack and obviously does not catch internal icons references or multiline <Icon /> references. In my case I needed to add few Icon cases manually however the script does the job however in the end - having 1.1 mb less in the final bundle!

How can you know precisely which icons are being imported through ant's own components, so as to put them in your icons.js?

I'm just adding the icons which are missing (not displayed) on a web page but should be there. It depends on how much antd's components you are using, but for me it took somewhere around 10 minutes to add. (I use lots of antd components, though)

For example if sorter arrows on the tables are missing:

  1. inspect ant table and find <i aria-label="icon: caret-down" class="anticon anticon-caret-down ant-table-column-sorter-down off">. You'll see that this <i /> tag is empty. You can see here that the name of the icon is caret-down.
  2. Find this icon in a @ant-design/icons/lib folder, choose filled or outline folder (depending on what icon type you need) and add new import to icons.js like so:
export { default as CaretDownOutline } from '@ant-design/icons/lib/outline/CaretDownOutline';

Not the best approach, but it works as expected. Looking forward for ant development team to fix this in a future releases so we can avoid such dirty hacks.

Hi !

Any news on this subject? Is it a candidate for next antd's release?
I tried a few things to solve this problem (webpack-ant-icon-loader, babel-import-plugin) but none of them worked.

Thanks!

Really need a solution on this, bundle size is too much!

@zlab @nuintun @anjmao 求助,请问一下https://zlab.github.io/report.html 这个页面是通过什么插件生成的呢,想分析一下自己的项目

找到了,是webpack-bundle-analyzer

只用到了 modal,却打包了500k 的 icon lib

都大半年了,没有进展吗?

放弃antd了 这么重要的问题居然没标注important...

现在按需加载必定会打包进icons的文件,500kb

i add alias in my webpack, and export icon in icon.ts, but when i run npm start,got an error

ERROR in ./node_modules/antd/lib/icon/index.js
Module not found: Error: Can't resolve '@ant-design/icons/lib/dist' in 'xxx\node_modules\antd\lib\icon'

this is my webpack resolve config

resolve: {
      modules: [path.resolve(__dirname, '../src'), 'node_modules'],
      alias: {
        '@ant-design/icons/lib/dist$': path.resolve(
          __dirname,
          '../src/utils/antdIcon.ts',
        ),
      },
      extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
      plugins: [
        new TsConfigPathsPlugin({
          tsconfig: path.resolve(__dirname, '../tsconfig.json'),
        }),
      ],
    },

1.项目中都没有用icon 图标,怎么有打包了,求大神解答?
image
2.用webpack externals = {'antd': 'antd'} 也不好使,打包分析中还是能看到antd?

1.项目中都没有用icon 图标,怎么有打包了,求大神解答?
2.用webpack externals = {'antd': 'antd'} 也不好使,打包分析中还是能看到antd?

@wiiler

  1. 参考这个,可能是用了引用 Icon 的组件

    https://github.com/ant-design/ant-design/issues/12011#issuecomment-418003883
    实际上内置使用了 <Icon /> 的组件例如 <DatePicker />, <Select /> 等,用到也会全量引入。

  2. 如果使用 externals 需要把 babel-plugin-import 插件关掉

i add alias in my webpack, and export icon in icon.ts, but when i run npm start,got an error

ERROR in ./node_modules/antd/lib/icon/index.js
Module not found: Error: Can't resolve '@ant-design/icons/lib/dist' in 'xxx\node_modules\antd\lib\icon'

this is my webpack resolve config

resolve: {
      modules: [path.resolve(__dirname, '../src'), 'node_modules'],
      alias: {
        '@ant-design/icons/lib/dist$': path.resolve(
          __dirname,
          '../src/utils/antdIcon.ts',
        ),
      },
      extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
      plugins: [
        new TsConfigPathsPlugin({
          tsconfig: path.resolve(__dirname, '../tsconfig.json'),
        }),
      ],
    },

I recommend these two practices

@As3ass1n
Why '../src/utils/antdIcon.ts' has a '..'? Is the webpack config placed in a separate directory?

1.项目中都没有用icon 图标,怎么有打包了,求大神解答?
2.用webpack externals = {'antd': 'antd'} 也不好使,打包分析中还是能看到antd?

@wiiler

  1. 参考这个,可能是用了引用 Icon 的组件
    > #12011 (comment)
    > 实际上内置使用了 <Icon /> 的组件例如 <DatePicker />, <Select /> 等,用到也会全量引入。
  2. 如果使用 externals 需要把 babel-plugin-import 插件关掉

明白了,感谢 @wangjianio

i add alias in my webpack, and export icon in icon.ts, but when i run npm start,got an error

ERROR in ./node_modules/antd/lib/icon/index.js
Module not found: Error: Can't resolve '@ant-design/icons/lib/dist' in 'xxx\node_modules\antd\lib\icon'

this is my webpack resolve config

resolve: {
      modules: [path.resolve(__dirname, '../src'), 'node_modules'],
      alias: {
        '@ant-design/icons/lib/dist$': path.resolve(
          __dirname,
          '../src/utils/antdIcon.ts',
        ),
      },
      extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
      plugins: [
        new TsConfigPathsPlugin({
          tsconfig: path.resolve(__dirname, '../tsconfig.json'),
        }),
      ],
    },

I recommend these two practices

@As3ass1n
Why '../src/utils/antdIcon.ts' has a '..'? Is the webpack config placed in a separate directory?

sorry, it's my fault. i wrote a wrong file name, and now i resolved it use alias. thanks

Will this problem not be solved in the future? Increase by nearly 400 k

Hi, is it possible to provide atleast rough time estimate of when it will be resolved?

image

Extra 490kb on the bundle makes Icons practically unusable. This is a pretty big issue, is there any temporary fix that we can do until you release a fix for this?

@smddzcy read the thread?

@schester44 With the thread written in a variety of languages and…I was about to say alphabets, or even syllabaries, but I think I have to go as far as scripts…I daresay it’s pretty hard for anyone whose linguistics are limited to languages typically restricted to Etruscan-derived alphabets to be entirely clear on what’s going on.

Hi folks, I've had success with the very simple purched-antd-icons package implementation, however that is entirely manual; I estimate 3-4 hours fiddling around to reconcile missing icons by inspecting the DOM. We intend to implement that at the very last stage in our dev/release cycle. For our packaged/offline-first applications, the only issue is approaching the very modest iOS WKWebview RAM limitation. For us, if iOS mobile profiles continue to not exhibit artefacts, we'll ignore this completely. Seeing as no progress is made here, my preference would be to see this new Icon API shelved and the old API brought back.

@afc163 ,

What you wrote on 15 September 2018 sounds like a good solution (Google translation below). Can you provide an estimate when this will be implemented?

Preserve the old usage and add warning & migration message in console.

import { Icon } from 'antd';
<Icon type="star" />

Provider new API like:

import Star from 'antd/icons/Star';
import Setting as SettingIcon from 'antd/icons/Setting';

<Star />
<SettingIcon />

And treeshaking-able way too:

import { Icon: { Star, Setting } } from 'antd';

<Star />
<SettingIcon />

@HeskeyBaozi @yesmeck

According to the V4 roadmap, this would be fixed at Q4 this year.

Cool :smiley:

Vào Th 7, 1 thg 6, 2019 vào lúc 01:51 Zach Guo notifications@github.com
đã viết:

According to the V4 roadmap
https://github.com/ant-design/ant-design/issues/16911, this would be
fixed at Q4 this year.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/ant-design/ant-design/issues/12011?email_source=notifications&email_token=ADKDE4RXC63VER4GSUMG5Q3PYFXT7A5CNFSM4FS3WEAKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWWCRFY#issuecomment-497821847,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADKDE4TGAYRMSJQB246RQ33PYFXT7ANCNFSM4FS3WEAA
.

ICYMI, the Icon docs mentioned this. Copy of it below.

"⚠️ About the extra bundle size brought by all SVG icons we imported in 3.9.0, we will provide new API to allow developers importing icons as your need, you can trace #12011 for further progress.
Before this, you can use webpack plugin from community to chunk the icon file."

The last bit is cool, code split and load icons asynchronously, or in my case, code split and don't use the icons at all.

官方是不是放弃了这个了,都多久了,还不解决

官方是不是放弃了这个了,都多久了,还不解决

@zhe-he

image

No Clear solution!

这个官方真的不打算解决这个问题吗? 这么大不需要的打包,真的劝退啊

@DemoHu
image

@tibotiber thanks for the link to the icon-loader , the icon chunk still gets inserted into the index.html? any suggestions on how to remove the chunk from being inserted from index.html

@jasan-s I'm guessing that would depend on how you build the bundles, and where you use the icons. For example, I'm on the latest create-react-app, which configures code splitting for me, and I make sure to not import icons anywhere in the component tree of the main bundle (I never use icons).

workaround from @tobiaslins is not working for me, it says Module not found: Error: Can't resolve '@ant-design/icons/lib/dist' in '/Users/fede/Projects/despe/deliveries/node_modules/antd/es/icon' can anyone point me how to fix it? Thanks

@marcosfede I use customize-cra, is there a way not to eject? I still got this error

./node_modules/antd/lib/icon/index.js
Cannot find module: '@ant-design/icons/lib/dist'. Make sure this package is installed.

You can install this package by running: yarn add @ant-design/icons/lib/dist.

@marcosfede Oh! my bad. I got it now.

我有个想法 💡 @afc163

我们可以使用 svg 图标,然后保持之前的用法:

<Icon type='search' />

然后通过 babel 插件转换成:

import _searchIcon from '@ant-design/icons/lib/dist/search.svg'
<Icon component={ _searchIcon } />

// 或者直接转化成
<Icon component={ require('@ant-design/icons/lib/dist/search.svg') } />

然后就可以借助 tree-shaking 只打包使用的 icon。

至于动态的 type ,不支持使用就好。有动态的需求可以使用即可:

import * as AllIcons from '@ant-design/icons/lib/dist'

<Icon component={ AllIcons[type] } />

实际上是去掉了原 type 的实际功能,将所有的 type 用法转换成了 component 用法。

我有个想法 💡 @afc163

我们可以使用 svg 图标,然后保持之前的用法:

<Icon type='search' />

然后通过 babel 插件转换成:

import _searchIcon from '@ant-design/icons/lib/dist/search.svg'
<Icon component={ _searchIcon } />

// 或者直接转化成
<Icon component={ require('@ant-design/icons/lib/dist/search.svg') } />

然后就可以借助 tree-shaking 只打包使用的 icon。

至于动态的 type ,不支持使用就好。有动态的需求可以使用即可:

import * as AllIcons from '@ant-design/icons/lib/dist'

<Icon component={ AllIcons[type] } />

实际上是去掉了原 type 的实际功能,将所有的 type 用法转换成了 component 用法。

思路和 4.0 改造是一样的,不过这个用 babel 转义显然降低了工作量,只有动态变更的需要手动处理了。

昨晚发完评论后临时写了个 Babel 插件,本地试了一下,完全可行 @wendzhue @afc163

const template = require('@babel/template')

function genRequireEpx (name) {
  return template.expression(`require('@ant-design/icons/lib/dist/${name}.svg')`)()
}

module.exports = function ({ Plugin, types: t }) {
  return {
    visitor: {
      // <Icon type='search' />
      JSXElement({ node }, { opts: { patterns = [] } }) {
        const { name, attributes } = node.openingElement
        if (!(name && name.name === 'Icon') || !attributes || !attributes.length) {
          return
        }
        attributes.forEach(attr => {
          if (attr.name.name === 'type') {
            attr.name.name = 'component'
            attr.value = genRequireEpx(attr.value.value)
          }
        })
      },
      // React.createElement(Icon, { type: "search" }
      CallExpression({ node }, { opts: { patterns = [] } }) {
        const cal = node.callee
        const arg = node.arguments
        if (!(cal.object && cal.object.name === 'React' &&
            cal.property && cal.property.name === 'createElement' &&
            arg[0] && arg[0].name === 'Icon' &&
            arg[1] && arg[1].properties
          )) {
          return
        }
        arg[1].properties.forEach(obj => {
          if (obj.key.name === 'type') {
            obj.key.name = 'component'
            obj.value = genRequireEpx(obj.value.value)
          }
        })
      },
    }
  };
}

还需要完善下转换规则和阉割 type 的实际功能。

any progress ?

看到官方icon源码里面的对这个打包的解决方案,把icon单独打包出一个js
https://github.com/Beven91/webpack-ant-icon-loader

@ARKKYN antd v4 working in progress #16911

You can try the alpha version of antd 4 now

这个官方真的不打算解决这个问题吗? 这么大不需要的打包,真的劝退啊

其实这东西跟 afc163 在圣诞节的所作所为是一样的调性,潜台词是“老子喜欢,你爱用不用”

@lizy0329 4.0.0-alpha.2 已经在改了,涉及到精力和时间安排,着急的话fork自己改了...

@lizy0329 see #18217

No cool, realy.

这不酷,真的。但这东西其实在改动的时候都应该想象到后果了,跟 HO!HO! 一样的调性没办法不拿来比较。

@lizy0329

其实这东西跟 afc163 在圣诞节的所作所为是一样的调性,潜台词是“老子喜欢,你爱用不用”

Why use SVG instead of font?
Use React SVG components for icons instead of an icon font

Has a company done this before?
Delivering Octicons with SVG

What is the problem now?
The previous icon uses font, loaded by cdn, the size will not be reflected on the vendor. There is no default cdn (you can still put all the icons into a chunk and use your own cdn for hosting) to host the svg icon, this part will be reflected in the vendor.
What is discussed in this issue is how to do the tree shaking, how to load icon on demand.

If you can't tolerate it, load all the icons at once, there (in the issue) are at least three ways to avoid.

@afc163
I think the change log of 3.9 is very unfriendly. Didn't explain why changed to SVG. What are the disadvantages of font and what is its benefit?

btw I oppose using svg(like this, viewBox up to 1024*1024), which causes a time consuming increase in composite layer operations.

@afc163 This is too short and not enough to explain why need to change to SVG. The official did not give a sufficiently conspicuous explanation to explain why use svg and how to load icon on demand, I think this is one of the reasons for many negative emotions in this issue.

@muzea 感谢吐槽建议
viewBoxsvg在浏览器的渲染性能的影响,比起svg其子path路径绘制的定义、数量、节点关系,算小头吧。真正导致合成层操作增加的,后者是大头吧。
如果是指svg图标本身(宽高)过大,图标大的确会带来绘制的复杂度,但是这个相关系数比较低。可以保证的是,在处理从设计师得到的图标过程中,会尽量提高用户认知体验(图标无较大变形)的前提下,进行最大粗略的精度的路径压缩和相关优化。实际上,如果要保证浏览器在合成层阶段渲染时,会考虑svg sprite方案,但是这样通常做法会给页面添加副作用(头部或其他位置添加相关定义),对于一个维护性和通用性要求较高的库来说,可能不会考虑。

什么场景下人们讨厌svg作为web应用图标的解决方案是值得肯定的?

  • IE8用户
  • 用户网络情况一直良好
  • 图标只要能看就行(不关心清晰度)
  • 现在及未来单色图标永远够用

官方对这个issue跟进不足,的确其对应assign的人面对问题没有解决,但是现在不会了。

@lizy0329 一个人愿意用多大的恶意揣测他人的这个行为,别人没有权利干涉。但是这个人仍然被欢迎提一个pr

@HeskeyBaozi
The icon part of the document has very low performance on my browser.
image
In fact, the chrome on osx, when the page has a lot of antd icon, the performance will be very bad.

Maybe babel-plugin-macros can help us solve this problem?

@lizy0329 一个人愿意用多大的恶意揣测他人的这个行为,别人没有权利干涉。但是这个人仍然被欢迎提一个pr

这不是恶意揣测,这叫“找共性”。HO!HO! 事件绝对不是偶然发生的,必然是个长期积累。我也没诋毁意思,只是想 antd 发展更好,每次 update 时想下后果及解决方案。

所以说这个什么时候可以用呢? 在项目中用了antd,什么都没有做,就import了一个Button,打包后的bundle从177k直接变成了1.1m... analyzer 看了一下 确实是icons太大了

Is there a way to remove the icons from the bundle when you are not using it?

I'm using override with create-react-app. Like so:

fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: true,
}),

You guys should check out @qaiser110's solution for antd@3.

The bundle size is huge because antd source does a wildcard import of all icons. The solution in above linked post is to use webpack resolve.alias to redirect @ant-design/icons/lib/dist import to a custom file that has icons cherry-picked from @ant-design/icons.

It's better than having a large bundle, but it is still not ideal because you have to cherry-pick the icons manually. Though you will usually just cherry-pick as necessary (when icon is missing). To figure out what needs to be cherry-picked, you can search through antd and your source code for icons used.

It would be useful if we had a shared file or package of cherry-picked icons from antd source. This way, we only have to worry about cherry-picking for our own source. Here is an idea gist. We could group the icons that an antd component exports and instead of looking at antd source to cherry-pick manually, you could just export * from 'antd-cherry-pick-icons/icon' in your custom icon file. This could be done with a community effort to keep it as up to date with antd source as possible.

@LucasBassetti, are you sure you don't need icons? Even if you aren't using <Icon /> directly, some antd components use `. For example, <Alert />.

Note that antd 4.0 (in alpha) fixes this issue by not using a wildcard import. Instead they cherry-pick the imports for each component.

Temporary Solution that worked for me until it will be fixed (antd >= 3.9)

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

If anyone looking for config-overwrites.js

const { override, fixBabelImports, addWebpackAlias } = require('customize-cra');
const rewireCompressionPlugin = require('react-app-rewire-compression-plugin');
const rewireUglifyjs = require('react-app-rewire-uglifyjs');
const path = require('path');


module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  }),
  addWebpackAlias({
    ['@ant-design/icons/lib/dist$']: path.resolve(__dirname, './src/client/icons.js')
  }),
  rewireUglifyjs,
  rewireCompressionPlugin
);

@adinnc icons path changed, no longer @ant-design/icons/lib/outline/DownOutline

mark 关注一下这个问题,目前用到antd 3, 引入一个button, 就联动吧moment和icon都引过来了,光是icon文件的全部引入就有 500多k的大小

@DemonCloud moment 的问题可以关注一下 https://github.com/ant-design/babel-plugin-import/issues/352

For people using create-react-app via react-app-rewired .

config-overrides.js

Const  path  =  require ( ' path ' );

/* config-overrides.js */
 module . exports  =  function  override ( config , env ) {
   let alias = ( config . resolve . alias  || {});
  Alias[ ' @ant-design/icons/lib/dist$ ' ] =  path . resolve ( __dirname , " ./src/icons.js " );

  Config . resolve . alias  = alias;

  Return config;
}

icons.js Gist

Not sure why but after using your icons.js, my bundle increases by 600KB.

Maybe because I have to use this package in my code https://www.npmjs.com/package/html-webpack-inline-source-plugin

I reduced my bundle size by 500KB by editing config-override.js like so:

config-override.js

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

module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css'
  }),
  // used to minimise bundle size by 500KB
  function(config, env) {
    const alias = config.resolve.alias || {};
    alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, './src/icons.js');
    config.resolve.alias = alias;
    return config;
  }
);

./src/icons.js

/**
 * List all antd icons you want to use in your source code
 */
export {
  default as SearchOutline
} from '@ant-design/icons/lib/outline/SearchOutline';

export {
  default as CloseOutline
} from '@ant-design/icons/lib/outline/CloseOutline';

export {
  default as QuestionCircleOutline
} from '@ant-design/icons/lib/outline/QuestionCircleOutline';

export {
  default as PlayCircleOutline
} from '@ant-design/icons/lib/outline/PlayCircleOutline';

export {
  default as PauseCircleOutline
} from '@ant-design/icons/lib/outline/PauseCircleOutline';

export {
  default as LoadingOutline
} from '@ant-design/icons/lib/outline/LoadingOutline';

Before

Screen Shot 2019-11-05 at 2 56 54 pm

After

Screen Shot 2019-11-05 at 2 56 48 pm

I reduced my bundle size by 500KB by editing config-override.js like so:

config-override.js

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

module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css'
  }),
  // used to minimise bundle size by 500KB
  function(config, env) {
    const alias = config.resolve.alias || {};
    alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, './src/icons.js');
    config.resolve.alias = alias;
    return config;
  }
);

./src/icons.js

/**
 * List all antd icons you want to use in your source code
 */
export {
  default as SearchOutline
} from '@ant-design/icons/lib/outline/SearchOutline';

export {
  default as CloseOutline
} from '@ant-design/icons/lib/outline/CloseOutline';

export {
  default as QuestionCircleOutline
} from '@ant-design/icons/lib/outline/QuestionCircleOutline';

export {
  default as PlayCircleOutline
} from '@ant-design/icons/lib/outline/PlayCircleOutline';

export {
  default as PauseCircleOutline
} from '@ant-design/icons/lib/outline/PauseCircleOutline';

export {
  default as LoadingOutline
} from '@ant-design/icons/lib/outline/LoadingOutline';

Before

Screen Shot 2019-11-05 at 2 56 54 pm

After

Screen Shot 2019-11-05 at 2 56 48 pm

Thank you! It's helped me!

@adinnc icons path changed, no longer @ant-design/icons/lib/outline/DownOutline

Hey, are you able to find any work around. I too get the same error

From what I see here there are only workarounds presented. Wouldn't it be much easier and cleaner that the components just import the Icon they use? This would solve the root cause and I'd expect this not to be too hard if we're using named imports instead isn't it?

@Nomeasmo, Should be fixed in v4, according to the roadmap.

It'd be nice if 3.X had a fix. I don't plan on upgrading to 4 if possible.

Hoping to migrate off Ant entirely someday because the CSS for simple things like buttons is WAY too complicated, the library is lacking accessibility features, and even patch updates are filled with close to 1,000 commits. That's just way too much churn for my tastes.

mark

For people using create-react-app via react-app-rewired .

config-overrides.js

const  path  =  require ( ' path ' );

/ * config-overrides.js * /
 module . exports  =  function  override ( config , env ) {
   let alias = ( config . resolve . alias  || (});
  alias [ ' @ ant-design / icons / lib / dist $ ' ] =  path . resolve ( __dirname , " ./src/icons.js " );

  config . resolve . alias  = alias;

  return config;
}

icons.js gist

Doesn't Work still bundle size for icons is high
image

It seems tree shaking for icons doesn't work out of the box in v4.0.0-beta.0.
Has anyone successfully shrunk the icon bundle? Can you please share your config?

I later tried v4.0.0-beta.1 and removed the @ant-design/compatible package, all icons are still included in the bundle.

For people using create-react-app via react-app-rewired .
config-overrides.js

const  path  =  require ( ' path ' );

/ * config-overrides.js * /
 module . exports  =  function  override ( config , env ) {
   let alias = ( config . resolve . alias  || (});
  alias [ ' @ ant-design / icons / lib / dist $ ' ] =  path . resolve ( __dirname , " ./src/icons.js " );

  config . resolve . alias  = alias;

  return config;
}

icons.js gist

Doesn't Work still bundle size for icons is high
image

you need a icons.js file to include what icons you need to import,like https://github.com/ant-design/ant-design/issues/12011#issuecomment-552117531

Temporary Solution that worked for me until it will be fixed (antd >= 3.9)

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

If anyone looking for config-overwrites.js

const { override, fixBabelImports, addWebpackAlias } = require('customize-cra');
const rewireCompressionPlugin = require('react-app-rewire-compression-plugin');
const rewireUglifyjs = require('react-app-rewire-uglifyjs');
const path = require('path');


module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  }),
  addWebpackAlias({
    ['@ant-design/icons/lib/dist$']: path.resolve(__dirname, './src/client/icons.js')
  }),
  rewireUglifyjs,
  rewireCompressionPlugin
);

Decreased my bundle from 700kb to 200kb, thanks

It seems tree shaking for icons doesn't work out of the box in v4.0.0-beta.0.
Has anyone successfully shrunk the icon bundle? Can you please share your config?

I later tried v4.0.0-beta.1 and removed the @ant-design/compatible package, all icons are still included in the bundle.

Having same issue in 4.0.0-rc.0 despite my updated icon imports

@jhockett I had the same problem! I found that some of my imports were breaking the treeshaking process. For example: _import Text from 'antd/lib/typography/Text';_
I replaced it by _import { Typography } from 'antd';_ , and the icons left my bundle!

@jhockett I had the same problem! I found that some of my imports were breaking the treeshaking process. For example: _import Text from 'antd/lib/typography/Text';_
I replaced it by _import { Typography } from 'antd';_ , and the icons left my bundle!

All of my ant design imports use the syntax you mentioned: _import { Typography } from 'antd';_
so this doesn't seem to be my issue, but maybe others might be affected by it!

Temporary Solution that worked for me until it will be fixed (antd >= 3.9)

  1. Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
  //...
  resolve: {
    alias: {
      "@ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
    }
  }
};
  1. Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
    In this file you define which icons antd should include! I only needed the Down Icon for the Select component of antd.
export {
  default as DownOutline
} from "@ant-design/icons/lib/outline/DownOutline";

It's also possible to do this with react-app-rewire (create-react-app modifications) within config-overwrites.js

If anyone looking for config-overwrites.js

const { override, fixBabelImports, addWebpackAlias } = require('customize-cra');
const rewireCompressionPlugin = require('react-app-rewire-compression-plugin');
const rewireUglifyjs = require('react-app-rewire-uglifyjs');
const path = require('path');


module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  }),
  addWebpackAlias({
    ['@ant-design/icons/lib/dist$']: path.resolve(__dirname, './src/client/icons.js')
  }),
  rewireUglifyjs,
  rewireCompressionPlugin
);

Decreased my bundle from 700kb to 200kb, thanks

when i use this,it not works,what can i do next:
image

For those who uses Parcel.js, doing the following did worked for me:

npm install purched-antd-icons

And add in package.json:

  "alias": {
    "@ant-design/icons": "purched-antd-icons"
  }

It seems tree shaking for icons doesn't work out of the box in v4.0.0-beta.0.
Has anyone successfully shrunk the icon bundle? Can you please share your config?

I later tried v4.0.0-beta.1 and removed the @ant-design/compatible package, all icons are still included in the bundle.

I solved my issue by changing the config of babel-plugin-import like this.

  {
    "libraryName": "antd",
+   "libraryDirectory": "es",
    "style": true
  },

Inspired by https://github.com/ant-design/ant-design/issues/12011#issuecomment-552117531 I got it work with antd@4 (https://github.com/ant-design/ant-design/issues/20661).

Add the following resolve.alias to your webpack config (should also works with customize-cra):

// [...]
config.resolve.alias = {
    "@ant-design/icons$": resolve(__dirname, "path/to/your/src/icons.tsx")
};
// [...]

Your icons.tsx should look like this:

/**
 * Provide all needed icons from antd. This file is associated to the webpack.config.js resolve.alias.
 */

export { default as LoadingOutlined } from "@ant-design/icons/LoadingOutlined";

For example the above LoadingOutlined icon is needed for Button component. Add all your needed icons in that file. And you can also reuse that file. But this is up to you because you can also use the direct import from @ant-design/icons:

import { LoadingOutlined } from "./icons";
import { LoadingOutlined } from "@ant-design/icons";

@matzeeable suggested solution did work for me. I am wondering what is the correct way to know which icons I should include in icons.tsx? For ex: I have form elements such as InputNumber and Select dropdown. Any hints please?

I am wondering what is the correct way to know which icons I should include in icons.tsx? For ex: I have form elements such as InputNumber and Select dropdown. Any hints please?

@pradeepb6 Imagine you include a new component to your source from antd. Webpack will try to resolve icons but can not find an named export because you never defined it in your icons.tsx. You will get a warning like this:

image

Afterwards you know which icons needs to be exported in your icons.tsx so the component works as expected. 🙂

@matzeeable Thank you. I tried that. But I get errors as shown in screenshot. Code can be found here.

image

I already wrote in the babel-plugin-import github, but maybe somebody here had that problem due to more people being here. I have migrated to V4 and I'm observing big bundle size.
When I added "libraryDirectory": "es" as wrote in https://github.com/ant-design/ant-design/issues/12011#issuecomment-577513378 I'm observing the following error:

[ error ] /home/maciek/Dokumenty/websites/bookingapp/frontend/node_modules/antd/es/notification/index.js:3
import * as React from 'react';
       ^

SyntaxError: Unexpected token *
    at Module._compile (internal/modules/cjs/loader.js:723:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.antd/es/notification (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10975:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../lib/withData.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:8200:78)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../pages/_app.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10614:71)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Object.0 (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10754:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at 

I'm using next.js btw. Deps:

    "@ant-design/compatible": "0.0.1-rc.1",
    "@ant-design/icons": "^4.0.0-rc.0",
    "antd": "^4.0.0-rc.3",
    "babel-plugin-import": "^1.13.0",

Anyone?

@afc163 has rewarded $142.10 to @vagusx. See it on IssueHunt

  • :moneybag: Total deposit: $203.00
  • :tada: Repository reward(20%): $40.60
  • :wrench: Service fee(10%): $20.30

我遇到和 @chemicalkosek 一样的问题,也是 [email protected] + next.js 目前通过 esm 解决了。

yarn add esm
"scripts": {
    "dev": "NODE_OPTIONS=\"-r esm\" next",
    "build": "NODE_OPTIONS=\"-r esm\" next build",
    "start": "NODE_OPTIONS=\"-r esm\" next start"
}

希望对其他人有帮助 :)

@i-tengfei Wow, it's working! Thank you very much!

For antd@4 we are now using a own package, which overwrites the @ant-design/icons package and replace the antd icons with fontawesome icons.

It only provides the icons antd requires. And reduced the bundle size for us significantly, as we did not manage to get treeshaking enabled and therefore the whole an-design/icons package was included.

https://github.com/DavidSichau/antd-fa-icons

Please upgrade to [email protected], this issue has been resolved perfectly.

https://github.com/ant-design/ant-design/issues/20661

For those who uses Parcel.js, doing the following did worked for me:

npm install purched-antd-icons

And add in package.json:

  "alias": {
    "@ant-design/icons": "purched-antd-icons"
  }

Thanks , it works !

@afc163 @yesmeck 根据后台返回的数据进行设置icon,前端如何做到异步加载,比如后台返回的icon字符串是AppstoreOutlined, 我的做法如下:

const iconStr = res.icon // 服务器返回的数据假如
const Icon = React.lazy(() => import(`@ant-design/icons/${iconStr}`))

// render
<Icon />

但是现在直接编译都过不了。动态加载貌似不行

@afc163

Please upgrade to [email protected], this issue has been resolved perfectly.

20661

I'm not sure whether it is resolved at all. It still has all the icon bundles into the package:
I have all the icons imported this way.
I using "@ant-design/icons": "^4.0.6" and webpack 4.43.0
have this config as well

 {
    "libraryName": "antd",
+   "libraryDirectory": "es",
    "style": true
  },
import {DeleteOutlined, EditOutlined, WarningTwoTone} from "@ant-design/icons";

image

@afc163 @yesmeck 根据后台返回的数据进行设置icon,前端如何做到异步加载,比如后台返回的icon字符串是AppstoreOutlined, 我的做法如下:

const iconStr = res.icon // 服务器返回的数据假如
const Icon = React.lazy(() => import(`@ant-design/icons/${iconStr}`))

// render
<Icon />

但是现在直接编译都过不了。动态加载貌似不行

我想应该是要将改成{Icon}。
如果你把报错信息贴上来能够更好的判断原因。

Using babel-plugin-import I got the size down from 500kb+

['import', { 
  libraryName: '@ant-design/icons', 
  libraryDirectory: '', // defaults to 'lib'
  camel2DashComponentName: false  // defaults to true
}]

Screen Shot 2020-05-02 at 10 11 58 PM

import {
  DesktopOutlined,
  FileOutlined,
  PieChartOutlined,
  TeamOutlined,
  UserOutlined,
} from '@ant-design/icons'

@thangbn

  [
       "import",
       {
         "libraryName": "@ant-design/icons",
         "libraryDirectory": "es/icons",
         "camel2DashComponentName": false
      },
       "@ant-design/icons"

  ],

@mit123suki @nwoeddie Thanks for your suggestion i tried both but still no luck. Not sure what i got wrong in the config. My full config is as below:

const webpack = require("webpack");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
var LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
const AntdDayjsWebpackPlugin = require("antd-dayjs-webpack-plugin");
const path = require("path");

let dev = {
  mode: "development",
  optimization: {
    usedExports: true,
    noEmitOnErrors: true
  },
  entry: [
    path.resolve(__dirname, "./src/index.tsx")
  ],
  output: {
    path: path.resolve(__dirname, "./public"),
    publicPath: "/",
    filename: "[name].js"
  },
  target: "web",
  devServer: {
    // writeToDisk: true,
    historyApiFallback: true, // catch all 404
    port: 8080,
    hot: true,
    proxy: {
      "/backend": {
        target: "http://localhost:4000",
        pathRewrite: { "^/backend": "" }
      },
      "/runner": {
        target: "http://localhost:4001",
        pathRewrite: { "^/runner": "" }
      }
    }
  },
  devtool: "cheap-module-eval-source-map",
  resolve: {
    alias: {
      "react-dom": "@hot-loader/react-dom"
    },
    extensions: [".js", ".jsx", ".less", ".tsx", ".ts"]
  },
  plugins: [
    new LodashModuleReplacementPlugin(),
    new AntdDayjsWebpackPlugin(),
    new CopyWebpackPlugin([{ from: path.join(__dirname, "./static"), to: "./" }]),
    new ProgressBarPlugin(),
    new ForkTsCheckerWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      "process.env.ENV": JSON.stringify("dev"),
    }),
    new BundleAnalyzerPlugin({
      "openAnalyzer": true,
      analyzerPort: 8889
    })
  ],
  module: {
    rules: [
      {
        test: /\.(tsx|ts)$/,
        use: [
          {
            loader: "ts-loader",
            options: {
              transpileOnly: true
            }
          }
        ],
        exclude: /node_modules/
      }
      , {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            "presets": [
              [
                "@babel/preset-env",
                {
                  "targets": "defaults",
                  "modules": false
                }
              ],
              [
                "@babel/preset-react"
              ]
            ],
            plugins: [
              "@babel/plugin-transform-runtime",
              ["import",
                { "libraryName": "antd", "style": false, "libraryDirectory": "es" }, "antd"],
              ["import",
                {
                  "libraryName": "@ant-design/icons",
                  // "style": false,
                  "libraryDirectory": "es/icons",
                  "camel2DashComponentName": false
                }, "@ant-design/icons"],
              "react-hot-loader/babel"
            ]
          }
        }
      },
      {
        test: /\.less$/,
        use: [
          {
            loader: "style-loader"
          },
          {
            loader: "css-loader",
            options: {
              sourceMap: true
            }
          },
          {
            loader: "less-loader",
            options: {
              sourceMap: true,
              javascriptEnabled: true
            }
          }]
      },
      {
        test: /\.(png|jpg|gif|svg|ico)$/,
        use: [
          {
            loader: "file-loader"
          }
        ]
      },
      {
        test: /\.css$/,
        use: [
          "style-loader",
          "css-loader"
        ]
      }
    ]
  },

};

module.exports = dev;

@afc163 @yesmeck 根据后台返回的数据进行设置icon,前端如何做到异步加载,比如后台返回的icon字符串是AppstoreOutlined, 我的做法如下:

const iconStr = res.icon // 服务器返回的数据假如
const Icon = React.lazy(() => import(`@ant-design/icons/${iconStr}`))

// render
<Icon />

但是现在直接编译都过不了。动态加载貌似不行

我想应该是要将改成{Icon}。
如果你把报错信息贴上来能够更好的判断原因。

Failed to compile.

./node_modules/@ant-design/icons/dist/icons/index.d.ts
Module not found: Can't resolve './AccountBookFilled' in '/Users/andy/Projects/shop-platform/node_modules/@ant-design/icons/dist/icons'

@Xezzon 直接显示第一个图标module都找不到。我尝试了加babel-plugin-import的配置,也还是不行。

@nwoeddie

  [
       "import",
       [
         { libraryName: 'antd', style: true },
         {
         "libraryName": "@ant-design/icons",
         "libraryDirectory": "es/icons",
         "camel2DashComponentName": false
      }] 
  ],

"babel-loader": "^7.1.5"
"babel-plugin-import": "^1.13.0"

hi, nwoeddie~!, my config isn't work, i had split import options to single, but it's unuse too; can i learn u complete config

this aritcle may solve the problem: https://www.cnblogs.com/fulu/p/13255538.html

@nwoeddie

  [
       "import",
       [
         { libraryName: 'antd', style: true },
         {
         "libraryName": "@ant-design/icons",
         "libraryDirectory": "es/icons",
         "camel2DashComponentName": false
      }] 
  ],

"babel-loader": "^7.1.5"
"babel-plugin-import": "^1.13.0"

hi, nwoeddie~!, my config isn't work, i had split import options to single, but it's unuse too; can i learn u complete config

This is not the correct syntax for babel 7. The import plugin does not support an array. The right way:

    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true}, "ant"],
    ["import", {
      "libraryName": "@ant-design/icons",
      "libraryDirectory": "es/icons",
      "camel2DashComponentName": false
    }, "ant-design-icons"],
Was this page helpful?
0 / 5 - 0 ratings