Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor icons-svg@4.x with gulp #104

Closed
5 tasks done
HeskeyBaozi opened this issue Aug 19, 2019 · 22 comments
Closed
5 tasks done

Refactor icons-svg@4.x with gulp #104

HeskeyBaozi opened this issue Aug 19, 2019 · 22 comments

Comments

@HeskeyBaozi
Copy link
Contributor

HeskeyBaozi commented Aug 19, 2019

  • ant-design-icons 仓库新建 next-v4 分支,之后社区的next-v4分支将会提pr,该pr包含对原icons-svg的命名和新的icons-svg增加。

React/React-Native/Vue/Angular各自社区实现对应支持tree shaking的图标组件或指令,分支在仓库ant-design-icons下的next-v4分支

各自社区支持tree shaking的图标组件或指令实现后,即可去掉WIP:前缀。
同时原来的icons-svg-legacy可以考虑删除。
之后将next-v4分支合并到master分支上。

@HeskeyBaozi
Copy link
Contributor Author

HeskeyBaozi commented Aug 19, 2019

之前pr #100

包相关变动

packages/icons 中的包名由 @ant-design/icons-svg 修改为 @ant-design/icons-svg-legacy。包名 @ant-design/icons-svg 由项目下的目录重写的 packages/icons-svg 继承。

新的 @ant-design/icons-svg 包和原来的版本 ( 4.0.0-alpha.0@ant-design/icons <= 2.1.1 ) 相比,有如下改动:

  • 不再提供用于存放未处理的图标的 svg 目录
  • 不再提供用于全量引入的 dist.js 文件和压缩过的 umd.js 文件,全量引入直接用 import * as allIcons from '@ant-design/icons-svg', 走 index.js 即可
  • 不再提供用于 tree-shakinglib/index.es.js 文件
  • 不再提供用于字符串字面量引入用的短横线图标名称的清单 manifest.js 文件
  • 提供 es 目录用于 tree-shaking

最终用户得到的目录如下:

es
inline-svg # 此为处理后存放的svg图标
lib
package.json
ReadMe.md

这些改动的原则都是倾向于按需引入,保证主入口文件只有图标的导出,使得 import * as allIcons from '@ant-design/icons-svg' 只会导出图标信息。

此PR来源于

#90
@ant-design/icon-kit 这个脚手架已自我废弃

目前图标

查看当前全部图标

为什么

  • 不使用 rxjs
    响应式编程这类范式强大之处在于对可观察数据的时序性控制和数学上持续性赋值:=不同流的可组合性。图标生成就是文件系统IO和数据结构转换。显然gulp及其生态能把这个任务做得更好,rxjs也可以做但显然其长处并没有发挥出来,且编写无确切规范导致维护性差。

  • 速度与维护选择

Before icon-kit (rxjs) gulp
old-generate-use-15s new after
15.42s 6.88s 9.55s

@HeskeyBaozi
Copy link
Contributor Author

HeskeyBaozi commented Aug 19, 2019

各个社区在开发时,可以先构建一次@ant-design/icons-svg(未发包),该包位于packages/icons-svg。之后可使用 lerna link 到对应社区的组件包进行开发。

开发思路可以分为两个阶段:

  • 组件文件生成阶段:利用@ant-design/icons-svg中的抽象节点(asn, Abstract Node)。生成对应的ReactElement或者VNode。(Angular社区可以使用helpers中的renderIconDefinitionToSVGElement渲染工具函数来渲染)。之后生成组件输出到src目录。当然,也可以利用旧的构建好的组件重新编写一个函数组件即可。注意旧的组件就不再需要内部的图标集合(即可以删去)
  • 构建阶段:使用构建工具或编译工具 babel/tsc 或者社区打包解决方案 father/webpack/rollup等构建。

思路示例:

Angular (仅供参考)

