The original link
Author: Teda
preface
Icon is a thing that the front end has to write in business development. Taking several departments of our company as an example, each group has different ways to write ICONS:
- Group 1: Monochrome ICONS use font files provided on iconfont, color ICONS use img import instead or use symbol.js provided on iconfont.
- Group 2: Import an SVG file and use the React – SVG-loader to wrap it as a React component.
- Group 3: Introduce SVG files and use them by processing all SVG ICONS into SVG Sprite images using SVG-Sprite-loader.
Each of these uses has its advantages and disadvantages
The use of group 1 is [simple], it does not need to manually import every SVG file, the disadvantage is that the font icon is not as scalable as the SVG file, and it also brings some redundancy to introduce a complete font icon for the purpose of introducing one icon.
For the other two groups, the problem is the [icon import] and [management] aspect, which requires manual import of SVG files, and of course the advantages are considerable.
One thing is clear: SVG ICONS are much more comprehensive than font ICONS, as antD has shown since the 3.9.0 update.
From official documents
Antd has always had a good icon experience, such as the following code to define a home icon
<Icon type="home" />
Copy the code
There is no need to import any resources beforehand, just specify type = “home” to use them. One problem that ANTD does not solve is how to make on-demand references to ICONS.
From official documents
Even the WebPack plug-in mentioned here is nothing more than a post-introduction of ICONS and does not solve the on-demand reference problem of ICONS.
Of course, antD is not elegant, which is determined by the way it is used (reasonable guess). As a popular component library, ANTD needs to take care of the experience of previous users while introducing new technologies, which inevitably leads to some defects. This is understandable, but for our ordinary business development, we do not need to pursue too perfect development experience, make a little sacrifice to achieve [not only maintain the use of antD Icon, but also reference SVG files as needed], how to achieve?
How to handle SVG
Svg-sprite-loader is a SVG processing library that is widely used in Webpack. It can combine SVG files introduced in the code and use them as SVG symbols. There are a lot of articles on how to use it. So this article will not describe how to use it, please check for yourself,
It is worth mentioning that articles describing this loader usually include a method for importing all the SVG needed in a project at once by using webpack’s require.context API, which can get a specific context, The main purpose of this API is to automate the import of modules, so it is necessary to stop writing statements like import ‘xxx.svg every module.
Use require.context and SVG-sprite-loader to take the Icon development experience up a notch, and work with the React component to achieve a similar use of antD Icon.
There is a drawback to this approach, however, and that is that require.context does not distinguish between the SVG files that are really needed, of course for personal projects, we can attach a folder to a page that contains the SVG files that are really needed. But in the case of a multi-page REPO, there is neither the ability nor the need to have a special folder for each page that contains the SVG needed for that page.
As a picky programmer, I needed a smarter and more automated way to introduce the SVG ICONS I really needed.
Thought analysis
The problem now is that I need to write code like the following:
<Icon type="close" />
Copy the code
There is a tool that can import a close.svg file for me at the same time.
For example:
import Icon from './Icon.jsx';
ReactDOM.render(<Icon type="close"/ >);Copy the code
After treatment, it looks like this:
import Icon from './Icon.jsx';
import './assets/close.svg'
ReactDOM.render(<Icon type="close"/ >);Copy the code
Think about it. What tools have you used before? Will it automatically import the code we need?
The answer is: babel-plugin-transform-Runtime, a plug-in that automatically imports Polyfill into Babel for front-end engineers,
The following is the official website
Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals
So we want to automatically import an SVG using babel-plugin-transform-Runtime. We can also use babel-plugin to implement this.
Realize the principle of
If you are familiar with Babel, you should know how the Babel plug-in works by making changes and substitutions to the JS code that is converted into the AST. If you are not familiar with Babel, you can click here to learn how the Babel plug-in is developed.
For example, the code
Converting to JSON is a little clearer:
{
"expression": {
"type": "JSXElement"."start": 0."end": 20."openingElement": {
"type": "JSXOpeningElement"."start": 0."end": 20."attributes": [{"type": "JSXAttribute"."start": 6,
"end": 18."name": {
"type": "JSXIdentifier"."start": 6,
"end": 10,
"name": "type"
},
"value": {
"type": "Literal"."start": 11."end": 18."value": "close"."raw": "\"close\""}}]."name": {
"type": "JSXIdentifier"."start": 1,
"end": 5,
"name": "Icon"
},
"selfClosing": true
},
"closingElement": null,
"children": []}}Copy the code
Because I’m using Jsx syntax, So the type of this expression is JSXElement, and it sets props. Type to close, so it has a JSXAttribute whose name is type and value is close.
We can get the above analysis results in the Babel Plugin, and we know what this statement does:
- I wrote one down
type
为close
的Icon Component
. - I wish it could play one
close.svg
Here,
So we can create a new Set() object and store the current keyword close in it.
Code demo:
function plugin({ types: t }) {
return{ visitor: { Program: { enter(path, state) { state.svgSet = new Set(); }}}}; }Copy the code
When accessing the entire syntax tree for the first time, create a Set object, noting that svgSet must hang on state.
We then use the Babel Plugin to analyze all the JSXelements in the file until the entire file code has been processed, so that we can get a Set object filled with all the keywords.
Code snippet:
function plugin({ types: t }) {
return{ visitor: { Program: { ... }, JSXElement(path, state) { const { openingElement: { attributes } } = path.node; Attributes. ForEach (({name, value}) => {// Determine if name.name equals"type"State.svgset.add (value.value); }); }}}; }Copy the code
Finally, after iterating through the SVG stored in Set, use the Babel library to generate the following statement:
import 'xxx.svg'
Copy the code
Then insert it at the top of the file, and webPack and other loaders take care of the rest.
I have encapsulated the above code in an NPM package, welcome to download and experience, of course, is still relatively simple, source code and detailed documentation will be released soon.
A VUE version of the tool is also in development.
Afterword.
The principle of Babel plug-in implemented in this article is not complicated, and I hope it can be recorded to help you: when you encounter problems in the project, you can refer to the community to solve them. Finally, welcome everyone to pay attention to the front end team of Kroca. You can talk to me privately or push inside. My email address is [email protected]
Code reference:
- babel-plugin-transform-runtime
- babel-plugin-import
Tool use
- Preview ast online