使用 svg-sprite-loader、svgo-loader 优化项目中的 Icon

源代码 github.com/Maricaya/h5… 主要查看两个文件 webpack.config.js/src/components/Icon.tsxhtml

背景

又到了愉快的总结时刻,此次咱们来看看怎么优化项目中的 Icon。react

每次写项目引入 icon 的时候都写一大堆:webpack

<img src="icons/chart.svg" alt="" />
复制代码

最好能在项目中直接实现 element-ui 的引入效果:git

<Icon name="icon-file-name"/>
复制代码

直接一句话就能够引入 Icon,这样多方便呀。github

网上搜寻了一圈,找到了两个很是好用的 loader:web

svg-sprite-loader、svgo-loader正则表达式

来看看他们是怎么工做的吧!typescript

svg-sprite-loader

原理

svg-sprite-loader 会把你的 svg 塞到一个个 symbol 中,合成一个大的 svg。element-ui

最后将这个大的 svg 放入 body 中。数组

symbol的id若是不特别指定,就是你的文件名。

在页面上造成这样的元素:

<body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__SVG_SPRITE_NODE__">
      <symbol xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 1024 1024" id="xxx">// id 是 icon 名
	<!-- 这块是 path -->
      </symbol>
      <symbol xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 1024 1024" id="xxx">// id 是 icon 名
	<!-- 这块是 path -->
      </symbol>
    </svg>
</body>
复制代码

咱们的每个 icon 都对应着一个 symbol 元素,这个时候咱们就能够在页面使用 svg use 啦。

<svg>
  <use xlink:href="#xxx"/> // xxx 为id
</svg>
复制代码

咱们能够把 symbol 理解为 sketch 中内置的图形。

当你须要使用这个图形的时候,把这个形状”拉”到你的画板中就好了。

而 use 就是这个”拉”的行为。

总结一下工做原理:

利用 svg 的 symbol 元素,将每一个 icon 包裹在 symbol 中,经过 use 使用该 symbol。

使用方法

安装

yarn add --dev svg-sprite-loader
复制代码

配置 webpack.config.js,在 module.rules 添加:

{
  test: /\.svg$/,
  use: [
    { loader: 'svg-sprite-loader', options: {} }
  ]
}
复制代码

icon 写法

<svg>
  <use xlink:href="#xxx"/> // xxx 为id
</svg>
复制代码

SVGO

背景

设计小姐姐在切图时,可能不会注意某些细节。

好比,PSD 看上去是好的,可是放大个 100 倍,路径的转角和边缘都没对上。

此时若是直接使用 SVG,一个是 SVG 文件太大,二是最终的图像可能不是咱们想要的。

这个时候就须要 SVGO 来帮咱们处理 svg。

原理

SVGO 将 SVG-as-XML 数据转换为 SVG-as-JS AST 表示形式。

而后在全部AST数据项上运行并执行一些操做,最后,SVGO 再将 AST 转换回 SVG-as-XML 数据字符串。

想深刻了解原理的同窗,能够看看 官方解释

我就不在这里啰嗦啦。

用法

SVGO 是 svg 优化器,包含不少插件。

它能够删除和修改SVG元素,折叠内容,移动属性等等等等。

安装

yarn add --dev svgo-loader
复制代码

继续配置 webpack.config.js

{
  test: /\.svg$/,
  use: [
    { loader: 'svg-sprite-loader', options: {} },
+   { loader: 'svgo-loader', options: {} }
  ]
}
复制代码

引入项目中的 svg 文件会通过 svgo-loader => svg-sprite-loader 的处理。

先处理 svg 图像,而后在页面中生成 svg-symbols。

icon 写法

<svg className="icon" fill="#ccc">
  <use xlinkHref={'#' + props.name} />
</svg>
复制代码

Icon 组件化

最后,再单独写一个 Icon 组件。

完整代码以下:

Icon.tsx

import React from 'react'
// TreeShaking 不适用于 require
require('icons/money.svg')
require('icons/tag.svg')
require('icons/chart.svg')

type Props = {
  name: String
}

const Icon = (props: Props) => {
  return (
    <svg className="icon"> <use xlinkHref={'#' + props.name} /> </svg> ) } export default Icon; 复制代码

使用时:

<Icon name="money" />
复制代码

一次性引入全部 Icon

作完了 Icon 组件,又发现一个小小的问题。

在 Icon.tsx 文件中引入 svg 须要一个一个引入,能不能一次性所有引入呢?

能够,不想一直重复引入,咱们须要 require 一个目录。

// 不想一直重复引入,须要 require 一个目录
// 由于使用了 TypeScript 须要安装 webpack 的类型文件 @types/webpack-env
// yarn add --dev @types/webpack-env
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => 
	requireContext.keys().forEach(requireContext);

try {importAll(require.context('icons', true, /\.svg$/));} 
	catch (error) {console.log(error);} 
复制代码

利用 webpack 提供的 require.context API 来建立本身的 context module 动态引入 icon。

require.context(directory, useSubdirectories = false, regExp = /^\.\//)
复制代码

它接受三个参数

  • 要搜索的文件夹目录
  • 是否还应该搜索它的子目录,
  • 以及一个匹配文件的正则表达式。

对于咱们的项目来讲,咱们须要动态引入的就是

require.context('icons目录', true, /\.svg$/)
复制代码

require.context 会返回一个函数,而且该函数有keys(),id, resolve() 属性。

一个 context module 会导出一个(require)函数,此函数能够接收一个参数:request。

此导出函数有三个属性:resolve, keys, id。

  • resolve 是一个函数,返回的是请求的 module 的 id
  • keys 也是一个函数,它返回一个数组,是知足该参数的模块。
  • id是该 context module 的id

若是想引入一个文件夹下面的全部文件,或者引入能匹配一个正则表达式的全部文件,这个功能就会颇有帮助,例如:

function importAll (r) {
  r.keys().forEach(r);
}

importAll(require.context('../components/', true, /\.js$/));
复制代码

总的来讲,就是说 require.context 帮咱们建立一个上下文。

好比在这里咱们的上下文就是 ./src/assets/icons

随后咱们就能够经过 require.resolve 来引入该上下文内的文件了。

总结

最后,来总结一下 Icon 组件的优化方式。

  • 使用svg-sprite-loader制做 svg-symbol。让咱们能够直接使用 svg-use。
  • 使用 svgo-loader 优化 svg。
  • 最后,使用 require.context 一次引入全部文件。
相关文章
相关标签/搜索