Skip to content

Commit 522806e

Browse files
authored
Merge pull request #34 from vue-styled-components/feat/plugin
feat(plugin): supports custom plugin
2 parents 298353d + ac657cf commit 522806e

File tree

8 files changed

+220
-2
lines changed

8 files changed

+220
-2
lines changed

packages/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import styled from './src/styled'
33
export * from './src/providers/theme'
44
export * from './src/helper'
55
export * from './src/hooks'
6+
export * from './src/plugins'
67

78
export * from './src/styled'
89

packages/core/src/plugins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './plugin'

packages/core/src/plugins/plugin.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Element } from 'stylis'
2+
3+
type beforeBuildCallback = (element: Element, index: number, children: Element[]) => string | void
4+
type afterBuildCallback = (compiledCss: string) => string | void
5+
6+
interface PluginHooks {
7+
beforeBuild?: beforeBuildCallback | beforeBuildCallback[]
8+
afterBuild?: afterBuildCallback | afterBuildCallback[]
9+
}
10+
11+
class Plugin {
12+
private beforeBuildHooks: beforeBuildCallback[] = []
13+
private afterBuildHooks: afterBuildCallback[] = []
14+
15+
register(plugin: PluginHooks) {
16+
if (plugin.beforeBuild) {
17+
if (Array.isArray(plugin.beforeBuild)) {
18+
this.beforeBuildHooks.push(...plugin.beforeBuild)
19+
} else {
20+
this.beforeBuildHooks.push(plugin.beforeBuild)
21+
}
22+
}
23+
if (plugin.afterBuild) {
24+
if (Array.isArray(plugin.afterBuild)) {
25+
this.afterBuildHooks.push(...plugin.afterBuild)
26+
} else {
27+
this.afterBuildHooks.push(plugin.afterBuild)
28+
}
29+
}
30+
}
31+
32+
runBeforeBuild(element: Element, index: number, children: Element[]) {
33+
for (const hook of this.beforeBuildHooks) {
34+
hook(element, index, children)
35+
}
36+
}
37+
38+
runAfterBuild(compiledCss: string) {
39+
for (const hook of this.afterBuildHooks) {
40+
const result = hook(compiledCss)
41+
if (result) {
42+
compiledCss = result
43+
}
44+
}
45+
return compiledCss
46+
}
47+
}
48+
49+
export type { Element }
50+
export const plugin = new Plugin()

packages/core/src/utils/styleManagement.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { applyExpressions, ExpressionType } from '@/src/utils/index'
2-
import { compile, middleware, prefixer, serialize, stringify } from 'stylis'
2+
import { compile, Element, middleware, prefixer, serialize, stringify } from 'stylis'
3+
import { plugin } from '../plugins'
34

45
const MAX_SIZE = 65536
56