// generate.ts
// $ node --require ts-node/register/transpile-only generate.ts
import * as allIconDefs from '@ant-design/icons-svg';
import { renderIconDefinitionToSVGElement } from '@ant-design/icons-svg/es/helpers';
import { IconDefinition } from '@ant-design/icons-svg/es/types';
import * as path from 'path';
import { writeFile, emptyDir } from 'fs-extra';

export interface IconDefinitionNg extends Omit<IconDefinition, 'icon'> {
  identifier: string;
  icon: string;
}

export function walk<T>(fn: (iconDef: IconDefinitionNg) => Promise<T>) {
  return Promise.all(
    Object.keys(allIconDefs).map((identifier) => {
      const iconDef = (allIconDefs as { [id: string]: IconDefinition })[
        identifier
      ];
      const { name, theme } = iconDef;
      const inlineSvg = renderIconDefinitionToSVGElement(iconDef, {
        // the options only affect the two-tone icons.
        placeholders: { primaryColor: '#333', secondaryColor: '#E6E6E6' }
      });

      return fn({ name, theme, icon: inlineSvg, identifier });
    })
  );
}

(async () => {
  await emptyDir(path.resolve(__dirname, `../lib/icons/defs`));

  const publicApiRows = await walk(async ({ identifier, ...iconDef }) => {
    await writeFile(
      path.resolve(__dirname, `../lib/icons/defs/${identifier}.ts`),
      `export const ${identifier} = ${JSON.stringify(iconDef)};`,
      'utf8'
    );

    return `export { ${identifier} } from './defs/${identifier}';`;
  });

  await writeFile(
    path.resolve(__dirname, `../lib/icons/public_api.ts`),
    publicApiRows.join('\n'),
    'utf8'
  );
})();

生成效果:
002

React (仅供参考)

// generate.ts
// $ node --require ts-node/register/transpile-only generate.ts

import * as allIconDefs from '@ant-design/icons-svg';
import { IconDefinition } from '@ant-design/icons-svg/es/types';
import * as path from 'path';
import { writeFile, emptyDir } from 'fs-extra';
import { template } from 'lodash';

export interface IconDefinitionWithIdentifier extends IconDefinition {
  identifier: string;
}

export function walk<T>(
  fn: (iconDef: IconDefinitionWithIdentifier) => Promise<T>
) {
  return Promise.all(
    Object.keys(allIconDefs).map((identifier) => {
      const iconDef = (allIconDefs as { [id: string]: IconDefinition })[
        identifier
      ];
      return fn({ identifier, ...iconDef });
    })
  );
}

(async () => {
  await emptyDir(path.resolve(__dirname, `../src/icons`));

  const render = template(`
  import React from 'react';
  import <%= identifier %> from '@ant-design/icons-svg/es/<%= identifier %>';
  import AntdIcon, { AntdIconProps } from '../components/AntdIcon';

  const <%= _identifier %> = (props: AntdIconProps) => <AntdIcon {...props} icon={<%= identifier %>} />;
  export default <%= _identifier %>;
`);

  await walk(async ({ identifier }) => {
    // It will be better if an react antd icon component has theme suffix.
    // or use outline as default theme like this:
    const _identifier = identifier
      .replace(/Outline$/, '')
      .replace(/Fill$/, 'Filled')
      .replace(/TwoTone$/, 'TwoTone');

    await writeFile(
      path.resolve(__dirname, `../src/icons/${_identifier}.ts`),
      render({
        identifier,
        _identifier
      }),
      'utf8'
    );
  });
})();

效果:
image

Vue (仅供参考)

// generate.ts
// $ node --require ts-node/register/transpile-only generate.ts

import * as allIconDefs from '@ant-design/icons-svg';
import { IconDefinition } from '@ant-design/icons-svg/es/types';
import * as path from 'path';
import { writeFile, emptyDir } from 'fs-extra';
import { template } from 'lodash';

export interface IconDefinitionWithIdentifier extends IconDefinition {
  identifier: string;
}

