@ikkin/plugin-unocss 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +407 -0
- package/dist/plugin-unocss.d.mts +62 -0
- package/dist/plugin-unocss.d.ts +62 -0
- package/dist/plugin-unocss.js +255 -0
- package/dist/plugin-unocss.js.map +1 -0
- package/dist/plugin-unocss.mjs +228 -0
- package/dist/plugin-unocss.mjs.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# @ikkin/plugin-unocss
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ikkin/plugin-unocss)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
> UnoCSS plugin for Rsbuild with CLI pre-generation and automatic injection
|
|
7
|
+
|
|
8
|
+
一个标准的 Rsbuild 插件,用于在项目中集成 UnoCSS,支持 CLI 预生成模式。
|
|
9
|
+
|
|
10
|
+
## 特性
|
|
11
|
+
|
|
12
|
+
✅ **CLI 预生成模式**: 扫描源文件并生成独立的 CSS 文件
|
|
13
|
+
✅ **自动注入**: 通过 HTML 标签注入 CSS 链接,不污染源码
|
|
14
|
+
✅ **Watch 模式**: 开发环境监听文件变化并自动重新生成 CSS
|
|
15
|
+
✅ **浏览器自动刷新**: CSS 变化后自动刷新浏览器,无需手动刷新页面
|
|
16
|
+
✅ **零配置**: 开箱即用,完全自动化
|
|
17
|
+
✅ **类型安全**: 完整的 TypeScript 支持
|
|
18
|
+
✅ **灵活配置**: 支持自定义监听目录和扫描模式
|
|
19
|
+
✅ **开箱即用**: 内置 `globby` 和 `chokidar`,用户无需额外安装
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
### 通过 NPM 安装(推荐)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# npm
|
|
27
|
+
npm install @ikkin/plugin-unocss unocss
|
|
28
|
+
|
|
29
|
+
# pnpm
|
|
30
|
+
pnpm add @ikkin/plugin-unocss unocss
|
|
31
|
+
|
|
32
|
+
# yarn
|
|
33
|
+
yarn add @ikkin/plugin-unocss unocss
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> **注意**: 插件已内置 `globby` 和 `chokidar`,你不需要额外安装这些依赖!
|
|
37
|
+
|
|
38
|
+
### 本地开发
|
|
39
|
+
|
|
40
|
+
如果你想在本地开发或修改插件:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 在项目根目录
|
|
44
|
+
pnpm install
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 使用方法
|
|
48
|
+
|
|
49
|
+
### 1. 基础配置
|
|
50
|
+
|
|
51
|
+
在 `rsbuild.config.ts` 中添加插件:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { defineConfig } from '@rsbuild/core';
|
|
55
|
+
import { pluginReact } from '@rsbuild/plugin-react';
|
|
56
|
+
import { pluginUnocss } from '@ikkin/plugin-unocss';
|
|
57
|
+
|
|
58
|
+
export default defineConfig({
|
|
59
|
+
plugins: [
|
|
60
|
+
pluginReact(),
|
|
61
|
+
pluginUnocss(),
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. 创建 UnoCSS 配置文件
|
|
67
|
+
|
|
68
|
+
在项目根目录创建 `uno.config.ts`:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { defineConfig, presetWind4 } from 'unocss';
|
|
72
|
+
|
|
73
|
+
export default defineConfig({
|
|
74
|
+
content: {
|
|
75
|
+
filesystem: ['./src/**/*.{html,js,ts,jsx,tsx}', './index.html'],
|
|
76
|
+
},
|
|
77
|
+
presets: [presetWind4()],
|
|
78
|
+
shortcuts: {
|
|
79
|
+
'flex-center': 'flex items-center justify-center',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. 直接使用
|
|
85
|
+
|
|
86
|
+
在组件中直接使用 UnoCSS 工具类:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
const App = () => {
|
|
90
|
+
return (
|
|
91
|
+
<div className="flex-center p-4 bg-blue-500 text-white">
|
|
92
|
+
Hello UnoCSS!
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 工作原理
|
|
99
|
+
|
|
100
|
+
### 构建流程
|
|
101
|
+
|
|
102
|
+
1. **扫描文件**: 插件扫描配置的文件路径,提取所有使用的 UnoCSS 类名
|
|
103
|
+
2. **生成 CSS**: 根据实际使用情况生成 CSS 文件
|
|
104
|
+
- **生产环境**: 生成带 hash 的文件名(如 `uno.a1b2c3d4.css`)
|
|
105
|
+
- **开发环境**: 生成固定文件名(`uno.css`)以支持热更新
|
|
106
|
+
3. **自动注入**: 通过 HTML 标签注入 CSS 链接(不污染源码)
|
|
107
|
+
- **生产环境**: 复制 CSS 到 `dist/uno.[hash].css` 并在 HTML 中添加 `<link rel="stylesheet" href="/uno.[hash].css">`
|
|
108
|
+
- **开发环境**: 通过 dev server 中间件在 `/uno.css` 路径提供 CSS 文件
|
|
109
|
+
4. **零配置**: 用户无需手动导入 CSS 文件
|
|
110
|
+
|
|
111
|
+
### 为什么不污染源码?
|
|
112
|
+
|
|
113
|
+
传统方案会修改 `src/index.tsx` 添加 import 语句,这样会:
|
|
114
|
+
- ❌ 污染项目的源代码
|
|
115
|
+
- ❌ 用户可能会误提交这个自动生成的导入
|
|
116
|
+
- ❌ 代码审查时会看到不相关的修改
|
|
117
|
+
|
|
118
|
+
本插件采用 HTML 注入方案:
|
|
119
|
+
- ✅ 完全不修改源代码
|
|
120
|
+
- ✅ 通过 HTML 标签自动注入 CSS 链接
|
|
121
|
+
- ✅ 用户体验更加简洁
|
|
122
|
+
|
|
123
|
+
### Watch 模式与自动刷新
|
|
124
|
+
|
|
125
|
+
开发环境下的 watch 模式提供以下功能:
|
|
126
|
+
|
|
127
|
+
1. **文件监听**: 监听指定目录(默认 `src`)下的文件变化
|
|
128
|
+
2. **CSS 自动生成**: 文件添加、修改、删除时自动重新生成 CSS
|
|
129
|
+
3. **浏览器自动刷新**: 使用 `devServer.sockWrite('static-changed', '/uno.css')` 触发浏览器 CSS 刷新
|
|
130
|
+
4. **防抖机制**: 300ms 防抖,避免频繁重新生成
|
|
131
|
+
|
|
132
|
+
这样你在开发时添加新组件或修改样式后,浏览器会立即显示最新的样式,无需手动刷新页面。
|
|
133
|
+
|
|
134
|
+
### 输出路径
|
|
135
|
+
|
|
136
|
+
默认情况下,生成的 CSS 文件位于:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
plugins/generated/uno.css
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
你可以通过 `outputPath` 选项自定义输出路径:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// 相对于项目根目录
|
|
146
|
+
pluginUnocss({
|
|
147
|
+
outputPath: './src/styles/uno-generated.css',
|
|
148
|
+
})
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**路径解析规则**:
|
|
152
|
+
- **以 `./` 前缀**: 相对于项目根目录(推荐,更明确)
|
|
153
|
+
- 例如:`./src/styles/uno.css` → `项目根目录/src/styles/uno.css`
|
|
154
|
+
- **相对路径(不带 `./`)**: 相对于插件目录(更简洁)
|
|
155
|
+
- 例如:`generated/uno.css` → `plugins/generated/uno.css`
|
|
156
|
+
- **绝对路径**: 直接使用绝对路径
|
|
157
|
+
- 例如:`/custom/path/uno.css` → `/custom/path/uno.css`
|
|
158
|
+
- **未配置**: 默认相对于插件目录
|
|
159
|
+
- 默认:`plugins/generated/uno.css`
|
|
160
|
+
|
|
161
|
+
**默认路径的好处**:
|
|
162
|
+
- 在插件目录内,不会污染项目源码
|
|
163
|
+
- 当插件作为 npm 包发布时,用户看不到生成的文件
|
|
164
|
+
- 可以通过 `.gitignore` 忽略
|
|
165
|
+
|
|
166
|
+
## 配置选项
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
pluginUnocss({
|
|
170
|
+
// UnoCSS 配置文件路径或直接配置对象
|
|
171
|
+
unocssConfig: './uno.config.ts',
|
|
172
|
+
|
|
173
|
+
// 生成 CSS 的输出路径
|
|
174
|
+
// 以 `./` 开头:相对于项目根目录(推荐,更明确)
|
|
175
|
+
// 相对路径(不带 `./`):相对于插件目录(更简洁)
|
|
176
|
+
// 绝对路径:使用绝对路径
|
|
177
|
+
// 未配置:默认相对于插件目录
|
|
178
|
+
outputPath: './generated/uno.css',
|
|
179
|
+
|
|
180
|
+
// 扫描的文件路径模式
|
|
181
|
+
contentPatterns: [
|
|
182
|
+
'./src/**/*.{html,js,ts,jsx,tsx}',
|
|
183
|
+
'./index.html',
|
|
184
|
+
],
|
|
185
|
+
|
|
186
|
+
// 监听的目录路径(用于 watch 模式)
|
|
187
|
+
watchDirectory: 'src',
|
|
188
|
+
|
|
189
|
+
// 是否自动注入 CSS
|
|
190
|
+
autoInject: true,
|
|
191
|
+
|
|
192
|
+
// 是否启用 watch 模式
|
|
193
|
+
watch: true,
|
|
194
|
+
|
|
195
|
+
// 是否在文件名中添加 hash 值(仅生产环境)
|
|
196
|
+
enableHash: true,
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 选项说明
|
|
201
|
+
|
|
202
|
+
#### `unocssConfig`
|
|
203
|
+
|
|
204
|
+
- **类型**: `string | UserConfig`
|
|
205
|
+
- **默认值**: `'./uno.config.ts'`
|
|
206
|
+
- **说明**: UnoCSS 配置文件路径(相对于项目根目录)或直接传入配置对象
|
|
207
|
+
|
|
208
|
+
#### `outputPath`
|
|
209
|
+
|
|
210
|
+
- **类型**: `string`
|
|
211
|
+
- **默认值**: `'./generated/uno.css'`
|
|
212
|
+
- **说明**: 生成的 CSS 文件输出路径
|
|
213
|
+
- **路径解析规则**:
|
|
214
|
+
- 以 `./` 开头:相对于项目根目录(推荐,更明确)
|
|
215
|
+
- 相对路径(不带 `./`):相对于插件目录(更简洁)
|
|
216
|
+
- 绝对路径:使用绝对路径
|
|
217
|
+
- 未配置:默认相对于插件目录
|
|
218
|
+
|
|
219
|
+
**示例**:
|
|
220
|
+
```typescript
|
|
221
|
+
// 推荐用法:相对于项目根目录
|
|
222
|
+
pluginUnocss({
|
|
223
|
+
outputPath: './src/styles/uno-generated.css',
|
|
224
|
+
// 生成到: 项目根目录/src/styles/uno-generated.css
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
// 相对于插件目录(更简洁)
|
|
228
|
+
pluginUnocss({
|
|
229
|
+
outputPath: 'generated/uno.css',
|
|
230
|
+
// 生成到: plugins/generated/uno.css
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// 使用绝对路径
|
|
234
|
+
pluginUnocss({
|
|
235
|
+
outputPath: '/absolute/path/to/file.css',
|
|
236
|
+
// 生成到: /absolute/path/to/file.css
|
|
237
|
+
})
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### `contentPatterns`
|
|
241
|
+
|
|
242
|
+
- **类型**: `string[]`
|
|
243
|
+
- **默认值**: `['./src/**/*.{html,js,ts,jsx,tsx}', './index.html']`
|
|
244
|
+
- **说明**: 用于扫描 UnoCSS 类名的文件 glob 模式数组
|
|
245
|
+
|
|
246
|
+
#### `watchDirectory`
|
|
247
|
+
|
|
248
|
+
- **类型**: `string`
|
|
249
|
+
- **默认值**: `'src'`
|
|
250
|
+
- **说明**: Watch 模式下监听的目录路径(相对于项目根目录)
|
|
251
|
+
- **示例**: 如果你的源代码在 `packages` 目录,可以设置为 `'packages'`
|
|
252
|
+
|
|
253
|
+
#### `autoInject`
|
|
254
|
+
|
|
255
|
+
- **类型**: `boolean`
|
|
256
|
+
- **默认值**: `true`
|
|
257
|
+
- **说明**: 是否自动在 HTML 中注入 CSS 链接标签
|
|
258
|
+
|
|
259
|
+
#### `watch`
|
|
260
|
+
|
|
261
|
+
- **类型**: `boolean`
|
|
262
|
+
- **默认值**: `true`
|
|
263
|
+
- **说明**: 是否在开发环境启用 watch 模式
|
|
264
|
+
|
|
265
|
+
#### `enableHash`
|
|
266
|
+
|
|
267
|
+
- **类型**: `boolean`
|
|
268
|
+
- **默认值**: `true`
|
|
269
|
+
- **说明**: 是否在文件名中添加 hash 值(仅生产环境)
|
|
270
|
+
- **作用**:
|
|
271
|
+
- ✅ 浏览器缓存优化:CSS 变化时 hash 也变化,强制浏览器重新加载
|
|
272
|
+
- ✅ CDN 友好:可以设置长期缓存策略
|
|
273
|
+
- ✅ 版本管理:每个版本的 CSS 都有唯一文件名
|
|
274
|
+
- **示例**:
|
|
275
|
+
- 启用:`uno.a1b2c3d4.css`
|
|
276
|
+
- 禁用:`uno.css`
|
|
277
|
+
|
|
278
|
+
## 开发 vs 生产环境
|
|
279
|
+
|
|
280
|
+
### 开发环境
|
|
281
|
+
|
|
282
|
+
- ✅ 启动时生成 CSS
|
|
283
|
+
- ✅ Watch 模式监听文件变化(需要 `chokidar`)
|
|
284
|
+
- ✅ 文件添加、修改、删除时自动重新生成 CSS
|
|
285
|
+
- ✅ 浏览器自动刷新 CSS(无需手动刷新页面)
|
|
286
|
+
- ✅ 通过 dev server 中间件提供 CSS 文件
|
|
287
|
+
|
|
288
|
+
### 生产环境
|
|
289
|
+
|
|
290
|
+
- ✅ 构建前生成 CSS
|
|
291
|
+
- ✅ CSS 文件名包含内容 hash(如 `uno.a1b2c3d4.css`)
|
|
292
|
+
- ✅ CSS 复制到 `dist/uno.[hash].css`
|
|
293
|
+
- ✅ 自动注入带 hash 的 CSS 链接到 HTML
|
|
294
|
+
- ✅ 浏览器缓存优化:文件变化时 hash 自动更新
|
|
295
|
+
|
|
296
|
+
## 高级用法
|
|
297
|
+
|
|
298
|
+
### 自定义监听目录
|
|
299
|
+
|
|
300
|
+
如果你的项目结构比较复杂,可以自定义监听的目录:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
// rsbuild.config.ts
|
|
304
|
+
export default defineConfig({
|
|
305
|
+
plugins: [
|
|
306
|
+
pluginUnocss({
|
|
307
|
+
watchDirectory: 'packages', // 监听 packages 目录
|
|
308
|
+
contentPatterns: [
|
|
309
|
+
'./packages/**/*.{html,js,ts,jsx,tsx}',
|
|
310
|
+
'./index.html',
|
|
311
|
+
],
|
|
312
|
+
}),
|
|
313
|
+
],
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 直接传入 UnoCSS 配置
|
|
318
|
+
|
|
319
|
+
也可以不使用配置文件,直接传入 UnoCSS 配置对象:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { presetWind4 } from 'unocss';
|
|
323
|
+
|
|
324
|
+
export default defineConfig({
|
|
325
|
+
plugins: [
|
|
326
|
+
pluginUnocss({
|
|
327
|
+
unocssConfig: {
|
|
328
|
+
presets: [presetWind4()],
|
|
329
|
+
shortcuts: {
|
|
330
|
+
'flex-center': 'flex items-center justify-center',
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
}),
|
|
334
|
+
],
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### 禁用自动注入
|
|
339
|
+
|
|
340
|
+
如果你想手动控制 CSS 的导入,可以禁用自动注入:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
export default defineConfig({
|
|
344
|
+
plugins: [
|
|
345
|
+
pluginUnocss({
|
|
346
|
+
autoInject: false, // 禁用自动注入
|
|
347
|
+
}),
|
|
348
|
+
],
|
|
349
|
+
});
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
然后手动在入口文件中导入生成的 CSS:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// src/index.tsx
|
|
356
|
+
import '../plugins/generated/uno.css';
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## 注意事项
|
|
360
|
+
|
|
361
|
+
1. **生成的文件不需要提交到 Git**
|
|
362
|
+
- `plugins/generated/` 目录已加入 `.gitignore`
|
|
363
|
+
- 每次构建时会自动重新生成
|
|
364
|
+
|
|
365
|
+
2. **Watch 模式需要 `chokidar`**
|
|
366
|
+
- 如果未安装,watch 模式会自动跳过并显示警告
|
|
367
|
+
- 安装命令: `pnpm add -D chokidar`
|
|
368
|
+
|
|
369
|
+
3. **CSS 自动注入**
|
|
370
|
+
- 生产环境:CSS 会被复制到 `dist/uno.css` 并自动注入到 HTML
|
|
371
|
+
- 开发环境:通过 dev server 中间件提供 CSS 文件
|
|
372
|
+
- 无需手动导入或修改源代码
|
|
373
|
+
|
|
374
|
+
4. **纯 CSS 输出**
|
|
375
|
+
- 插件生成纯 CSS 文件,包含所有使用的工具类
|
|
376
|
+
- 不会注入虚拟 CSS 模块到构建流程
|
|
377
|
+
- 生成的 CSS 可被浏览器直接缓存
|
|
378
|
+
|
|
379
|
+
5. **文件变化检测**
|
|
380
|
+
- Watch 模式会监听指定目录下的所有 `.html`、`.js`、`.ts`、`.jsx`、`.tsx` 文件
|
|
381
|
+
- 文件添加、修改、删除都会触发 CSS 重新生成
|
|
382
|
+
- 300ms 防抖机制避免频繁重新生成
|
|
383
|
+
|
|
384
|
+
## 优势对比
|
|
385
|
+
|
|
386
|
+
| 特性 | UnoCSS Plugin | PostCSS 方案 | CLI 手动方案 |
|
|
387
|
+
|------|---------------|-------------|-------------|
|
|
388
|
+
| 配置复杂度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
|
|
389
|
+
| 开发体验 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
|
|
390
|
+
| 生产优化 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
391
|
+
| 自动化程度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
|
|
392
|
+
| CSS 可见性 | ✅ | ❌ | ✅ |
|
|
393
|
+
| Watch 支持 | ✅ 自动 | ✅ | ⚠️ 需手动配置 |
|
|
394
|
+
| 浏览器自动刷新 | ✅ | ✅ | ❌ |
|
|
395
|
+
| 源码污染 | ❌ | ❌ | ⚠️ 可能 |
|
|
396
|
+
| 灵活配置 | ✅ | ⚠️ | ⚠️ |
|
|
397
|
+
|
|
398
|
+
## 许可证
|
|
399
|
+
|
|
400
|
+
MIT
|
|
401
|
+
|
|
402
|
+
## 相关链接
|
|
403
|
+
|
|
404
|
+
- [UnoCSS 官方文档](https://unocss.dev/)
|
|
405
|
+
- [Rsbuild 官方文档](https://rsbuild.rs/)
|
|
406
|
+
- [插件 GitHub 仓库](https://github.com/yourusername/plugin-unocss)
|
|
407
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RsbuildPlugin } from '@rsbuild/core';
|
|
2
|
+
import { UserConfig } from 'unocss';
|
|
3
|
+
|
|
4
|
+
interface PluginUnocssOptions {
|
|
5
|
+
/** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */
|
|
6
|
+
unocssConfig?: string | UserConfig;
|
|
7
|
+
/**
|
|
8
|
+
* 生成的 CSS 文件输出路径
|
|
9
|
+
*
|
|
10
|
+
* 路径解析规则:
|
|
11
|
+
* - 以 './' 开头: 相对于项目根目录 (推荐)
|
|
12
|
+
* - 相对路径: 相对于插件目录
|
|
13
|
+
* - 绝对路径: 直接使用
|
|
14
|
+
* - 未配置: 默认为 'generated/uno.css' 相对于插件目录
|
|
15
|
+
*/
|
|
16
|
+
outputPath?: string;
|
|
17
|
+
/** 扫描的内容文件路径模式 (支持 glob 模式) */
|
|
18
|
+
contentPatterns?: string[];
|
|
19
|
+
/** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */
|
|
20
|
+
watchDirectory?: string;
|
|
21
|
+
/** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */
|
|
22
|
+
autoInject?: boolean;
|
|
23
|
+
/** 是否在开发环境启用文件监听模式 (默认: true) */
|
|
24
|
+
watch?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 是否在生产环境为 CSS 文件名添加 content hash
|
|
27
|
+
*
|
|
28
|
+
* 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)
|
|
29
|
+
*/
|
|
30
|
+
enableHash?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* UnoCSS Plugin for Rsbuild
|
|
34
|
+
*
|
|
35
|
+
* 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.
|
|
36
|
+
*
|
|
37
|
+
* 特性:
|
|
38
|
+
* - 扫描项目文件并生成独立的 CSS 文件
|
|
39
|
+
* - 开发环境支持文件监听和热更新
|
|
40
|
+
* - 生产环境支持 CSS 文件名 hash
|
|
41
|
+
* - 自动在 HTML 中注入 CSS link 标签
|
|
42
|
+
*
|
|
43
|
+
* @param options - 插件配置选项
|
|
44
|
+
* @returns Rsbuild 插件实例
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { pluginUnocss } from '@ikkin/plugin-unocss';
|
|
49
|
+
*
|
|
50
|
+
* export default {
|
|
51
|
+
* plugins: [
|
|
52
|
+
* pluginUnocss({
|
|
53
|
+
* outputPath: './src/generated/uno.css',
|
|
54
|
+
* enableHash: true,
|
|
55
|
+
* })
|
|
56
|
+
* ]
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function pluginUnocss(options?: PluginUnocssOptions): RsbuildPlugin;
|
|
61
|
+
|
|
62
|
+
export { type PluginUnocssOptions, pluginUnocss as default, pluginUnocss };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RsbuildPlugin } from '@rsbuild/core';
|
|
2
|
+
import { UserConfig } from 'unocss';
|
|
3
|
+
|
|
4
|
+
interface PluginUnocssOptions {
|
|
5
|
+
/** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */
|
|
6
|
+
unocssConfig?: string | UserConfig;
|
|
7
|
+
/**
|
|
8
|
+
* 生成的 CSS 文件输出路径
|
|
9
|
+
*
|
|
10
|
+
* 路径解析规则:
|
|
11
|
+
* - 以 './' 开头: 相对于项目根目录 (推荐)
|
|
12
|
+
* - 相对路径: 相对于插件目录
|
|
13
|
+
* - 绝对路径: 直接使用
|
|
14
|
+
* - 未配置: 默认为 'generated/uno.css' 相对于插件目录
|
|
15
|
+
*/
|
|
16
|
+
outputPath?: string;
|
|
17
|
+
/** 扫描的内容文件路径模式 (支持 glob 模式) */
|
|
18
|
+
contentPatterns?: string[];
|
|
19
|
+
/** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */
|
|
20
|
+
watchDirectory?: string;
|
|
21
|
+
/** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */
|
|
22
|
+
autoInject?: boolean;
|
|
23
|
+
/** 是否在开发环境启用文件监听模式 (默认: true) */
|
|
24
|
+
watch?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 是否在生产环境为 CSS 文件名添加 content hash
|
|
27
|
+
*
|
|
28
|
+
* 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)
|
|
29
|
+
*/
|
|
30
|
+
enableHash?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* UnoCSS Plugin for Rsbuild
|
|
34
|
+
*
|
|
35
|
+
* 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.
|
|
36
|
+
*
|
|
37
|
+
* 特性:
|
|
38
|
+
* - 扫描项目文件并生成独立的 CSS 文件
|
|
39
|
+
* - 开发环境支持文件监听和热更新
|
|
40
|
+
* - 生产环境支持 CSS 文件名 hash
|
|
41
|
+
* - 自动在 HTML 中注入 CSS link 标签
|
|
42
|
+
*
|
|
43
|
+
* @param options - 插件配置选项
|
|
44
|
+
* @returns Rsbuild 插件实例
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { pluginUnocss } from '@ikkin/plugin-unocss';
|
|
49
|
+
*
|
|
50
|
+
* export default {
|
|
51
|
+
* plugins: [
|
|
52
|
+
* pluginUnocss({
|
|
53
|
+
* outputPath: './src/generated/uno.css',
|
|
54
|
+
* enableHash: true,
|
|
55
|
+
* })
|
|
56
|
+
* ]
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function pluginUnocss(options?: PluginUnocssOptions): RsbuildPlugin;
|
|
61
|
+
|
|
62
|
+
export { type PluginUnocssOptions, pluginUnocss as default, pluginUnocss };
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var fs = require('fs');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var url = require('url');
|
|
8
|
+
var crypto = require('crypto');
|
|
9
|
+
|
|
10
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function (k) {
|
|
16
|
+
if (k !== 'default') {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return e[k]; }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
30
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
31
|
+
|
|
32
|
+
// plugin-unocss.ts
|
|
33
|
+
var __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-unocss.js', document.baseURI).href)));
|
|
34
|
+
var __dirname$1 = path__namespace.dirname(__filename$1);
|
|
35
|
+
function pluginUnocss(options = {}) {
|
|
36
|
+
const {
|
|
37
|
+
unocssConfig = "./uno.config.ts",
|
|
38
|
+
outputPath = "",
|
|
39
|
+
contentPatterns = [
|
|
40
|
+
"./src/**/*.{html,js,ts,jsx,tsx}",
|
|
41
|
+
"./index.html"
|
|
42
|
+
],
|
|
43
|
+
watchDirectory = "src",
|
|
44
|
+
autoInject = true,
|
|
45
|
+
watch = true,
|
|
46
|
+
enableHash = true
|
|
47
|
+
} = options;
|
|
48
|
+
return {
|
|
49
|
+
name: "unocss",
|
|
50
|
+
setup(api) {
|
|
51
|
+
const rootContext = api.context.rootPath;
|
|
52
|
+
const pluginDir = __dirname$1;
|
|
53
|
+
let resolvedOutputPath;
|
|
54
|
+
if (!outputPath) {
|
|
55
|
+
resolvedOutputPath = path__namespace.resolve(pluginDir, "./generated/uno.css");
|
|
56
|
+
} else if (path__namespace.isAbsolute(outputPath)) {
|
|
57
|
+
resolvedOutputPath = outputPath;
|
|
58
|
+
} else if (outputPath.startsWith("./")) {
|
|
59
|
+
resolvedOutputPath = path__namespace.resolve(rootContext, outputPath);
|
|
60
|
+
} else {
|
|
61
|
+
resolvedOutputPath = path__namespace.resolve(pluginDir, outputPath);
|
|
62
|
+
}
|
|
63
|
+
let currentCssPath = resolvedOutputPath;
|
|
64
|
+
let devServerInstance = null;
|
|
65
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
66
|
+
const loadConfig = async () => {
|
|
67
|
+
if (typeof unocssConfig === "string") {
|
|
68
|
+
const configPath = path__namespace.resolve(rootContext, unocssConfig);
|
|
69
|
+
try {
|
|
70
|
+
const configModule = await import(`file:///${configPath.replace(/\\/g, "/")}`);
|
|
71
|
+
return configModule.default || configModule;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.warn(
|
|
74
|
+
`[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`
|
|
75
|
+
);
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return unocssConfig;
|
|
80
|
+
};
|
|
81
|
+
const generateCSS = async () => {
|
|
82
|
+
console.log("[UnoCSS Hybrid] Generating CSS...");
|
|
83
|
+
try {
|
|
84
|
+
const config = await loadConfig();
|
|
85
|
+
const { globby } = await import('globby');
|
|
86
|
+
const files = await globby(contentPatterns, {
|
|
87
|
+
cwd: rootContext,
|
|
88
|
+
absolute: true
|
|
89
|
+
});
|
|
90
|
+
if (files.length === 0) {
|
|
91
|
+
console.warn("[UnoCSS Hybrid] No files found to scan");
|
|
92
|
+
return resolvedOutputPath;
|
|
93
|
+
}
|
|
94
|
+
console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);
|
|
95
|
+
console.log(`[UnoCSS Hybrid] Files:`, files.map((f) => path__namespace.relative(rootContext, f)));
|
|
96
|
+
const { createGenerator } = await import('unocss');
|
|
97
|
+
const generator = await createGenerator(config);
|
|
98
|
+
const allContents = files.map((file) => {
|
|
99
|
+
const content = fs__namespace.readFileSync(file, "utf-8");
|
|
100
|
+
return content;
|
|
101
|
+
}).join("\n");
|
|
102
|
+
const result = await generator.generate(allContents);
|
|
103
|
+
if (!result.css || result.css.trim().length === 0) {
|
|
104
|
+
console.warn("[UnoCSS Hybrid] Generated CSS is empty");
|
|
105
|
+
return resolvedOutputPath;
|
|
106
|
+
}
|
|
107
|
+
let finalOutputPath;
|
|
108
|
+
if (isProd && enableHash) {
|
|
109
|
+
const distDir = path__namespace.join(rootContext, "dist");
|
|
110
|
+
const hash = crypto.createHash("md5").update(result.css).digest("hex").substring(0, 8);
|
|
111
|
+
finalOutputPath = path__namespace.join(distDir, `uno.${hash}.css`);
|
|
112
|
+
currentCssPath = finalOutputPath;
|
|
113
|
+
} else {
|
|
114
|
+
finalOutputPath = resolvedOutputPath;
|
|
115
|
+
currentCssPath = resolvedOutputPath;
|
|
116
|
+
}
|
|
117
|
+
const outputDir = path__namespace.dirname(finalOutputPath);
|
|
118
|
+
if (!fs__namespace.existsSync(outputDir)) {
|
|
119
|
+
fs__namespace.mkdirSync(outputDir, { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
fs__namespace.writeFileSync(finalOutputPath, result.css);
|
|
122
|
+
const stats = fs__namespace.statSync(finalOutputPath);
|
|
123
|
+
console.log(
|
|
124
|
+
`[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`
|
|
125
|
+
);
|
|
126
|
+
return finalOutputPath;
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error("[UnoCSS Hybrid] Failed to generate CSS:", err);
|
|
129
|
+
return resolvedOutputPath;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
if (isProd) {
|
|
133
|
+
api.onBeforeBuild(async () => {
|
|
134
|
+
await generateCSS();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (autoInject) {
|
|
138
|
+
api.modifyHTMLTags((tags) => {
|
|
139
|
+
let cssPath;
|
|
140
|
+
if (isProd && enableHash) {
|
|
141
|
+
const cssFileName = path__namespace.basename(currentCssPath);
|
|
142
|
+
cssPath = `/${cssFileName}`;
|
|
143
|
+
} else {
|
|
144
|
+
cssPath = "/uno.css";
|
|
145
|
+
}
|
|
146
|
+
tags.headTags.unshift({
|
|
147
|
+
tag: "link",
|
|
148
|
+
attrs: {
|
|
149
|
+
rel: "stylesheet",
|
|
150
|
+
href: cssPath
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);
|
|
154
|
+
return tags;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (!isProd) {
|
|
158
|
+
api.modifyRsbuildConfig((config) => {
|
|
159
|
+
const existingSetupMiddlewares = config.dev?.setupMiddlewares;
|
|
160
|
+
const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares) ? existingSetupMiddlewares : existingSetupMiddlewares ? [existingSetupMiddlewares] : [];
|
|
161
|
+
return {
|
|
162
|
+
...config,
|
|
163
|
+
dev: {
|
|
164
|
+
...config.dev,
|
|
165
|
+
setupMiddlewares: [
|
|
166
|
+
...setupMiddlewaresArray,
|
|
167
|
+
(middlewares, devServer) => {
|
|
168
|
+
devServerInstance = devServer;
|
|
169
|
+
middlewares.unshift(async (req, res, next) => {
|
|
170
|
+
if (req.url === "/uno.css") {
|
|
171
|
+
try {
|
|
172
|
+
if (!fs__namespace.existsSync(resolvedOutputPath)) {
|
|
173
|
+
res.statusCode = 404;
|
|
174
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
175
|
+
res.end("CSS file not found. Please restart the dev server to generate it.");
|
|
176
|
+
console.warn("[UnoCSS Hybrid] CSS file not found at:", resolvedOutputPath);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
res.setHeader("Content-Type", "text/css; charset=utf-8");
|
|
180
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
181
|
+
const css = fs__namespace.readFileSync(resolvedOutputPath, "utf-8");
|
|
182
|
+
res.end(css);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
console.error("[UnoCSS Hybrid] Error serving CSS:", err);
|
|
185
|
+
res.statusCode = 500;
|
|
186
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
187
|
+
res.end("Error loading CSS file. Check console for details.");
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
next();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
api.onBeforeStartDevServer(async () => {
|
|
199
|
+
console.log("[UnoCSS Hybrid] Development mode: CLI generation enabled");
|
|
200
|
+
await generateCSS();
|
|
201
|
+
});
|
|
202
|
+
api.onAfterStartDevServer(async () => {
|
|
203
|
+
console.log("[UnoCSS Hybrid] Dev server started, CSS available at /uno.css");
|
|
204
|
+
if (watch) {
|
|
205
|
+
try {
|
|
206
|
+
const chokidar = await import('chokidar');
|
|
207
|
+
const watchDir = path__namespace.resolve(rootContext, watchDirectory);
|
|
208
|
+
const watcher = chokidar.watch(watchDir, {
|
|
209
|
+
ignored: /(^|[\/\\])\../,
|
|
210
|
+
// ignore dotfiles
|
|
211
|
+
ignoreInitial: true,
|
|
212
|
+
persistent: true
|
|
213
|
+
});
|
|
214
|
+
let regenerateTimer = null;
|
|
215
|
+
watcher.on("all", async (event, filePath) => {
|
|
216
|
+
const ext = path__namespace.extname(filePath);
|
|
217
|
+
const shouldWatch = [".html", ".js", ".ts", ".jsx", ".tsx"].includes(ext);
|
|
218
|
+
if (shouldWatch && (event === "change" || event === "add" || event === "unlink")) {
|
|
219
|
+
console.log(`[UnoCSS Hybrid] File ${event}: ${path__namespace.relative(rootContext, filePath)}`);
|
|
220
|
+
if (regenerateTimer) {
|
|
221
|
+
clearTimeout(regenerateTimer);
|
|
222
|
+
}
|
|
223
|
+
regenerateTimer = setTimeout(async () => {
|
|
224
|
+
console.log("[UnoCSS Hybrid] Regenerating CSS...");
|
|
225
|
+
await generateCSS();
|
|
226
|
+
console.log("[UnoCSS Hybrid] Refreshing CSS in browser...");
|
|
227
|
+
devServerInstance?.sockWrite("static-changed", "/uno.css");
|
|
228
|
+
}, 300);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
console.log("[UnoCSS Hybrid] Watch mode: enabled");
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.warn("[UnoCSS Hybrid] Watch mode not available:", err.message);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
api.onAfterBuild(() => {
|
|
239
|
+
if (isProd && fs__namespace.existsSync(currentCssPath)) {
|
|
240
|
+
const stats = fs__namespace.statSync(currentCssPath);
|
|
241
|
+
const fileName = path__namespace.basename(currentCssPath);
|
|
242
|
+
console.log(
|
|
243
|
+
`[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
var plugin_unocss_default = pluginUnocss;
|
|
251
|
+
|
|
252
|
+
exports.default = plugin_unocss_default;
|
|
253
|
+
exports.pluginUnocss = pluginUnocss;
|
|
254
|
+
//# sourceMappingURL=plugin-unocss.js.map
|
|
255
|
+
//# sourceMappingURL=plugin-unocss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","fileURLToPath","__dirname","path","fs","createHash"],"mappings":"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","file":"plugin-unocss.js","sourcesContent":["import type { RsbuildPlugin } from '@rsbuild/core';\nimport type { UserConfig } from 'unocss';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { createHash } from 'crypto';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface PluginUnocssOptions {\n /** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */\n unocssConfig?: string | UserConfig;\n\n /**\n * 生成的 CSS 文件输出路径\n *\n * 路径解析规则:\n * - 以 './' 开头: 相对于项目根目录 (推荐)\n * - 相对路径: 相对于插件目录\n * - 绝对路径: 直接使用\n * - 未配置: 默认为 'generated/uno.css' 相对于插件目录\n */\n outputPath?: string;\n\n /** 扫描的内容文件路径模式 (支持 glob 模式) */\n contentPatterns?: string[];\n\n /** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */\n watchDirectory?: string;\n\n /** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */\n autoInject?: boolean;\n\n /** 是否在开发环境启用文件监听模式 (默认: true) */\n watch?: boolean;\n\n /**\n * 是否在生产环境为 CSS 文件名添加 content hash\n *\n * 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)\n */\n enableHash?: boolean;\n}\n\n/**\n * UnoCSS Plugin for Rsbuild\n *\n * 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.\n *\n * 特性:\n * - 扫描项目文件并生成独立的 CSS 文件\n * - 开发环境支持文件监听和热更新\n * - 生产环境支持 CSS 文件名 hash\n * - 自动在 HTML 中注入 CSS link 标签\n *\n * @param options - 插件配置选项\n * @returns Rsbuild 插件实例\n *\n * @example\n * ```ts\n * import { pluginUnocss } from '@ikkin/plugin-unocss';\n *\n * export default {\n * plugins: [\n * pluginUnocss({\n * outputPath: './src/generated/uno.css',\n * enableHash: true,\n * })\n * ]\n * };\n * ```\n */\nexport function pluginUnocss(\n options: PluginUnocssOptions = {},\n): RsbuildPlugin {\n const {\n unocssConfig = './uno.config.ts',\n outputPath = '',\n contentPatterns = [\n './src/**/*.{html,js,ts,jsx,tsx}',\n './index.html',\n ],\n watchDirectory = 'src',\n autoInject = true,\n watch = true,\n enableHash = true,\n } = options;\n\n return {\n name: 'unocss',\n\n setup(api) {\n const rootContext = api.context.rootPath;\n\n // 解析输出路径\n const pluginDir = __dirname;\n let resolvedOutputPath: string;\n\n if (!outputPath) {\n // 未配置:使用默认路径(相对于插件目录)\n resolvedOutputPath = path.resolve(pluginDir, './generated/uno.css');\n } else if (path.isAbsolute(outputPath)) {\n // 绝对路径:直接使用\n resolvedOutputPath = outputPath;\n } else if (outputPath.startsWith('./')) {\n // 以 ./ 开头:相对于项目根目录(推荐,更明确)\n resolvedOutputPath = path.resolve(rootContext, outputPath);\n } else {\n // 相对路径(不带 ./):相对于插件目录(更简洁)\n resolvedOutputPath = path.resolve(pluginDir, outputPath);\n }\n\n // 用于保存当前生成的 CSS 文件路径(可能包含 hash)\n let currentCssPath = resolvedOutputPath;\n\n // 用于保存 dev server 实例,以便在文件变化时触发刷新\n let devServerInstance: any = null;\n\n // 通过环境变量判断是否是生产环境\n const isProd = process.env.NODE_ENV === 'production';\n\n // 读取 UnoCSS 配置\n const loadConfig = async (): Promise<UserConfig> => {\n if (typeof unocssConfig === 'string') {\n const configPath = path.resolve(rootContext, unocssConfig);\n try {\n const configModule = await import(\n `file:///${configPath.replace(/\\\\/g, '/')}`\n );\n return configModule.default || configModule;\n } catch (err) {\n console.warn(\n `[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`,\n );\n return {};\n }\n }\n return unocssConfig;\n };\n\n // 生成 UnoCSS CSS\n const generateCSS = async (): Promise<string> => {\n console.log('[UnoCSS Hybrid] Generating CSS...');\n\n try {\n const config = await loadConfig();\n\n // 扫描文件\n const { globby } = await import('globby');\n const files = await globby(contentPatterns, {\n cwd: rootContext,\n absolute: true,\n });\n\n if (files.length === 0) {\n console.warn('[UnoCSS Hybrid] No files found to scan');\n return resolvedOutputPath;\n }\n\n console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);\n console.log(`[UnoCSS Hybrid] Files:`, files.map(f => path.relative(rootContext, f)));\n\n // 使用 UnoCSS generator\n const { createGenerator } = await import('unocss');\n const generator = await createGenerator(config);\n\n // 读取所有文件内容并生成\n const allContents = files.map(file => {\n const content = fs.readFileSync(file, 'utf-8');\n return content;\n }).join('\\n');\n\n // 生成 CSS\n const result = await generator.generate(allContents);\n\n if (!result.css || result.css.trim().length === 0) {\n console.warn('[UnoCSS Hybrid] Generated CSS is empty');\n return resolvedOutputPath;\n }\n\n // 计算输出路径\n let finalOutputPath: string;\n if (isProd && enableHash) {\n // 生产环境:直接生成到 dist 目录,文件名带 hash\n const distDir = path.join(rootContext, 'dist');\n const hash = createHash('md5').update(result.css).digest('hex').substring(0, 8);\n finalOutputPath = path.join(distDir, `uno.${hash}.css`);\n currentCssPath = finalOutputPath;\n } else {\n // 开发环境:生成到插件目录的 generated 子目录,文件名固定\n finalOutputPath = resolvedOutputPath;\n currentCssPath = resolvedOutputPath;\n }\n\n // 确保输出目录存在\n const outputDir = path.dirname(finalOutputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // 写入 CSS 文件\n fs.writeFileSync(finalOutputPath, result.css);\n\n const stats = fs.statSync(finalOutputPath);\n console.log(\n `[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`,\n );\n\n return finalOutputPath;\n } catch (err) {\n console.error('[UnoCSS Hybrid] Failed to generate CSS:', err);\n return resolvedOutputPath;\n }\n };\n\n // 生产环境:构建前生成 CSS\n if (isProd) {\n api.onBeforeBuild(async () => {\n await generateCSS();\n });\n }\n\n // 自动注入:通过修改 HTML 标签来注入 CSS(不污染源码)\n if (autoInject) {\n api.modifyHTMLTags((tags) => {\n let cssPath: string;\n\n if (isProd && enableHash) {\n // 生产环境:使用带 hash 的文件名\n const cssFileName = path.basename(currentCssPath);\n cssPath = `/${cssFileName}`;\n } else {\n // 开发环境或未启用 hash:使用固定文件名\n cssPath = '/uno.css';\n }\n\n tags.headTags.unshift({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n href: cssPath,\n },\n });\n\n console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);\n return tags;\n });\n }\n\n // 开发环境:配置静态文件服务\n if (!isProd) {\n api.modifyRsbuildConfig((config) => {\n const existingSetupMiddlewares = config.dev?.setupMiddlewares;\n const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares)\n ? existingSetupMiddlewares\n : existingSetupMiddlewares\n ? [existingSetupMiddlewares]\n : [];\n\n return {\n ...config,\n dev: {\n ...config.dev,\n setupMiddlewares: [\n ...setupMiddlewaresArray,\n (middlewares, devServer) => {\n // 保存 dev server 实例\n devServerInstance = devServer;\n\n // 添加自定义中间件来提供 CSS 文件\n middlewares.unshift(async (req, res, next) => {\n if (req.url === '/uno.css') {\n try {\n // 检查文件是否存在\n if (!fs.existsSync(resolvedOutputPath)) {\n res.statusCode = 404;\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('CSS file not found. Please restart the dev server to generate it.');\n console.warn('[UnoCSS Hybrid] CSS file not found at:', resolvedOutputPath);\n return;\n }\n\n // 设置正确的 Content-Type 和缓存控制\n res.setHeader('Content-Type', 'text/css; charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache');\n\n const css = fs.readFileSync(resolvedOutputPath, 'utf-8');\n res.end(css);\n } catch (err) {\n console.error('[UnoCSS Hybrid] Error serving CSS:', err);\n res.statusCode = 500;\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Error loading CSS file. Check console for details.');\n }\n } else {\n next();\n }\n });\n },\n ],\n },\n };\n });\n\n // 启动时生成 CSS\n api.onBeforeStartDevServer(async () => {\n console.log('[UnoCSS Hybrid] Development mode: CLI generation enabled');\n await generateCSS();\n });\n\n // 合并启动后的操作\n api.onAfterStartDevServer(async () => {\n console.log('[UnoCSS Hybrid] Dev server started, CSS available at /uno.css');\n\n // Watch 模式\n if (watch) {\n try {\n // 动态导入 chokidar\n const chokidar = await import('chokidar');\n\n // 监听指定目录\n const watchDir = path.resolve(rootContext, watchDirectory);\n\n // 监听内容文件变化\n const watcher = chokidar.watch(watchDir, {\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\n ignoreInitial: true,\n persistent: true,\n });\n\n // 防抖:避免频繁重新生成\n let regenerateTimer: NodeJS.Timeout | null = null;\n\n watcher.on('all', async (event: string, filePath: string) => {\n // 检查文件扩展名\n const ext = path.extname(filePath);\n const shouldWatch = ['.html', '.js', '.ts', '.jsx', '.tsx'].includes(ext);\n\n // 监听文件添加、修改和删除\n if (shouldWatch && (event === 'change' || event === 'add' || event === 'unlink')) {\n console.log(`[UnoCSS Hybrid] File ${event}: ${path.relative(rootContext, filePath)}`);\n\n if (regenerateTimer) {\n clearTimeout(regenerateTimer);\n }\n\n regenerateTimer = setTimeout(async () => {\n console.log('[UnoCSS Hybrid] Regenerating CSS...');\n await generateCSS();\n\n // 触发浏览器刷新 CSS\n console.log('[UnoCSS Hybrid] Refreshing CSS in browser...');\n devServerInstance?.sockWrite('static-changed', '/uno.css');\n }, 300);\n }\n });\n\n console.log('[UnoCSS Hybrid] Watch mode: enabled');\n } catch (err) {\n console.warn('[UnoCSS Hybrid] Watch mode not available:', (err as Error).message);\n }\n }\n });\n }\n\n // 构建完成后的日志\n api.onAfterBuild(() => {\n if (isProd && fs.existsSync(currentCssPath)) {\n const stats = fs.statSync(currentCssPath);\n const fileName = path.basename(currentCssPath);\n console.log(\n `[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`,\n );\n }\n });\n },\n };\n}\n\nexport default pluginUnocss;\n"]}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
|
|
6
|
+
// plugin-unocss.ts
|
|
7
|
+
var __filename$1 = fileURLToPath(import.meta.url);
|
|
8
|
+
var __dirname$1 = path.dirname(__filename$1);
|
|
9
|
+
function pluginUnocss(options = {}) {
|
|
10
|
+
const {
|
|
11
|
+
unocssConfig = "./uno.config.ts",
|
|
12
|
+
outputPath = "",
|
|
13
|
+
contentPatterns = [
|
|
14
|
+
"./src/**/*.{html,js,ts,jsx,tsx}",
|
|
15
|
+
"./index.html"
|
|
16
|
+
],
|
|
17
|
+
watchDirectory = "src",
|
|
18
|
+
autoInject = true,
|
|
19
|
+
watch = true,
|
|
20
|
+
enableHash = true
|
|
21
|
+
} = options;
|
|
22
|
+
return {
|
|
23
|
+
name: "unocss",
|
|
24
|
+
setup(api) {
|
|
25
|
+
const rootContext = api.context.rootPath;
|
|
26
|
+
const pluginDir = __dirname$1;
|
|
27
|
+
let resolvedOutputPath;
|
|
28
|
+
if (!outputPath) {
|
|
29
|
+
resolvedOutputPath = path.resolve(pluginDir, "./generated/uno.css");
|
|
30
|
+
} else if (path.isAbsolute(outputPath)) {
|
|
31
|
+
resolvedOutputPath = outputPath;
|
|
32
|
+
} else if (outputPath.startsWith("./")) {
|
|
33
|
+
resolvedOutputPath = path.resolve(rootContext, outputPath);
|
|
34
|
+
} else {
|
|
35
|
+
resolvedOutputPath = path.resolve(pluginDir, outputPath);
|
|
36
|
+
}
|
|
37
|
+
let currentCssPath = resolvedOutputPath;
|
|
38
|
+
let devServerInstance = null;
|
|
39
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
40
|
+
const loadConfig = async () => {
|
|
41
|
+
if (typeof unocssConfig === "string") {
|
|
42
|
+
const configPath = path.resolve(rootContext, unocssConfig);
|
|
43
|
+
try {
|
|
44
|
+
const configModule = await import(`file:///${configPath.replace(/\\/g, "/")}`);
|
|
45
|
+
return configModule.default || configModule;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.warn(
|
|
48
|
+
`[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`
|
|
49
|
+
);
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return unocssConfig;
|
|
54
|
+
};
|
|
55
|
+
const generateCSS = async () => {
|
|
56
|
+
console.log("[UnoCSS Hybrid] Generating CSS...");
|
|
57
|
+
try {
|
|
58
|
+
const config = await loadConfig();
|
|
59
|
+
const { globby } = await import('globby');
|
|
60
|
+
const files = await globby(contentPatterns, {
|
|
61
|
+
cwd: rootContext,
|
|
62
|
+
absolute: true
|
|
63
|
+
});
|
|
64
|
+
if (files.length === 0) {
|
|
65
|
+
console.warn("[UnoCSS Hybrid] No files found to scan");
|
|
66
|
+
return resolvedOutputPath;
|
|
67
|
+
}
|
|
68
|
+
console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);
|
|
69
|
+
console.log(`[UnoCSS Hybrid] Files:`, files.map((f) => path.relative(rootContext, f)));
|
|
70
|
+
const { createGenerator } = await import('unocss');
|
|
71
|
+
const generator = await createGenerator(config);
|
|
72
|
+
const allContents = files.map((file) => {
|
|
73
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
74
|
+
return content;
|
|
75
|
+
}).join("\n");
|
|
76
|
+
const result = await generator.generate(allContents);
|
|
77
|
+
if (!result.css || result.css.trim().length === 0) {
|
|
78
|
+
console.warn("[UnoCSS Hybrid] Generated CSS is empty");
|
|
79
|
+
return resolvedOutputPath;
|
|
80
|
+
}
|
|
81
|
+
let finalOutputPath;
|
|
82
|
+
if (isProd && enableHash) {
|
|
83
|
+
const distDir = path.join(rootContext, "dist");
|
|
84
|
+
const hash = createHash("md5").update(result.css).digest("hex").substring(0, 8);
|
|
85
|
+
finalOutputPath = path.join(distDir, `uno.${hash}.css`);
|
|
86
|
+
currentCssPath = finalOutputPath;
|
|
87
|
+
} else {
|
|
88
|
+
finalOutputPath = resolvedOutputPath;
|
|
89
|
+
currentCssPath = resolvedOutputPath;
|
|
90
|
+
}
|
|
91
|
+
const outputDir = path.dirname(finalOutputPath);
|
|
92
|
+
if (!fs.existsSync(outputDir)) {
|
|
93
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
fs.writeFileSync(finalOutputPath, result.css);
|
|
96
|
+
const stats = fs.statSync(finalOutputPath);
|
|
97
|
+
console.log(
|
|
98
|
+
`[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`
|
|
99
|
+
);
|
|
100
|
+
return finalOutputPath;
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error("[UnoCSS Hybrid] Failed to generate CSS:", err);
|
|
103
|
+
return resolvedOutputPath;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
if (isProd) {
|
|
107
|
+
api.onBeforeBuild(async () => {
|
|
108
|
+
await generateCSS();
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (autoInject) {
|
|
112
|
+
api.modifyHTMLTags((tags) => {
|
|
113
|
+
let cssPath;
|
|
114
|
+
if (isProd && enableHash) {
|
|
115
|
+
const cssFileName = path.basename(currentCssPath);
|
|
116
|
+
cssPath = `/${cssFileName}`;
|
|
117
|
+
} else {
|
|
118
|
+
cssPath = "/uno.css";
|
|
119
|
+
}
|
|
120
|
+
tags.headTags.unshift({
|
|
121
|
+
tag: "link",
|
|
122
|
+
attrs: {
|
|
123
|
+
rel: "stylesheet",
|
|
124
|
+
href: cssPath
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);
|
|
128
|
+
return tags;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (!isProd) {
|
|
132
|
+
api.modifyRsbuildConfig((config) => {
|
|
133
|
+
const existingSetupMiddlewares = config.dev?.setupMiddlewares;
|
|
134
|
+
const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares) ? existingSetupMiddlewares : existingSetupMiddlewares ? [existingSetupMiddlewares] : [];
|
|
135
|
+
return {
|
|
136
|
+
...config,
|
|
137
|
+
dev: {
|
|
138
|
+
...config.dev,
|
|
139
|
+
setupMiddlewares: [
|
|
140
|
+
...setupMiddlewaresArray,
|
|
141
|
+
(middlewares, devServer) => {
|
|
142
|
+
devServerInstance = devServer;
|
|
143
|
+
middlewares.unshift(async (req, res, next) => {
|
|
144
|
+
if (req.url === "/uno.css") {
|
|
145
|
+
try {
|
|
146
|
+
if (!fs.existsSync(resolvedOutputPath)) {
|
|
147
|
+
res.statusCode = 404;
|
|
148
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
149
|
+
res.end("CSS file not found. Please restart the dev server to generate it.");
|
|
150
|
+
console.warn("[UnoCSS Hybrid] CSS file not found at:", resolvedOutputPath);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
res.setHeader("Content-Type", "text/css; charset=utf-8");
|
|
154
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
155
|
+
const css = fs.readFileSync(resolvedOutputPath, "utf-8");
|
|
156
|
+
res.end(css);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.error("[UnoCSS Hybrid] Error serving CSS:", err);
|
|
159
|
+
res.statusCode = 500;
|
|
160
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
161
|
+
res.end("Error loading CSS file. Check console for details.");
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
next();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
api.onBeforeStartDevServer(async () => {
|
|
173
|
+
console.log("[UnoCSS Hybrid] Development mode: CLI generation enabled");
|
|
174
|
+
await generateCSS();
|
|
175
|
+
});
|
|
176
|
+
api.onAfterStartDevServer(async () => {
|
|
177
|
+
console.log("[UnoCSS Hybrid] Dev server started, CSS available at /uno.css");
|
|
178
|
+
if (watch) {
|
|
179
|
+
try {
|
|
180
|
+
const chokidar = await import('chokidar');
|
|
181
|
+
const watchDir = path.resolve(rootContext, watchDirectory);
|
|
182
|
+
const watcher = chokidar.watch(watchDir, {
|
|
183
|
+
ignored: /(^|[\/\\])\../,
|
|
184
|
+
// ignore dotfiles
|
|
185
|
+
ignoreInitial: true,
|
|
186
|
+
persistent: true
|
|
187
|
+
});
|
|
188
|
+
let regenerateTimer = null;
|
|
189
|
+
watcher.on("all", async (event, filePath) => {
|
|
190
|
+
const ext = path.extname(filePath);
|
|
191
|
+
const shouldWatch = [".html", ".js", ".ts", ".jsx", ".tsx"].includes(ext);
|
|
192
|
+
if (shouldWatch && (event === "change" || event === "add" || event === "unlink")) {
|
|
193
|
+
console.log(`[UnoCSS Hybrid] File ${event}: ${path.relative(rootContext, filePath)}`);
|
|
194
|
+
if (regenerateTimer) {
|
|
195
|
+
clearTimeout(regenerateTimer);
|
|
196
|
+
}
|
|
197
|
+
regenerateTimer = setTimeout(async () => {
|
|
198
|
+
console.log("[UnoCSS Hybrid] Regenerating CSS...");
|
|
199
|
+
await generateCSS();
|
|
200
|
+
console.log("[UnoCSS Hybrid] Refreshing CSS in browser...");
|
|
201
|
+
devServerInstance?.sockWrite("static-changed", "/uno.css");
|
|
202
|
+
}, 300);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
console.log("[UnoCSS Hybrid] Watch mode: enabled");
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.warn("[UnoCSS Hybrid] Watch mode not available:", err.message);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
api.onAfterBuild(() => {
|
|
213
|
+
if (isProd && fs.existsSync(currentCssPath)) {
|
|
214
|
+
const stats = fs.statSync(currentCssPath);
|
|
215
|
+
const fileName = path.basename(currentCssPath);
|
|
216
|
+
console.log(
|
|
217
|
+
`[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
var plugin_unocss_default = pluginUnocss;
|
|
225
|
+
|
|
226
|
+
export { plugin_unocss_default as default, pluginUnocss };
|
|
227
|
+
//# sourceMappingURL=plugin-unocss.mjs.map
|
|
228
|
+
//# sourceMappingURL=plugin-unocss.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","__dirname"],"mappings":";;;;;;AAOA,IAAMA,YAAA,GAAa,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,IAAMC,WAAA,GAAiB,aAAQD,YAAU,CAAA;AAiElC,SAAS,YAAA,CACd,OAAA,GAA+B,EAAC,EACjB;AACf,EAAA,MAAM;AAAA,IACJ,YAAA,GAAe,iBAAA;AAAA,IACf,UAAA,GAAa,EAAA;AAAA,IACb,eAAA,GAAkB;AAAA,MAChB,iCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,cAAA,GAAiB,KAAA;AAAA,IACjB,UAAA,GAAa,IAAA;AAAA,IACb,KAAA,GAAQ,IAAA;AAAA,IACR,UAAA,GAAa;AAAA,GACf,GAAI,OAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IAEN,MAAM,GAAA,EAAK;AACT,MAAA,MAAM,WAAA,GAAc,IAAI,OAAA,CAAQ,QAAA;AAGhC,MAAA,MAAM,SAAA,GAAYC,WAAA;AAClB,MAAA,IAAI,kBAAA;AAEJ,MAAA,IAAI,CAAC,UAAA,EAAY;AAEf,QAAA,kBAAA,GAA0B,IAAA,CAAA,OAAA,CAAQ,WAAW,qBAAqB,CAAA;AAAA,MACpE,CAAA,MAAA,IAAgB,IAAA,CAAA,UAAA,CAAW,UAAU,CAAA,EAAG;AAEtC,QAAA,kBAAA,GAAqB,UAAA;AAAA,MACvB,CAAA,MAAA,IAAW,UAAA,CAAW,UAAA,CAAW,IAAI,CAAA,EAAG;AAEtC,QAAA,kBAAA,GAA0B,IAAA,CAAA,OAAA,CAAQ,aAAa,UAAU,CAAA;AAAA,MAC3D,CAAA,MAAO;AAEL,QAAA,kBAAA,GAA0B,IAAA,CAAA,OAAA,CAAQ,WAAW,UAAU,CAAA;AAAA,MACzD;AAGA,MAAA,IAAI,cAAA,GAAiB,kBAAA;AAGrB,MAAA,IAAI,iBAAA,GAAyB,IAAA;AAG7B,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA;AAGxC,MAAA,MAAM,aAAa,YAAiC;AAClD,QAAA,IAAI,OAAO,iBAAiB,QAAA,EAAU;AACpC,UAAA,MAAM,UAAA,GAAkB,IAAA,CAAA,OAAA,CAAQ,WAAA,EAAa,YAAY,CAAA;AACzD,UAAA,IAAI;AACF,YAAA,MAAM,YAAA,GAAe,MAAM,OACzB,CAAA,QAAA,EAAW,WAAW,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAC,CAAA,CAAA,CAAA;AAE3C,YAAA,OAAO,aAAa,OAAA,IAAW,YAAA;AAAA,UACjC,SAAS,GAAA,EAAK;AACZ,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,8CAA8C,UAAU,CAAA,sBAAA;AAAA,aAC1D;AACA,YAAA,OAAO,EAAC;AAAA,UACV;AAAA,QACF;AACA,QAAA,OAAO,YAAA;AAAA,MACT,CAAA;AAGA,MAAA,MAAM,cAAc,YAA6B;AAC/C,QAAA,OAAA,CAAQ,IAAI,mCAAmC,CAAA;AAE/C,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,UAAA,EAAW;AAGhC,UAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,OAAO,QAAQ,CAAA;AACxC,UAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,eAAA,EAAiB;AAAA,YAC1C,GAAA,EAAK,WAAA;AAAA,YACL,QAAA,EAAU;AAAA,WACX,CAAA;AAED,UAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,YAAA,OAAA,CAAQ,KAAK,wCAAwC,CAAA;AACrD,YAAA,OAAO,kBAAA;AAAA,UACT;AAEA,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,sBAAA,EAAyB,KAAA,CAAM,MAAM,CAAA,cAAA,CAAgB,CAAA;AACjE,UAAA,OAAA,CAAQ,GAAA,CAAI,0BAA0B,KAAA,CAAM,GAAA,CAAI,OAAU,IAAA,CAAA,QAAA,CAAS,WAAA,EAAa,CAAC,CAAC,CAAC,CAAA;AAGnF,UAAA,MAAM,EAAE,eAAA,EAAgB,GAAI,MAAM,OAAO,QAAQ,CAAA;AACjD,UAAA,MAAM,SAAA,GAAY,MAAM,eAAA,CAAgB,MAAM,CAAA;AAG9C,UAAA,MAAM,WAAA,GAAc,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AACpC,YAAA,MAAM,OAAA,GAAa,EAAA,CAAA,YAAA,CAAa,IAAA,EAAM,OAAO,CAAA;AAC7C,YAAA,OAAO,OAAA;AAAA,UACT,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAGZ,UAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,QAAA,CAAS,WAAW,CAAA;AAEnD,UAAA,IAAI,CAAC,OAAO,GAAA,IAAO,MAAA,CAAO,IAAI,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AACjD,YAAA,OAAA,CAAQ,KAAK,wCAAwC,CAAA;AACrD,YAAA,OAAO,kBAAA;AAAA,UACT;AAGA,UAAA,IAAI,eAAA;AACJ,UAAA,IAAI,UAAU,UAAA,EAAY;AAExB,YAAA,MAAM,OAAA,GAAe,IAAA,CAAA,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA;AAC7C,YAAA,MAAM,IAAA,GAAO,UAAA,CAAW,KAAK,CAAA,CAAE,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,SAAA,CAAU,GAAG,CAAC,CAAA;AAC9E,YAAA,eAAA,GAAuB,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,CAAA,IAAA,EAAO,IAAI,CAAA,IAAA,CAAM,CAAA;AACtD,YAAA,cAAA,GAAiB,eAAA;AAAA,UACnB,CAAA,MAAO;AAEL,YAAA,eAAA,GAAkB,kBAAA;AAClB,YAAA,cAAA,GAAiB,kBAAA;AAAA,UACnB;AAGA,UAAA,MAAM,SAAA,GAAiB,aAAQ,eAAe,CAAA;AAC9C,UAAA,IAAI,CAAI,EAAA,CAAA,UAAA,CAAW,SAAS,CAAA,EAAG;AAC7B,YAAG,EAAA,CAAA,SAAA,CAAU,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,UAC7C;AAGA,UAAG,EAAA,CAAA,aAAA,CAAc,eAAA,EAAiB,MAAA,CAAO,GAAG,CAAA;AAE5C,UAAA,MAAM,KAAA,GAAW,YAAS,eAAe,CAAA;AACzC,UAAA,OAAA,CAAQ,GAAA;AAAA,YACN,CAAA,+BAAA,EAAkC,eAAe,CAAA,EAAA,EAAA,CAAM,KAAA,CAAM,OAAO,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA;AAAA,WACtF;AAEA,UAAA,OAAO,eAAA;AAAA,QACT,SAAS,GAAA,EAAK;AACZ,UAAA,OAAA,CAAQ,KAAA,CAAM,2CAA2C,GAAG,CAAA;AAC5D,UAAA,OAAO,kBAAA;AAAA,QACT;AAAA,MACF,CAAA;AAGA,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,GAAA,CAAI,cAAc,YAAY;AAC5B,UAAA,MAAM,WAAA,EAAY;AAAA,QACpB,CAAC,CAAA;AAAA,MACH;AAGA,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,GAAA,CAAI,cAAA,CAAe,CAAC,IAAA,KAAS;AAC3B,UAAA,IAAI,OAAA;AAEJ,UAAA,IAAI,UAAU,UAAA,EAAY;AAExB,YAAA,MAAM,WAAA,GAAmB,cAAS,cAAc,CAAA;AAChD,YAAA,OAAA,GAAU,IAAI,WAAW,CAAA,CAAA;AAAA,UAC3B,CAAA,MAAO;AAEL,YAAA,OAAA,GAAU,UAAA;AAAA,UACZ;AAEA,UAAA,IAAA,CAAK,SAAS,OAAA,CAAQ;AAAA,YACpB,GAAA,EAAK,MAAA;AAAA,YACL,KAAA,EAAO;AAAA,cACL,GAAA,EAAK,YAAA;AAAA,cACL,IAAA,EAAM;AAAA;AACR,WACD,CAAA;AAED,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,wCAAA,EAA2C,OAAO,CAAA,CAAE,CAAA;AAChE,UAAA,OAAO,IAAA;AAAA,QACT,CAAC,CAAA;AAAA,MACH;AAGA,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,GAAA,CAAI,mBAAA,CAAoB,CAAC,MAAA,KAAW;AAClC,UAAA,MAAM,wBAAA,GAA2B,OAAO,GAAA,EAAK,gBAAA;AAC7C,UAAA,MAAM,qBAAA,GAAwB,KAAA,CAAM,OAAA,CAAQ,wBAAwB,CAAA,GAChE,2BACA,wBAAA,GACE,CAAC,wBAAwB,CAAA,GACzB,EAAC;AAEP,UAAA,OAAO;AAAA,YACL,GAAG,MAAA;AAAA,YACH,GAAA,EAAK;AAAA,cACH,GAAG,MAAA,CAAO,GAAA;AAAA,cACV,gBAAA,EAAkB;AAAA,gBAChB,GAAG,qBAAA;AAAA,gBACH,CAAC,aAAa,SAAA,KAAc;AAE1B,kBAAA,iBAAA,GAAoB,SAAA;AAGpB,kBAAA,WAAA,CAAY,OAAA,CAAQ,OAAO,GAAA,EAAK,GAAA,EAAK,IAAA,KAAS;AAC5C,oBAAA,IAAI,GAAA,CAAI,QAAQ,UAAA,EAAY;AAC1B,sBAAA,IAAI;AAEF,wBAAA,IAAI,CAAI,EAAA,CAAA,UAAA,CAAW,kBAAkB,CAAA,EAAG;AACtC,0BAAA,GAAA,CAAI,UAAA,GAAa,GAAA;AACjB,0BAAA,GAAA,CAAI,SAAA,CAAU,gBAAgB,2BAA2B,CAAA;AACzD,0BAAA,GAAA,CAAI,IAAI,mEAAmE,CAAA;AAC3E,0BAAA,OAAA,CAAQ,IAAA,CAAK,0CAA0C,kBAAkB,CAAA;AACzE,0BAAA;AAAA,wBACF;AAGA,wBAAA,GAAA,CAAI,SAAA,CAAU,gBAAgB,yBAAyB,CAAA;AACvD,wBAAA,GAAA,CAAI,SAAA,CAAU,iBAAiB,UAAU,CAAA;AAEzC,wBAAA,MAAM,GAAA,GAAS,EAAA,CAAA,YAAA,CAAa,kBAAA,EAAoB,OAAO,CAAA;AACvD,wBAAA,GAAA,CAAI,IAAI,GAAG,CAAA;AAAA,sBACb,SAAS,GAAA,EAAK;AACZ,wBAAA,OAAA,CAAQ,KAAA,CAAM,sCAAsC,GAAG,CAAA;AACvD,wBAAA,GAAA,CAAI,UAAA,GAAa,GAAA;AACjB,wBAAA,GAAA,CAAI,SAAA,CAAU,gBAAgB,2BAA2B,CAAA;AACzD,wBAAA,GAAA,CAAI,IAAI,oDAAoD,CAAA;AAAA,sBAC9D;AAAA,oBACF,CAAA,MAAO;AACL,sBAAA,IAAA,EAAK;AAAA,oBACP;AAAA,kBACF,CAAC,CAAA;AAAA,gBACH;AAAA;AACF;AACF,WACF;AAAA,QACF,CAAC,CAAA;AAGD,QAAA,GAAA,CAAI,uBAAuB,YAAY;AACrC,UAAA,OAAA,CAAQ,IAAI,0DAA0D,CAAA;AACtE,UAAA,MAAM,WAAA,EAAY;AAAA,QACpB,CAAC,CAAA;AAGD,QAAA,GAAA,CAAI,sBAAsB,YAAY;AACpC,UAAA,OAAA,CAAQ,IAAI,+DAA+D,CAAA;AAG3E,UAAA,IAAI,KAAA,EAAO;AACT,YAAA,IAAI;AAEF,cAAA,MAAM,QAAA,GAAW,MAAM,OAAO,UAAU,CAAA;AAGxC,cAAA,MAAM,QAAA,GAAgB,IAAA,CAAA,OAAA,CAAQ,WAAA,EAAa,cAAc,CAAA;AAGzD,cAAA,MAAM,OAAA,GAAU,QAAA,CAAS,KAAA,CAAM,QAAA,EAAU;AAAA,gBACvC,OAAA,EAAS,eAAA;AAAA;AAAA,gBACT,aAAA,EAAe,IAAA;AAAA,gBACf,UAAA,EAAY;AAAA,eACb,CAAA;AAGD,cAAA,IAAI,eAAA,GAAyC,IAAA;AAE7C,cAAA,OAAA,CAAQ,EAAA,CAAG,KAAA,EAAO,OAAO,KAAA,EAAe,QAAA,KAAqB;AAE3D,gBAAA,MAAM,GAAA,GAAW,aAAQ,QAAQ,CAAA;AACjC,gBAAA,MAAM,WAAA,GAAc,CAAC,OAAA,EAAS,KAAA,EAAO,OAAO,MAAA,EAAQ,MAAM,CAAA,CAAE,QAAA,CAAS,GAAG,CAAA;AAGxE,gBAAA,IAAI,gBAAgB,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,KAAA,IAAS,UAAU,QAAA,CAAA,EAAW;AAChF,kBAAA,OAAA,CAAQ,GAAA,CAAI,wBAAwB,KAAK,CAAA,EAAA,EAAU,cAAS,WAAA,EAAa,QAAQ,CAAC,CAAA,CAAE,CAAA;AAEpF,kBAAA,IAAI,eAAA,EAAiB;AACnB,oBAAA,YAAA,CAAa,eAAe,CAAA;AAAA,kBAC9B;AAEA,kBAAA,eAAA,GAAkB,WAAW,YAAY;AACvC,oBAAA,OAAA,CAAQ,IAAI,qCAAqC,CAAA;AACjD,oBAAA,MAAM,WAAA,EAAY;AAGlB,oBAAA,OAAA,CAAQ,IAAI,8CAA8C,CAAA;AAC1D,oBAAA,iBAAA,EAAmB,SAAA,CAAU,kBAAkB,UAAU,CAAA;AAAA,kBAC3D,GAAG,GAAG,CAAA;AAAA,gBACR;AAAA,cACF,CAAC,CAAA;AAED,cAAA,OAAA,CAAQ,IAAI,qCAAqC,CAAA;AAAA,YACnD,SAAS,GAAA,EAAK;AACZ,cAAA,OAAA,CAAQ,IAAA,CAAK,2CAAA,EAA8C,GAAA,CAAc,OAAO,CAAA;AAAA,YAClF;AAAA,UACF;AAAA,QACF,CAAC,CAAA;AAAA,MACH;AAGA,MAAA,GAAA,CAAI,aAAa,MAAM;AACrB,QAAA,IAAI,MAAA,IAAa,EAAA,CAAA,UAAA,CAAW,cAAc,CAAA,EAAG;AAC3C,UAAA,MAAM,KAAA,GAAW,YAAS,cAAc,CAAA;AACxC,UAAA,MAAM,QAAA,GAAgB,cAAS,cAAc,CAAA;AAC7C,UAAA,OAAA,CAAQ,GAAA;AAAA,YACN,CAAA,2BAAA,EAA8B,QAAQ,CAAA,EAAA,EAAA,CAAM,KAAA,CAAM,OAAO,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA;AAAA,WAC3E;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF;AAEA,IAAO,qBAAA,GAAQ","file":"plugin-unocss.mjs","sourcesContent":["import type { RsbuildPlugin } from '@rsbuild/core';\nimport type { UserConfig } from 'unocss';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport { createHash } from 'crypto';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface PluginUnocssOptions {\n /** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */\n unocssConfig?: string | UserConfig;\n\n /**\n * 生成的 CSS 文件输出路径\n *\n * 路径解析规则:\n * - 以 './' 开头: 相对于项目根目录 (推荐)\n * - 相对路径: 相对于插件目录\n * - 绝对路径: 直接使用\n * - 未配置: 默认为 'generated/uno.css' 相对于插件目录\n */\n outputPath?: string;\n\n /** 扫描的内容文件路径模式 (支持 glob 模式) */\n contentPatterns?: string[];\n\n /** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */\n watchDirectory?: string;\n\n /** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */\n autoInject?: boolean;\n\n /** 是否在开发环境启用文件监听模式 (默认: true) */\n watch?: boolean;\n\n /**\n * 是否在生产环境为 CSS 文件名添加 content hash\n *\n * 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)\n */\n enableHash?: boolean;\n}\n\n/**\n * UnoCSS Plugin for Rsbuild\n *\n * 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.\n *\n * 特性:\n * - 扫描项目文件并生成独立的 CSS 文件\n * - 开发环境支持文件监听和热更新\n * - 生产环境支持 CSS 文件名 hash\n * - 自动在 HTML 中注入 CSS link 标签\n *\n * @param options - 插件配置选项\n * @returns Rsbuild 插件实例\n *\n * @example\n * ```ts\n * import { pluginUnocss } from '@ikkin/plugin-unocss';\n *\n * export default {\n * plugins: [\n * pluginUnocss({\n * outputPath: './src/generated/uno.css',\n * enableHash: true,\n * })\n * ]\n * };\n * ```\n */\nexport function pluginUnocss(\n options: PluginUnocssOptions = {},\n): RsbuildPlugin {\n const {\n unocssConfig = './uno.config.ts',\n outputPath = '',\n contentPatterns = [\n './src/**/*.{html,js,ts,jsx,tsx}',\n './index.html',\n ],\n watchDirectory = 'src',\n autoInject = true,\n watch = true,\n enableHash = true,\n } = options;\n\n return {\n name: 'unocss',\n\n setup(api) {\n const rootContext = api.context.rootPath;\n\n // 解析输出路径\n const pluginDir = __dirname;\n let resolvedOutputPath: string;\n\n if (!outputPath) {\n // 未配置:使用默认路径(相对于插件目录)\n resolvedOutputPath = path.resolve(pluginDir, './generated/uno.css');\n } else if (path.isAbsolute(outputPath)) {\n // 绝对路径:直接使用\n resolvedOutputPath = outputPath;\n } else if (outputPath.startsWith('./')) {\n // 以 ./ 开头:相对于项目根目录(推荐,更明确)\n resolvedOutputPath = path.resolve(rootContext, outputPath);\n } else {\n // 相对路径(不带 ./):相对于插件目录(更简洁)\n resolvedOutputPath = path.resolve(pluginDir, outputPath);\n }\n\n // 用于保存当前生成的 CSS 文件路径(可能包含 hash)\n let currentCssPath = resolvedOutputPath;\n\n // 用于保存 dev server 实例,以便在文件变化时触发刷新\n let devServerInstance: any = null;\n\n // 通过环境变量判断是否是生产环境\n const isProd = process.env.NODE_ENV === 'production';\n\n // 读取 UnoCSS 配置\n const loadConfig = async (): Promise<UserConfig> => {\n if (typeof unocssConfig === 'string') {\n const configPath = path.resolve(rootContext, unocssConfig);\n try {\n const configModule = await import(\n `file:///${configPath.replace(/\\\\/g, '/')}`\n );\n return configModule.default || configModule;\n } catch (err) {\n console.warn(\n `[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`,\n );\n return {};\n }\n }\n return unocssConfig;\n };\n\n // 生成 UnoCSS CSS\n const generateCSS = async (): Promise<string> => {\n console.log('[UnoCSS Hybrid] Generating CSS...');\n\n try {\n const config = await loadConfig();\n\n // 扫描文件\n const { globby } = await import('globby');\n const files = await globby(contentPatterns, {\n cwd: rootContext,\n absolute: true,\n });\n\n if (files.length === 0) {\n console.warn('[UnoCSS Hybrid] No files found to scan');\n return resolvedOutputPath;\n }\n\n console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);\n console.log(`[UnoCSS Hybrid] Files:`, files.map(f => path.relative(rootContext, f)));\n\n // 使用 UnoCSS generator\n const { createGenerator } = await import('unocss');\n const generator = await createGenerator(config);\n\n // 读取所有文件内容并生成\n const allContents = files.map(file => {\n const content = fs.readFileSync(file, 'utf-8');\n return content;\n }).join('\\n');\n\n // 生成 CSS\n const result = await generator.generate(allContents);\n\n if (!result.css || result.css.trim().length === 0) {\n console.warn('[UnoCSS Hybrid] Generated CSS is empty');\n return resolvedOutputPath;\n }\n\n // 计算输出路径\n let finalOutputPath: string;\n if (isProd && enableHash) {\n // 生产环境:直接生成到 dist 目录,文件名带 hash\n const distDir = path.join(rootContext, 'dist');\n const hash = createHash('md5').update(result.css).digest('hex').substring(0, 8);\n finalOutputPath = path.join(distDir, `uno.${hash}.css`);\n currentCssPath = finalOutputPath;\n } else {\n // 开发环境:生成到插件目录的 generated 子目录,文件名固定\n finalOutputPath = resolvedOutputPath;\n currentCssPath = resolvedOutputPath;\n }\n\n // 确保输出目录存在\n const outputDir = path.dirname(finalOutputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // 写入 CSS 文件\n fs.writeFileSync(finalOutputPath, result.css);\n\n const stats = fs.statSync(finalOutputPath);\n console.log(\n `[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`,\n );\n\n return finalOutputPath;\n } catch (err) {\n console.error('[UnoCSS Hybrid] Failed to generate CSS:', err);\n return resolvedOutputPath;\n }\n };\n\n // 生产环境:构建前生成 CSS\n if (isProd) {\n api.onBeforeBuild(async () => {\n await generateCSS();\n });\n }\n\n // 自动注入:通过修改 HTML 标签来注入 CSS(不污染源码)\n if (autoInject) {\n api.modifyHTMLTags((tags) => {\n let cssPath: string;\n\n if (isProd && enableHash) {\n // 生产环境:使用带 hash 的文件名\n const cssFileName = path.basename(currentCssPath);\n cssPath = `/${cssFileName}`;\n } else {\n // 开发环境或未启用 hash:使用固定文件名\n cssPath = '/uno.css';\n }\n\n tags.headTags.unshift({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n href: cssPath,\n },\n });\n\n console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);\n return tags;\n });\n }\n\n // 开发环境:配置静态文件服务\n if (!isProd) {\n api.modifyRsbuildConfig((config) => {\n const existingSetupMiddlewares = config.dev?.setupMiddlewares;\n const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares)\n ? existingSetupMiddlewares\n : existingSetupMiddlewares\n ? [existingSetupMiddlewares]\n : [];\n\n return {\n ...config,\n dev: {\n ...config.dev,\n setupMiddlewares: [\n ...setupMiddlewaresArray,\n (middlewares, devServer) => {\n // 保存 dev server 实例\n devServerInstance = devServer;\n\n // 添加自定义中间件来提供 CSS 文件\n middlewares.unshift(async (req, res, next) => {\n if (req.url === '/uno.css') {\n try {\n // 检查文件是否存在\n if (!fs.existsSync(resolvedOutputPath)) {\n res.statusCode = 404;\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('CSS file not found. Please restart the dev server to generate it.');\n console.warn('[UnoCSS Hybrid] CSS file not found at:', resolvedOutputPath);\n return;\n }\n\n // 设置正确的 Content-Type 和缓存控制\n res.setHeader('Content-Type', 'text/css; charset=utf-8');\n res.setHeader('Cache-Control', 'no-cache');\n\n const css = fs.readFileSync(resolvedOutputPath, 'utf-8');\n res.end(css);\n } catch (err) {\n console.error('[UnoCSS Hybrid] Error serving CSS:', err);\n res.statusCode = 500;\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Error loading CSS file. Check console for details.');\n }\n } else {\n next();\n }\n });\n },\n ],\n },\n };\n });\n\n // 启动时生成 CSS\n api.onBeforeStartDevServer(async () => {\n console.log('[UnoCSS Hybrid] Development mode: CLI generation enabled');\n await generateCSS();\n });\n\n // 合并启动后的操作\n api.onAfterStartDevServer(async () => {\n console.log('[UnoCSS Hybrid] Dev server started, CSS available at /uno.css');\n\n // Watch 模式\n if (watch) {\n try {\n // 动态导入 chokidar\n const chokidar = await import('chokidar');\n\n // 监听指定目录\n const watchDir = path.resolve(rootContext, watchDirectory);\n\n // 监听内容文件变化\n const watcher = chokidar.watch(watchDir, {\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\n ignoreInitial: true,\n persistent: true,\n });\n\n // 防抖:避免频繁重新生成\n let regenerateTimer: NodeJS.Timeout | null = null;\n\n watcher.on('all', async (event: string, filePath: string) => {\n // 检查文件扩展名\n const ext = path.extname(filePath);\n const shouldWatch = ['.html', '.js', '.ts', '.jsx', '.tsx'].includes(ext);\n\n // 监听文件添加、修改和删除\n if (shouldWatch && (event === 'change' || event === 'add' || event === 'unlink')) {\n console.log(`[UnoCSS Hybrid] File ${event}: ${path.relative(rootContext, filePath)}`);\n\n if (regenerateTimer) {\n clearTimeout(regenerateTimer);\n }\n\n regenerateTimer = setTimeout(async () => {\n console.log('[UnoCSS Hybrid] Regenerating CSS...');\n await generateCSS();\n\n // 触发浏览器刷新 CSS\n console.log('[UnoCSS Hybrid] Refreshing CSS in browser...');\n devServerInstance?.sockWrite('static-changed', '/uno.css');\n }, 300);\n }\n });\n\n console.log('[UnoCSS Hybrid] Watch mode: enabled');\n } catch (err) {\n console.warn('[UnoCSS Hybrid] Watch mode not available:', (err as Error).message);\n }\n }\n });\n }\n\n // 构建完成后的日志\n api.onAfterBuild(() => {\n if (isProd && fs.existsSync(currentCssPath)) {\n const stats = fs.statSync(currentCssPath);\n const fileName = path.basename(currentCssPath);\n console.log(\n `[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`,\n );\n }\n });\n },\n };\n}\n\nexport default pluginUnocss;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ikkin/plugin-unocss",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "UnoCSS plugin for Rsbuild with CLI pre-generation and automatic injection",
|
|
5
|
+
"main": "./dist/plugin-unocss.js",
|
|
6
|
+
"module": "./dist/plugin-unocss.mjs",
|
|
7
|
+
"types": "./dist/plugin-unocss.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/plugin-unocss.d.ts",
|
|
11
|
+
"import": "./dist/plugin-unocss.mjs",
|
|
12
|
+
"require": "./dist/plugin-unocss.js",
|
|
13
|
+
"default": "./dist/plugin-unocss.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"prepack": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"rsbuild",
|
|
29
|
+
"plugin",
|
|
30
|
+
"unocss",
|
|
31
|
+
"css",
|
|
32
|
+
"atomic-css",
|
|
33
|
+
"utility-class",
|
|
34
|
+
"windi-css",
|
|
35
|
+
"tailwind",
|
|
36
|
+
"cli",
|
|
37
|
+
"atomic-css-engine"
|
|
38
|
+
],
|
|
39
|
+
"author": "ikkin <your.email@example.com>",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/ikkin/plugin-unocss.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/ikkin/plugin-unocss#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/ikkin/plugin-unocss/issues"
|
|
48
|
+
},
|
|
49
|
+
"sideEffects": false,
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@rsbuild/core": ">=1.0.0",
|
|
52
|
+
"unocss": ">=0.60.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"globby": "^14.0.0",
|
|
56
|
+
"chokidar": "^4.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@rsbuild/core": "^1.1.0",
|
|
60
|
+
"@types/node": "^22.0.0",
|
|
61
|
+
"tsup": "^8.0.0",
|
|
62
|
+
"typescript": "^5.6.0",
|
|
63
|
+
"unocss": "^66.6.0"
|
|
64
|
+
}
|
|
65
|
+
}
|