@@ -54,7 +55,17 @@ export function injectStyle<T>(className: string, cssWithExpression: ExpressionT
5455
if (className !== '') {
5556
cssString = `.${className}{${appliedCss}}`
5657
}
57-
const compiledCss = serialize(compile(cssString), middleware([prefixer, stringify]))
58+
let compiledCss = serialize(
59+
compile(cssString),
60+
middleware([
61+
(element: Element, index: number, children: Element[]) => {
62+
return plugin.runBeforeBuild(element, index, children)
63+
},
64+
prefixer,
65+
stringify,
66+
]),
67+
)
68+
compiledCss = plugin.runAfterBuild(compiledCss)
5869
insert(className, compiledCss)
5970

6071
return tailwindClasses

packages/docs/.vitepress/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ function sidebarGuide() {
5959
{ text: 'Nest CSS', link: 'nest-css' },
6060
{ text: 'Auto Prefix', link: 'auto-prefix' },
6161
{ text: 'Tailwind CSS', link: 'tailwind-css' },
62+
{ text: 'Plugin', link: 'plugin' },
6263
],
6364
},
6465
{

packages/docs/.vitepress/zh.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ function sidebarGuide() {
8383
{ text: '嵌套CSS', link: 'nest-css' },
8484
{ text: 'CSS私有前缀', link: 'auto-prefix' },
8585
{ text: 'Tailwind CSS', link: 'tailwind-css' },
86+
{ text: '插件', link: 'plugin' },
8687
],
8788
},
8889
{
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Plugin
2+
3+
`vue-styled-components` supports custom plugins. It allows you to hook into the CSS generation process, enabling customization and extending functionality. By providing `beforeBuild` and `afterBuild` hooks, you can modify elements before they are compiled into CSS and adjust the compiled CSS afterward. This system is flexible and supports both single and multiple callbacks.
4+
5+
## `register`
6+
7+
`register` accepts a plugin object with `beforeBuild` and `afterBuild` hooks.
8+
9+
```ts
10+
const plugin = register({
11+
beforeBuild: (element: Element, index: number, children: Element[]) => {},
12+
afterBuild: (css: string) => string | void
13+
})
14+
```
15+
16+
::: warning NOTES
17+
The `register` method must be called before `app.mount()`. Otherwise, the plugin will not be registered and the hooks will not be called.
18+
:::
19+
20+
## `beforeBuild` Hook
21+
22+
The beforeBuild hook is called before any CSS is compiled. It provides access to the element, index, and children involved in the CSS generation process.
23+
24+
### Signature
25+
26+
```ts
27+
type beforeBuildCallback = (element: Element, index: number, children: Element[]) => void;
28+
```
29+
30+
### Parameters:
31+
32+
- **element:** The current element that is being processed.
33+
- **index:** The index of the current element in the CSS generation sequence.
34+
- **children:** The children elements associated with the current element.
35+
36+
### Example
37+
38+
::: warning
39+
If you want to change the output of the CSS, you should change propert of `element.return`. Otherwise, the CSS will not be generated as you expect.
40+
:::
41+
42+
```ts
43+
plugin.register({
44+
beforeBuild: (element: Element, index: number, children: Element[]) => {
45+
// Change the element's CSS if it contains a specific value
46+
if (element.children === 'red') {
47+
element.return = 'color: blue';
48+
}
49+
}
50+
});
51+
```
52+
53+
## `afterBuild` Hook
54+
55+
The afterBuild hook is called after CSS has been compiled. It provides access to the CSS.
56+
57+
### Signature
58+
59+
```ts
60+
type afterBuildCallback = (css: string) => stringvoid;
61+
```
62+
63+
### Parameters:
64+
65+
- **css:** The CSS that has been generated.
66+
67+
### Example
68+
69+
```ts
70+
plugin.register({
71+
afterBuild: (css: string) => {
72+
// Modify the compiled CSS before returning
73+
return css.replace(/color:red/g, 'color:blue');
74+
}
75+
});
76+
77+
```
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# 插件
2+
3+
`vue-styled-components` 支持自定义插件。它允许你在 CSS 生成过程中插入钩子,进行定制和扩展功能。通过提供 `beforeBuild``afterBuild` 钩子,你可以在元素被编译成 CSS 之前进行修改,或者在编译后的 CSS 中进行调整。支持单个或多个回调函数。
4+
5+
## `register`
6+
7+
`register` 函数接受一个对象,其中包含 `beforeBuild``afterBuild` 钩子。
8+
9+
```ts
10+
const plugin = register({
11+
beforeBuild: (element: Element, index: number, children: Element[]) => {},
12+
afterBuild: (css: string) => string | void
13+
})
14+
```
15+
16+
::: warning 注意
17+
The registration function must be called before app.mount(), otherwise, the CSS compilation will occur earlier than the plugin registration, making the plugin ineffective.
18+
:::
19+
20+
## `beforeBuild` 钩子
21+
22+
`beforeBuild` 钩子在任何 CSS 被编译之前调用。它提供了对参与 CSS 生成过程的元素、索引和子元素的访问。
23+
24+
### 函数签名
25+
26+
```ts
27+
type beforeBuildCallback = (element: Element, index: number, children: Element[]) => void;
28+
```
29+
30+
### 参数:
31+
32+
- **element:** 当前正在处理的元素。
33+
- **index:** 当前元素在 CSS 生成序列中的索引。
34+
- **children:** 与当前元素相关的子元素。
35+
36+
### 示例
37+
38+
::: warning
39+
如果你想要更改 CSS 输出的内容,应该修改 `element.return` 的属性。否则,CSS 不会按预期生成。
40+
:::
41+
42+
```ts
43+
plugin.register({
44+
beforeBuild: (element: Element, index: number, children: Element[]) => {
45+
// 如果元素的内容包含特定的值,则更改其 CSS
46+
if (element.children === 'red') {
47+
element.return = 'color: blue';
48+
}
49+
}
50+
});
51+
```
52+
53+
## `afterBuild` 钩子
54+
55+
`afterBuild` 钩子在 CSS 编译完成后调用。它提供了对生成的 CSS 的访问。
56+
57+
### 函数签名
58+
59+
```ts
60+
type afterBuildCallback = (css: string) => stringvoid;
61+
```
62+
63+
### 参数:
64+
65+
- **css:** 已生成的 CSS。
66+
67+
### 示例
68+
69+
```ts
70+
plugin.register({
71+
afterBuild: (css: string) => {
72+
// 在返回之前修改编译后的 CSS
73+
return css.replace(/color:red/g, 'color:blue');
74+
}
75+
});
76+
```

0 commit comments

Comments
 (0)