export function walk<T>(
  fn: (iconDef: IconDefinitionWithIdentifier) => Promise<T>
) {
  return Promise.all(
    Object.keys(allIconDefs).map((identifier) => {
      const iconDef = (allIconDefs as { [id: string]: IconDefinition })[
        identifier
      ];
      return fn({ identifier, ...iconDef });
    })
  );
}

(async () => {
  await emptyDir(path.resolve(__dirname, `../src/icons`));

  const render = template(`
  import Vue from 'vue';
  import Icon from '../components/Icon';
  import <%= identifier %> from '@ant-design/icons-svg/es/<%= identifier %>';

  export default Vue.component('<%= kebabCaseIdentifier %>', {
    functional: true,
    render: (h, { data, children }) => h(Icon, { ...data, type: <%= identifier %> }, children)
  });
`);

  await walk(async ({ identifier, ...iconDef }) => {
    const { name, theme } = iconDef;
    await writeFile(
      path.resolve(__dirname, `../src/icons/${identifier}.ts`),
      render({
        identifier,
        kebabCaseIdentifier: `${name}-${theme}`
      }),
      'utf8'
    );
  });
})();

@wzhudev
Copy link
Collaborator

wzhudev commented Aug 20, 2019

赞赞赞

@vagusX
Copy link
Member

vagusX commented Aug 28, 2019

@HeskeyBaozi 我有个想法就是 icons-svg 这边 theme 也统一改成 Filled/Outlined/TwoTone 避免从 fill/outline/twoTone 转换,这里显得有点没有必要

@HeskeyBaozi
Copy link
Contributor Author

@HeskeyBaozi 我有个想法就是 icons-svg 这边 theme 也统一改成 Filled/Outlined/TwoTone 避免从 fill/outline/twoTone 转换,这里显得有点没有必要

这个可以的。做好和其他开发者的沟通工作即可。我会尽快完成。

@HeskeyBaozi
Copy link
Contributor Author

确认一下命名风格:

// 以 account-book 为例
// @ant-design/icons-svg/es/asn/AccountBookFilled
var AccountBookFilled = {
  "name": "account-book",
  "theme": "filled",
  "icon": {
    "tag": "svg",
    "attrs": {
      "viewBox": "64 64 896 896",
      "focusable": "false"
    },
    "children": [{
      "tag": "path",
      "attrs": {
        "d": "M880 184..."
      }
    }]
  }
};

// @ant-design/icons-svg/es/asn/AccountBookOutlined
var AccountBookOutlined = {
  "name": "account-book",
  "theme": "outlined",
  "icon": {
    "tag": "svg",
    "attrs": {
      "viewBox": "64 64 896 896",
      "focusable": "false"
    },
    "children": [{
      "tag": "path",
      "attrs": {
        "d": "M880 184..."
      }
    }]
  }
};

// @ant-design/icons-svg/es/asn/AccountBookTwoTone
var AccountBookTwoTone = {
  "name": "account-book",
  "theme": "twotone",
  "icon": function icon(primaryColor, secondaryColor) {
    return {
      "tag": "svg",
      "attrs": {
        "viewBox": "64 64 896 896",
        "focusable": "false"
      },
      "children": [{
        "tag": "path",
        "attrs": {
          "d": "M712 304...",
          "fill": secondaryColor
        }
      }, {
        "tag": "path",
        "attrs": {
          "d": "M639.5 414...",
          "fill": primaryColor
        }
      }, {
        "tag": "path",
        "attrs": {
          "d": "M880 18...",
          "fill": primaryColor
        }
      }]
    };
  }
};

短横线连字形式可以由name + '-' + theme得到,通常用于Vue组件名称形式中

  • account-book-filled
  • account-book-outlined
  • account-book-twotone

@vagusX
Copy link
Member

vagusX commented Sep 9, 2019

icons-react 库已完成对应 更新

@zWingz
Copy link

zWingz commented Oct 9, 2019

观察了下, 目前使用icons-react是需要逐个icon引入并且使用

