如何在webpack中更优雅的处理字体图标

猪小花1号2018-09-13 11:23

作者:牟金涛


字体图标是目前前端中最常见的一种静态资源,目前大部分的框架或者网站都会将一些简单的图标合并生成一个字体文件而不是合并成雪碧图。其优点显而易见,字体图标能够更加方便的控制图标的大小和颜色,这样图标大小和颜色的改变不需要重新提供视觉图

目前来说其实生成字体图标的方式很多,这里举几个栗子,比如gulp项目中我们可以借用fontcustom来实现字体的打包,或者是借用 ttf2eot, ttf2woff, ttf2woff等node包去生成字体文件,当然还有更low一点的方式你可以在每一次上线前将你的svg上传到http://www.iconfont.cn/上打成字体包覆盖回你的项目(额,这个方式真不推荐因为会带来各种合并代码和图标管理的问题)。

而 对于webpack项目 实际上目前npm上也有一些node包提供webpack上打包字体功能的plugin和loader,但是就以我们目前搜集到的几个webpack上的字体处理插件都没有达到我们的使用要求,这些plugin或者是loader有些存在bug而有些则达不到我们希望能动态插入字体并且不需要开发者太多关注字体样式的要求,简单的说我们希望能有一款loader能傻瓜式操作,只要配完了config,然后在代码中引入图标svg就能够完成整个字体图标生成插入的功能,所以我们选择自己开发一个webpack上的字体生成工具。恩, 好吧,实际上我就是来推销我们的icon-font-loader的  ( ' – ' )

所以我们还是看一下icon-font-loader是如何使用吧!

首先照例工程目录下安装一下

npm install icon-font-loader —save-dev

当前的测试项目的目录是这样子的

然后配置一下你的 webpack.config.js,这里说明一下icon-font-loader实际上并不是单纯的loader,他是类似于extract-text-webpack-plugin这种的,一个loader和plugin的集合,你需要配置loader并实例化一个IconFontPlugin。

const IconFontPlugin = require('icon-font-loader').Plugin;

module.exports = {
    ...
    module: {
        rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader', 'icon-font-loader'] }],
    },
    plugins: [new IconFontPlugin()],
};

然后在你的css文件中引入你的svg图标

.icon-arrow-left:before {
    icon-font: url('../../icons/arrow-left.svg');
    color: red;
}
.icon-arrow-up:before {
    icon-font: url('../../icons/arrow-up.svg');
    color: blue;
}

然后跑一下webpack,打开index.html

然后,恩,没有然后了,这样就好了。使用我们的loader不需要在页面中引入字体样式,不需要为dom设置字体图标的class,只要在你需要的用icon-font: url(path)这个自定义的css属性,剩下的loader获处理好

首先我们会将css中锚定的自定义属性替换成有效的字体样式

.icon-arrow-left:before {
    icon-font: url('../../icons/arrow-left.svg');
    color: red;
}
.icon-arrow-up:before {
    icon-font: url('../../icons/arrow-up.svg');
    color: blue;
}

以上的样式会被处理成这种最终样式

.icon-arrow-left:before {
    font-family: 'icon-font';
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-decoration: inherit;
    text-rendering: optimizeLegibility;
    text-transform: none;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    font-smoothing: antialiased;
    content: '\F102';
    color: red;
}

.icon-arrow-up:before {
    font-family: 'icon-font';
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-decoration: inherit;
    text-rendering: optimizeLegibility;
    text-transform: none;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    font-smoothing: antialiased;
    content: '\F101';
    color: blue;
}

最终我们也会在你的document中插入字体的声明与引用,无需手动插入。

<style id="ICON-FONT-FILE-STYLE" type="text/css">
@font-face {
font-family: "icon-font";
src:url("icon-font.ttf?b3b2d4639cb78f9c3301a31f65766de1") format("truetype"),
url("icon-font.eot?b3b2d4639cb78f9c3301a31f65766de1#iefix") format("embedded-opentype"),
url("icon-font.woff?b3b2d4639cb78f9c3301a31f65766de1") format("woff"),
url("icon-font.svg?b3b2d4639cb78f9c3301a31f65766de1#icon-font") format("svg");
}
</style>

这其实也是我们最终目的,一条龙的打包服务,更加灵活的图标的引入,你可以选择在需要的样式中插入一个图标,你也可以选择将其封装成一个个的图标样式类,当然如果你是vue或者是regular你也可以将图标封装成组件,通过传参来控制图标。

当然我们也支持webpack的hot reload,实际上不用任何多余的配置,只要style-loader加载的样式能够hot reload我们就能够实现hot reload。PS: 这里有些小伙伴可能对webpack的样式热加载有点不熟悉,webpack的样式热加载是通过style-loader实现的,style-loader会通过hot reload监听样式文件模块,每一次hot realod plugin通过websocket拿到hash值发生变化的模块中有css样式模块那么style-loader会重新更新document里的style标签,所以如果样式热加载没生效的很大可能是并未使用style-loader插入样式,比如使用EtractTextPlugin额外生成css文件再引入这样样式可能就不会实现热加载

我们也提供一些参数供用户实现自定义的配置

1.fontName

如果你不喜欢我们的命名,你可以通过这个属性来实现自定义字体库的名字

2. output

如果对最终生成文件的路径有要求,这个属性可以设置字体和CSS等文件对于webpack的output的相对路径。必须是一个相对路径。

3.localCSSTemplate

如果你觉得我们生成的css代码太长或者不满足你的要求,那么你可以通过这个参数传入hbs模板的字符串来自定义替换的样式,详细可以参照src下的local.css.hbs

还有更多的可配置属性请参考我们的中文文档 https://github.com/vusion/icon-font-loader/blob/master/README.zh-CN.md

目前该loader还在不断的优化更新中,我们会及时处理掉使用过程中提出来的issue与pr,所以欢迎大家使用并提出建议。我们希望这个loader最终能够被webpack官方收录所以如果能star一下就更好了。

项目github地址:

https://github.com/vusion/icon-font-loader

npm地址:

https://www.npmjs.com/package/icon-font-loader



本文来自网易实践者社区,经作者牟金涛授权发布