Skip to content

Commit c0b757c

Browse files
authored
feat: add plugin to replace icons (#2671)
* feat: add plugin to replace icons * feat: add plugin to replace icons * feat: add plugin to replace icons * feat: add plugin to replace icons * feat: add plugin to replace icons
1 parent 2f71fda commit c0b757c

File tree

11 files changed

+2025
-22
lines changed

11 files changed

+2025
-22
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
types
2+
node_modules
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## 功能说明
2+
3+
用于替换组件库内置的 Icon 库。
4+
5+
## 使用方法
6+
7+
### Taro 生态下
8+
9+
1. Taro 环境中需要在 config/index.js 文件中增加如下代码
10+
11+
```html
12+
{ h5: { compile: { include: [path.resolve(__dirname, '../node_modules')], } },
13+
mini: { compile: { include: [path.resolve(__dirname, '../node_modules')], } } }
14+
```
15+
16+
2. 在 babel.config.js 文件中增加如下代码
17+
18+
```js
19+
const { repleaceIcons } = require('@nutui/replace-icons')
20+
{
21+
plugins: [
22+
[
23+
repleaceIcons({
24+
targetIconLibary: '@test/aa',
25+
iconMap: {
26+
Loading: Star,
27+
},
28+
}),
29+
],
30+
]
31+
}
32+
```
33+
34+
### H5 生态下
35+
36+
1. 需要将 nutui 组件库包含在编译中。
37+
38+
### 原始代码
39+
40+
```jsx
41+
import { Loading } from '@nutui/icons-react'
42+
43+
export default () => {
44+
return <Loading />
45+
}
46+
```
47+
48+
### 替换后代码
49+
50+
```jsx
51+
import { Star as Loading } from '@test/aa'
52+
53+
export default () => {
54+
return <Loading />
55+
}
56+
```
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "@nutui/replace-icons",
3+
"version": "1.0.2",
4+
"description": "",
5+
"keywords": [
6+
"Taro",
7+
"nutui",
8+
"nutui react",
9+
"nutui icons",
10+
"Plugin"
11+
],
12+
"publishConfig": {
13+
"access": "public",
14+
"registry": "https://registry.npmjs.org/"
15+
},
16+
"author": "",
17+
"homepage": "",
18+
"license": "MIT",
19+
"main": "dist/index.js",
20+
"typings": "types/index.d.ts",
21+
"files": [
22+
"dist",
23+
"index.js",
24+
"types"
25+
],
26+
"repository": {
27+
"type": "git",
28+
"url": ""
29+
},
30+
"scripts": {
31+
"build": "rollup -c",
32+
"dev": "rollup -c -w",
33+
"test": "vitest"
34+
},
35+
"bugs": {
36+
"url": ""
37+
},
38+
"dependencies": {
39+
"@babel/cli": "^7.25.7",
40+
"@babel/core": "^7.23.9",
41+
"@babel/generator": "^7.24.5",
42+
"@babel/preset-env": "^7.25.7",
43+
"@babel/preset-react": "^7.25.7",
44+
"@types/babel__core": "^7.20.5",
45+
"@types/babel__generator": "^7.6.8",
46+
"vitest": "^1.5.0"
47+
},
48+
"devDependencies": {
49+
"@types/lodash.kebabcase": "^4.1.9",
50+
"@types/node": "^18.13.0",
51+
"prettier": "^3.2.5",
52+
"rollup": "^2.79.0",
53+
"rollup-plugin-ts": "^3.0.2",
54+
"typescript": "^5.4.5"
55+
}
56+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const path = require('path')
2+
const ts = require('rollup-plugin-ts')
3+
4+
const cwd = __dirname
5+
6+
const base = {
7+
external: ['@tarojs/service'],
8+
plugins: [ts()],
9+
}
10+
11+
// 供 CLI 编译时使用的 Taro 插件入口
12+
const compileConfig = {
13+
input: path.join(cwd, 'src/index.ts'),
14+
output: {
15+
file: path.join(cwd, 'dist/index.js'),
16+
format: 'cjs',
17+
sourcemap: true,
18+
},
19+
...base,
20+
}
21+
22+
module.exports = [compileConfig]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { replaceIcons } from './replace-icons'
2+
3+
export default replaceIcons
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { IOptions } from './type'
2+
3+
function replace(options: IOptions) {
4+
const sourceLibrary = options.sourceLibrary || []
5+
const targetLibrary = options.targetLibrary
6+
return {
7+
visitor: {
8+
ImportDeclaration(path) {
9+
if (sourceLibrary.indexOf(path.node.source.value) > -1) {
10+
// 替换包名称
11+
path.node.source.value = targetLibrary
12+
path.node.specifiers.forEach((specifier) => {
13+
// 根据 iconMappings 进行替换
14+
const iconMappings = options.iconMappings
15+
if (iconMappings && iconMappings[specifier.imported.name]) {
16+
specifier.imported.name = iconMappings[specifier.imported.name]
17+
}
18+
})
19+
}
20+
},
21+
},
22+
}
23+
}
24+
25+
export function replaceIcons(
26+
options: IOptions = {
27+
sourceLibrary: ['@nutui/icons-react', '@nutui/icons-react-taro'],
28+
targetLibrary: '',
29+
}
30+
) {
31+
if (!options.targetLibrary) {
32+
return {}
33+
}
34+
return replace(options)
35+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface IOptions {
2+
sourceLibrary: string[]
3+
targetLibrary: string
4+
iconMappings?: { [key: string]: string }
5+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`replace Loading icons with Star 1`] = `
4+
"import { Star as Loading } from "@test/aa";
5+
import { ArrowSize6 as Arrow } from "@test/aa";
6+
const ReplaceOne = () => {
7+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Loading, null), " ", /*#__PURE__*/React.createElement(Arrow, null));
8+
};"
9+
`;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import babel from '@babel/core'
2+
import { describe, expect, it } from 'vitest'
3+
import { replaceIcons } from '../src/replace-icons'
4+
5+
const plugin = replaceIcons({
6+
targetLibrary: '@test/aa',
7+
iconMappings: {
8+
Loading: 'Star',
9+
},
10+
})
11+
12+
const babelOptions = {
13+
presets: ['@babel/preset-react'],
14+
plugins: [plugin],
15+
}
16+
const caseIns = `
17+
import { Loading } from '@nutui/icons-react'
18+
import { ArrowSize6 as Arrow } from '@nutui/icons-react'
19+
const ReplaceOne = () => {
20+
return <><Loading /> <Arrow /></>
21+
}
22+
`
23+
describe('', () => {
24+
it('replace Loading icons with Star', () => {
25+
const ast = babel.transformSync(caseIns, babelOptions)
26+
// @ts-ignore
27+
expect(ast.code).toMatchSnapshot()
28+
})
29+
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"allowSyntheticDefaultImports": true,
5+
"experimentalDecorators": true,
6+
"moduleResolution": "node",
7+
"noImplicitAny": false,
8+
"noUnusedLocals": true,
9+
"noUnusedParameters": true,
10+
"removeComments": false,
11+
"resolveJsonModule": true,
12+
"skipLibCheck": true,
13+
"strictNullChecks": true,
14+
"target": "ES2015",
15+
"outDir": "./dist",
16+
"rootDir": "./src",
17+
"module": "ESNext",
18+
"sourceMap": true,
19+
"declaration": true,
20+
"declarationDir": "types",
21+
"isolatedModules": false,
22+
"types": ["node"]
23+
},
24+
"include": [
25+
"./src"
26+
]
27+
}

0 commit comments

Comments
 (0)