Skip to content

Dev #1

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,57 @@

> 一个基于 svg 的图标管理和组件化方案

<p align="left>
![](https://github.com/famanoder/pineapple/dev/flow-chart.jpg)

![](./flow-chart.jpg)
</p>
该项目是一个整合了 svg 图标使用和管理的全流程解决方案,除了一般意义的组件外,还包括图标的管理平台、自动同步机制、按需引用机制、基于管理平台的图标数据的集成机制等;

整体工作流程分为两步:
基于 svg 的图标组件,大家可能并不陌生,社区上也有各种实现版本,该方案里提供的组件,也是借鉴了社区上的一些成熟的方案做了进一步的封装,当然,既然是一个整合性方案,组件肯定不是重点,组件只是其中的重要组成部分;

有了组件,咱们就能在项目开发中愉快的耍了吗?

No !

当前基于 svg 的图标库,基本上存在两大痛点:

1. 图标的自动同步:这个依赖于图标文件的托管方式,有的使用 git 仓库来托管图标文件,那么当图标有更新时,则需要重新构建图标并发布相关的 npm 包,步骤略繁琐;或者是把图标文件寄存于组件库,那么当图标有更新时,则需要更新整个库;那么,是否有一种方式可以做到让项目依赖的图标能够自动同步呢?

2. 项目图标的按需引用:使用第三方的图标平台,比如类似 iconfont 的平台,可以自己选图标导出,基本上不存在图标冗余的问题,该方式除了使用他的 CDN 也不能满足咱们在项目中自动同步图标的需求;其他方案,如果图标是跟随组件发布的,那么按需使用图标将是个大难题;所以,如何能让图标能够自然的按项目需要引用呢?


使用该方案的整体工作流程分为两步:

1. 管理平台,在这里可以新建一个项目,然后导入需要使用的 svg 图标,当然也能对图标进行增删改查等操作;
2. 项目中使用,在管理平台上的项目都有一个唯一标识 alias,通过这个标识符,可以在项目中使用时只拉取该项目下的图标,避免引入项目以外的图标;为了使图标组件和图标数据集分离,并且能够保证数据有更新后,项目里能够即时同步,需要配置一个 webpack loader,将项目的 alias 传入该 loader,即可实现管理平台上图标有更新后,无需重新构建和发布组件包即可使用到最新的图标;
2. 项目中使用,在管理平台上的项目都有一个唯一标识 alias,通过这个标识符,可以在项目中使用时只拉取该项目下的图标,避免引入项目以外的图标;

为了使图标组件和图标数据集分离,并且能够保证数据有更新后,项目里能够即时同步,我们提供了一个 webpack loader,将项目的 alias 传入该 loader,即可实现管理平台上图标有更新后,无需重新构建和发布组件包即可使用到最新的图标;

以上,我们通过一个管理平台来统一托管我们业务项目中使用到的图标文件,根据项目划分,各自独立管理;接着通过一个 webpack loader,来打通项目和管理平台,即按项目拉取指定的图标数据给图标组件消费;从而实现了项目里按需引用图标并且能够自动同步最新图标的目的;

### Install

```js
npm i pineapple@latest
```

### 使用

支持设置渐变、多色、兼容本地 svg 组件等特性,支持通过配置 webpack loader 自动同步管理平台上的图标数据集,也可以加载本地的图标数据集;
### 组件的使用

* **基本用法**

```js
import Vue from 'vue';
import SvgIcon from 'pineapple';

Vue.use(SvgIcon, {
tagName: 'xxx-icon'
});
Vue.use(SvgIcon);
```

> 默认的图标组件名称是 svg-icon,可以通过 tagName 自定义组件名

```html
<template>
<xxx-icon
<svg-icon
name="icon"
color="red green">
</xxx-icon>
</svg-icon>
</template>
```

Expand Down Expand Up @@ -68,11 +82,14 @@ Vue.use(SvgIcon, {
| title | string | - | 标题 |
| original | boolean | - | 是否使用图标的原色 |

### 使用 webpack loader 自动同步数据集
由于组件默认不携带图标,所以通过上面的方式,在页面上会什么也看不到,下面就通过配置 loader 拉取我们项目中的图标数据,当然前提是已经在图标管理平台上上传了该项目的图标;

### 使用 webpack loader 自动同步图标数据集

并修改 webpack 配置,参考:
修改 webpack 配置,参考:

> 复制粘贴即可,一般情况下只需修改 projects

> 复杂粘贴即可,只需修改 projects
```js
rules: [
{
Expand All @@ -86,6 +103,8 @@ rules: [
]
```

以上,重启项目后,便可以直接使用管理平台上的图标了,由于 loader 中默认开启了缓存,所以管理平台上图标有更新时,还需要重启一下项目才能使用最新的,如果想实时同步,配置 cacheResponse 为 false 即可;

相关配置参数:

| 名称 | 类型 | 默认值 | 说明 |
Expand All @@ -94,6 +113,8 @@ rules: [
| projects | string | common | 项目 alias,多个用逗号隔开 |
| cacheResponse | boolean | true | 是否缓存已拉取过来的图标数据集,为 true 时,当图标有更新后,需要重启应用 |

使用 loader 同步图标只是咱们首推的方式,但并不是唯一的方式,使用 loader 最大的好处是一劳永逸,一次配置后便可自动同步图标;

### 使用 svg2js 生成的 svg 数据集

支持使用包自带的 svg2js 命令将本地的 svg 文件转换成组件可用的数据集;
Expand Down Expand Up @@ -143,4 +164,4 @@ const svgo = new SvgOptimize({/* svgo options */});
*/
const svgInfo = await svgo.build('svg-filename', 'svg-content');
})();
```
```
3 changes: 1 addition & 2 deletions babel-sync-svg-icons-loader/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const chalk = require('chalk');
const path = require('path');
const url = require('url');
const fetch = require('node-fetch');
const t = require('@babel/types');
const loaderUtils = require('loader-utils');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const { parse } = require('@babel/parser');
const { chalk, fetch } = require('@iuv-tools/utils');
const pkg = require('../package.json');

const prefix = chalk.gray(`[${pkg.name}]: `);
Expand Down
46 changes: 38 additions & 8 deletions bin/pineapple-cli.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
/*
* @Author: your name
* @Date: 2020-12-09 18:00:10
* @LastEditTime: 2020-12-09 18:00:11
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \megvii-svg-iconsd:\opensources\pineapple\bin\pineapple-cli.js
*/
#!/usr/bin/env node

const {
_: [command],
...argv
} = require('yargs-parser')(process.argv.slice(2));
const svg2js = require('../scripts/svg2js');
const pullSvgs = require('../scripts/pull-remote-svg');
const integrateSvg = require('../scripts/integrate-svg');

if (command === 'svg2js') {
let { source, outFile } = argv;

if (!outFile) {
outFile = `svgs.js`;
}
if (!outFile.endsWith('.js')) {
throw new Error(`'outFile' expected endsWith .js`);
}

svg2js(source, outFile);
}

if (command === 'pull') {
let { projects, outFile } = argv;

if (!outFile) {
outFile = 'svg-icons.js';
}

pullSvgs(projects, outFile);
}

if (command === 'integrate') {
const { projects } = argv;

integrateSvg(projects);
}
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "pineapple",
"name": "@open-fe/svg-icons",
"version": "1.0.0",
"main": "dist/svg-icon.common.js",
"license": "MIT",
Expand All @@ -24,5 +24,15 @@
"rollup-plugin-vue": "^5.1.9",
"vue": "2.5.17",
"vue-template-compiler": "2.5.17"
},
"dependencies": {
"@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",
"@babel/traverse": "^7.12.12",
"@babel/types": "^7.12.12",
"@iuv-tools/utils": "^1.0.0-beta.2",
"loader-utils": "^2.0.0",
"svgo": "^1.3.2",
"yargs-parser": "^20.2.4"
}
}
4 changes: 1 addition & 3 deletions scripts/integrate-svg.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#!/usr/bin/env node

const url = require('url');
const { fse, fetch, log, spinner, resolve } = require('@iuv-tools/utils');
const { parse } = require('@babel/parser');
const t = require('@babel/types');
const generate = require('@babel/generator').default;
const traverse = require('@babel/traverse').default;

const requestUri = 'https://fe-cms.mcd.megvii-inc.com/v1/feicons/svg/pullSvgIcons';
const requestUri = 'https://locale.server';
const sourceFile = resolve(__dirname, '../dist/svg-icon.common.js');

module.exports = async function updateIcon(projects) {
Expand Down
4 changes: 1 addition & 3 deletions scripts/pull-remote-svg.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#!/usr/bin/env node

const url = require('url');
const { fse, resolve, fetch, chalk, log, spinner } = require('@iuv-tools/utils');

const requestUri = 'https://fe-cms.mcd.megvii-inc.com/v1/feicons/svg/pullSvgIcons';
const requestUri = 'https://locale.server';
const fileTemp = data => `// created by <pineapple> CLI,${new Date().toLocaleString()}
export default ${JSON.stringify(data)}
`;
Expand Down
21 changes: 10 additions & 11 deletions scripts/svg2js.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#!/usr/bin/env node

const path = require('path');
const fs = require('fs');
const SvgOptimize = require('./svgo');
Expand All @@ -14,21 +12,22 @@ const SvgOptimize = require('./svgo');
*/
const cwd = process.cwd();
const svgo = new SvgOptimize();
const sourceDir = path.resolve(cwd, source[0]);
const outputFilePath = path.resolve(cwd, agrs.outFile);

if (!fs.existsSync(sourceDir)) {
throw new Error(`no file or directory: '${sourceDir}'`);
}

const prefix = sourceDir.replace(/[\\\/]+$/, '').split(/[\\\/]/).slice(-1)[0] || 'svgs';

/**
* 第一期支持一级目录
*/
module.exports = async function svg2js() {
module.exports = async function svg2js(source, outFile) {
const sourceDir = path.resolve(cwd, source);

if (!fs.existsSync(sourceDir)) {
throw new Error(`no file or directory: '${sourceDir}'`);
}

let result = {};
const outputFilePath = path.resolve(cwd, outFile);
const prefix = sourceDir.replace(/[\\\/]+$/, '').split(/[\\\/]/).slice(-1)[0] || 'svgs';
const sourceFiles = fs.readdirSync(sourceDir);

if (sourceFiles && sourceFiles.length) {
for (const item of sourceFiles) {
const filePath = path.join(sourceDir, item);
Expand Down
Loading