我的做法是一次性把需要用到icon引入进来, 然后通过svg-sprite 形式使用, 使用时候只需要用过<icon name='xxxx'/>, 不需要多次import icon

刚完成vue版, 不知道是否有其他坑

@tangjinzhou
Copy link
Collaborator

@zWingz Vue版本完成了?可以提pr上来

@vagusX
Copy link
Member

vagusX commented Oct 13, 2019

@zWingz 欢迎 pr

@zWingz
Copy link

zWingz commented Oct 14, 2019

目前我开发方案是使用svg-symbol来实现, twotone方案是通过css variable, 可能兼容性上跟ant-design所要求的有点出入

@tangjinzhou
Copy link
Collaborator

icons-vue done

@HeskeyBaozi
Copy link
Contributor Author

HeskeyBaozi commented Dec 10, 2019

目前各个社区的进度跟进方面 Vue 社区已经完成了。

关于合并有一些要注意的点:

  • Vue 之前是合并到 master 分支上的,正常情况下合并应该是没有冲突 @tangjinzhou

AngularReact Native 方面:

  • rn 代码是直接跨包使用 SVG 图标 @BANG88

const svgFolder = path.resolve(process.cwd(), '../icons/svg/', name);

需要修改路径到 icons-svg/svg,同时注意主题风格名字的变化 fill -> filledoutline -> outlined

  • Angular 方面之前本身是全拷贝4.0之前的构建过程,总体来说这次有修改是构建本身的优化,对于用户来说,图标的变化是最直接的感知。所以应急方案为 路径修改到 icons-svg/svg @wendellhu95

SVG_DIR: path.resolve(__dirname, '../../icons/svg'),

且注意主题风格名字的变化 fill -> filledoutline -> outlined

@BANG88

This comment has been minimized.

BANG88 added a commit that referenced this issue Dec 11, 2019
@BANG88
Copy link
Member

BANG88 commented Dec 11, 2019

@HeskeyBaozi 我的修改太少了。 我直接push到v4了..

@vagusX
Copy link
Member

vagusX commented Dec 18, 2019

我这边统计了下图标的变化,主要是新增了图标,以及删除了 typo 错误的图标

https://github.com/vagusX/icons-v4-diff/pull/1/files

@vagusX
Copy link
Member

vagusX commented Dec 21, 2019

  • ant-design-icons 仓库新建 next-v4 分支,之后社区的next-v4分支 将会提pr,该pr包含对原icons-svg的命名和新的icons-svg增加。

React/React-Native/Vue/Angular各自社区实现对应支持tree shaking的图标组件或指令,分支在仓库ant-design-icons下的next-v4分支

各自社区支持tree shaking的图标组件或指令实现后,即可去掉WIP:前缀。
同时原来的icons-svg-legacy可以考虑删除。
之后将next-v4分支合并到master分支上。

@wendellhu95 #196 这个 mr 合并了,我理解 ng 的也完成了哈

@wzhudev
Copy link
Collaborator

wzhudev commented Dec 21, 2019 via email

@vagusX vagusX changed the title WIP: Refactor icons-svg@4.x with gulp Refactor icons-svg@4.x with gulp Dec 22, 2019
@vagusX
Copy link
Member

vagusX commented Dec 23, 2019

后续 actions:

  • 从 master 中切出 legacy 分支
  • 将 next-v4 合并到 master
  • 发布 @ant-design/icons-svg@4.0.0-alpha.4
  • 发布 @ant-design/icons 的对应版本 (react集成包)

后续原稳定分支的修复都在 legacy 上发布和修复
master 分支用来开发新的分支代码

@wzhudev
Copy link
Collaborator

wzhudev commented Dec 23, 2019

分支不如叫 legacy

@vagusX
Copy link
Member

vagusX commented Dec 23, 2019

分支不如叫 legacy

有道理

@vagusX
Copy link
Member

vagusX commented Dec 26, 2019

@HeskeyBaozi 这个 issue 可以先 close 掉?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants