@ikkin/plugin-unocss 1.0.0 → 1.0.1

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.
@@ -134,6 +134,7 @@ function pluginUnocss(options = {}) {
134
134
  await generateCSS();
135
135
  });
136
136
  }
137
+ let cssVersion = Date.now();
137
138
  if (autoInject) {
138
139
  api.modifyHTMLTags((tags) => {
139
140
  let cssPath;
@@ -151,6 +152,45 @@ function pluginUnocss(options = {}) {
151
152
  }
152
153
  });
153
154
  console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);
155
+ if (!isProd) {
156
+ const hotReloadScript = `
157
+ (() => {
158
+ window.__unocss_version__ = ${cssVersion};
159
+
160
+ // \u76D1\u542C WebSocket \u6D88\u606F
161
+ const originalOnMessage = window.__whm__?.fns?.push;
162
+ if (window.__whm__?.fns) {
163
+ window.__whm__.fns.push(function(data) {
164
+ // \u76D1\u542C\u81EA\u5B9A\u4E49\u70ED\u66F4\u65B0\u4E8B\u4EF6
165
+ if (data.type === 'unocss-css-update') {
166
+ const { version } = data.data;
167
+ if (version !== window.__unocss_version__) {
168
+ window.__unocss_version__ = version;
169
+
170
+ // \u67E5\u627E UnoCSS \u7684 link \u6807\u7B7E
171
+ const link = document.querySelector('link[href*="/uno.css"]');
172
+ if (link) {
173
+ // \u66F4\u65B0 href \u5F3A\u5236\u91CD\u65B0\u52A0\u8F7D
174
+ const href = link.getAttribute('href');
175
+ if (href) {
176
+ // \u6DFB\u52A0\u7248\u672C\u53F7\u4F5C\u4E3A\u67E5\u8BE2\u53C2\u6570
177
+ const newHref = href.split('?')[0] + '?v=' + version;
178
+ link.setAttribute('href', newHref);
179
+ console.log('[UnoCSS] CSS hot updated:', newHref);
180
+ }
181
+ }
182
+ }
183
+ }
184
+ });
185
+ }
186
+ })();
187
+ `;
188
+ tags.bodyTags.push({
189
+ tag: "script",
190
+ children: hotReloadScript
191
+ });
192
+ console.log("[UnoCSS Hybrid] Hot reload script injected");
193
+ }
154
194
  return tags;
155
195
  });
156
196
  }
@@ -167,7 +207,7 @@ function pluginUnocss(options = {}) {
167
207
  (middlewares, devServer) => {
168
208
  devServerInstance = devServer;
169
209
  middlewares.unshift(async (req, res, next) => {
170
- if (req.url === "/uno.css") {
210
+ if (req.url?.startsWith("/uno.css")) {
171
211
  try {
172
212
  if (!fs__namespace.existsSync(resolvedOutputPath)) {
173
213
  res.statusCode = 404;
@@ -223,8 +263,12 @@ function pluginUnocss(options = {}) {
223
263
  regenerateTimer = setTimeout(async () => {
224
264
  console.log("[UnoCSS Hybrid] Regenerating CSS...");
225
265
  await generateCSS();
226
- console.log("[UnoCSS Hybrid] Refreshing CSS in browser...");
227
- devServerInstance?.sockWrite("static-changed", "/uno.css");
266
+ cssVersion = Date.now();
267
+ console.log("[UnoCSS Hybrid] Hot updating CSS in browser...");
268
+ devServerInstance?.sockWrite("unocss-css-update", {
269
+ version: cssVersion,
270
+ path: "/uno.css"
271
+ });
228
272
  }, 300);
229
273
  }
230
274
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","fileURLToPath","__dirname","path","fs","createHash"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,IAAMA,YAAA,GAAaC,iBAAA,CAAc,kQAAe,CAAA;AAChD,IAAMC,WAAA,GAAiBC,wBAAQH,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,GAAYE,WAAA;AAClB,MAAA,IAAI,kBAAA;AAEJ,MAAA,IAAI,CAAC,UAAA,EAAY;AAEf,QAAA,kBAAA,GAA0BC,eAAA,CAAA,OAAA,CAAQ,WAAW,qBAAqB,CAAA;AAAA,MACpE,CAAA,MAAA,IAAgBA,eAAA,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,GAA0BA,eAAA,CAAA,OAAA,CAAQ,aAAa,UAAU,CAAA;AAAA,MAC3D,CAAA,MAAO;AAEL,QAAA,kBAAA,GAA0BA,eAAA,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,GAAkBA,eAAA,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,OAAUA,eAAA,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,GAAaC,aAAA,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,GAAeD,eAAA,CAAA,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA;AAC7C,YAAA,MAAM,IAAA,GAAOE,iBAAA,CAAW,KAAK,CAAA,CAAE,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,SAAA,CAAU,GAAG,CAAC,CAAA;AAC9E,YAAA,eAAA,GAAuBF,eAAA,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,GAAiBA,wBAAQ,eAAe,CAAA;AAC9C,UAAA,IAAI,CAAIC,aAAA,CAAA,UAAA,CAAW,SAAS,CAAA,EAAG;AAC7B,YAAGA,aAAA,CAAA,SAAA,CAAU,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,UAC7C;AAGA,UAAGA,aAAA,CAAA,aAAA,CAAc,eAAA,EAAiB,MAAA,CAAO,GAAG,CAAA;AAE5C,UAAA,MAAM,KAAA,GAAWA,uBAAS,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,GAAmBD,yBAAS,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,CAAIC,aAAA,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,GAASA,aAAA,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,GAAgBD,eAAA,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,GAAWA,wBAAQ,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,EAAUA,yBAAS,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,IAAaC,aAAA,CAAA,UAAA,CAAW,cAAc,CAAA,EAAG;AAC3C,UAAA,MAAM,KAAA,GAAWA,uBAAS,cAAc,CAAA;AACxC,UAAA,MAAM,QAAA,GAAgBD,yBAAS,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.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"]}
1
+ {"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","fileURLToPath","__dirname","path","fs","createHash"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,IAAMA,YAAA,GAAaC,iBAAA,CAAc,kQAAe,CAAA;AAChD,IAAMC,WAAA,GAAiBC,wBAAQH,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,GAAYE,WAAA;AAClB,MAAA,IAAI,kBAAA;AAEJ,MAAA,IAAI,CAAC,UAAA,EAAY;AAEf,QAAA,kBAAA,GAA0BC,eAAA,CAAA,OAAA,CAAQ,WAAW,qBAAqB,CAAA;AAAA,MACpE,CAAA,MAAA,IAAgBA,eAAA,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,GAA0BA,eAAA,CAAA,OAAA,CAAQ,aAAa,UAAU,CAAA;AAAA,MAC3D,CAAA,MAAO;AAEL,QAAA,kBAAA,GAA0BA,eAAA,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,GAAkBA,eAAA,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,OAAUA,eAAA,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,GAAaC,aAAA,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,GAAeD,eAAA,CAAA,IAAA,CAAK,WAAA,EAAa,MAAM,CAAA;AAC7C,YAAA,MAAM,IAAA,GAAOE,iBAAA,CAAW,KAAK,CAAA,CAAE,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,SAAA,CAAU,GAAG,CAAC,CAAA;AAC9E,YAAA,eAAA,GAAuBF,eAAA,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,GAAiBA,wBAAQ,eAAe,CAAA;AAC9C,UAAA,IAAI,CAAIC,aAAA,CAAA,UAAA,CAAW,SAAS,CAAA,EAAG;AAC7B,YAAGA,aAAA,CAAA,SAAA,CAAU,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,UAC7C;AAGA,UAAGA,aAAA,CAAA,aAAA,CAAc,eAAA,EAAiB,MAAA,CAAO,GAAG,CAAA;AAE5C,UAAA,MAAM,KAAA,GAAWA,uBAAS,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,GAAa,KAAK,GAAA,EAAI;AAG1B,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,GAAmBD,yBAAS,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;AAGhE,UAAA,IAAI,CAAC,MAAA,EAAQ;AACX,YAAA,MAAM,eAAA,GAAkB;AAAA;AAAA,4CAAA,EAEU,UAAU,CAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAA,CAAA;AA8B5C,YAAA,IAAA,CAAK,SAAS,IAAA,CAAK;AAAA,cACjB,GAAA,EAAK,QAAA;AAAA,cACL,QAAA,EAAU;AAAA,aACX,CAAA;AACD,YAAA,OAAA,CAAQ,IAAI,4CAA4C,CAAA;AAAA,UAC1D;AAEA,UAAA,OAAO,IAAA;AAAA,QACT,CAAC,CAAA;AAAA,MACH;AAGA,MAAA,IAAI,CAAC,MAAA,EAAQ;AAEX,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,GAAA,EAAK,UAAA,CAAW,UAAU,CAAA,EAAG;AACnC,sBAAA,IAAI;AAEF,wBAAA,IAAI,CAAIC,aAAA,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,GAASA,aAAA,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,GAAgBD,eAAA,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,GAAWA,wBAAQ,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,EAAUA,yBAAS,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,UAAA,GAAa,KAAK,GAAA,EAAI;AAGtB,oBAAA,OAAA,CAAQ,IAAI,gDAAgD,CAAA;AAC5D,oBAAA,iBAAA,EAAmB,UAAU,mBAAA,EAAqB;AAAA,sBAChD,OAAA,EAAS,UAAA;AAAA,sBACT,IAAA,EAAM;AAAA,qBACP,CAAA;AAAA,kBACH,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,IAAaC,aAAA,CAAA,UAAA,CAAW,cAAc,CAAA,EAAG;AAC3C,UAAA,MAAM,KAAA,GAAWA,uBAAS,cAAc,CAAA;AACxC,UAAA,MAAM,QAAA,GAAgBD,yBAAS,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.js","sourcesContent":["import type { RsbuildPlugin } from '@rsbuild/core';\r\nimport type { UserConfig } from 'unocss';\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport { fileURLToPath } from 'url';\r\nimport { createHash } from 'crypto';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\n\r\nexport interface PluginUnocssOptions {\r\n /** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */\r\n unocssConfig?: string | UserConfig;\r\n\r\n /**\r\n * 生成的 CSS 文件输出路径\r\n *\r\n * 路径解析规则:\r\n * - 以 './' 开头: 相对于项目根目录 (推荐)\r\n * - 相对路径: 相对于插件目录\r\n * - 绝对路径: 直接使用\r\n * - 未配置: 默认为 'generated/uno.css' 相对于插件目录\r\n */\r\n outputPath?: string;\r\n\r\n /** 扫描的内容文件路径模式 (支持 glob 模式) */\r\n contentPatterns?: string[];\r\n\r\n /** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */\r\n watchDirectory?: string;\r\n\r\n /** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */\r\n autoInject?: boolean;\r\n\r\n /** 是否在开发环境启用文件监听模式 (默认: true) */\r\n watch?: boolean;\r\n\r\n /**\r\n * 是否在生产环境为 CSS 文件名添加 content hash\r\n *\r\n * 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)\r\n */\r\n enableHash?: boolean;\r\n}\r\n\r\n/**\r\n * UnoCSS Plugin for Rsbuild\r\n *\r\n * 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.\r\n *\r\n * 特性:\r\n * - 扫描项目文件并生成独立的 CSS 文件\r\n * - 开发环境支持文件监听和热更新\r\n * - 生产环境支持 CSS 文件名 hash\r\n * - 自动在 HTML 中注入 CSS link 标签\r\n *\r\n * @param options - 插件配置选项\r\n * @returns Rsbuild 插件实例\r\n *\r\n * @example\r\n * ```ts\r\n * import { pluginUnocss } from '@ikkin/plugin-unocss';\r\n *\r\n * export default {\r\n * plugins: [\r\n * pluginUnocss({\r\n * outputPath: './src/generated/uno.css',\r\n * enableHash: true,\r\n * })\r\n * ]\r\n * };\r\n * ```\r\n */\r\nexport function pluginUnocss(\r\n options: PluginUnocssOptions = {},\r\n): RsbuildPlugin {\r\n const {\r\n unocssConfig = './uno.config.ts',\r\n outputPath = '',\r\n contentPatterns = [\r\n './src/**/*.{html,js,ts,jsx,tsx}',\r\n './index.html',\r\n ],\r\n watchDirectory = 'src',\r\n autoInject = true,\r\n watch = true,\r\n enableHash = true,\r\n } = options;\r\n\r\n return {\r\n name: 'unocss',\r\n\r\n setup(api) {\r\n const rootContext = api.context.rootPath;\r\n\r\n // 解析输出路径\r\n const pluginDir = __dirname;\r\n let resolvedOutputPath: string;\r\n\r\n if (!outputPath) {\r\n // 未配置:使用默认路径(相对于插件目录)\r\n resolvedOutputPath = path.resolve(pluginDir, './generated/uno.css');\r\n } else if (path.isAbsolute(outputPath)) {\r\n // 绝对路径:直接使用\r\n resolvedOutputPath = outputPath;\r\n } else if (outputPath.startsWith('./')) {\r\n // 以 ./ 开头:相对于项目根目录(推荐,更明确)\r\n resolvedOutputPath = path.resolve(rootContext, outputPath);\r\n } else {\r\n // 相对路径(不带 ./):相对于插件目录(更简洁)\r\n resolvedOutputPath = path.resolve(pluginDir, outputPath);\r\n }\r\n\r\n // 用于保存当前生成的 CSS 文件路径(可能包含 hash)\r\n let currentCssPath = resolvedOutputPath;\r\n\r\n // 用于保存 dev server 实例,以便在文件变化时触发刷新\r\n let devServerInstance: any = null;\r\n\r\n // 通过环境变量判断是否是生产环境\r\n const isProd = process.env.NODE_ENV === 'production';\r\n\r\n // 读取 UnoCSS 配置\r\n const loadConfig = async (): Promise<UserConfig> => {\r\n if (typeof unocssConfig === 'string') {\r\n const configPath = path.resolve(rootContext, unocssConfig);\r\n try {\r\n const configModule = await import(\r\n `file:///${configPath.replace(/\\\\/g, '/')}`\r\n );\r\n return configModule.default || configModule;\r\n } catch (err) {\r\n console.warn(\r\n `[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`,\r\n );\r\n return {};\r\n }\r\n }\r\n return unocssConfig;\r\n };\r\n\r\n // 生成 UnoCSS CSS\r\n const generateCSS = async (): Promise<string> => {\r\n console.log('[UnoCSS Hybrid] Generating CSS...');\r\n\r\n try {\r\n const config = await loadConfig();\r\n\r\n // 扫描文件\r\n const { globby } = await import('globby');\r\n const files = await globby(contentPatterns, {\r\n cwd: rootContext,\r\n absolute: true,\r\n });\r\n\r\n if (files.length === 0) {\r\n console.warn('[UnoCSS Hybrid] No files found to scan');\r\n return resolvedOutputPath;\r\n }\r\n\r\n console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);\r\n console.log(`[UnoCSS Hybrid] Files:`, files.map(f => path.relative(rootContext, f)));\r\n\r\n // 使用 UnoCSS generator\r\n const { createGenerator } = await import('unocss');\r\n const generator = await createGenerator(config);\r\n\r\n // 读取所有文件内容并生成\r\n const allContents = files.map(file => {\r\n const content = fs.readFileSync(file, 'utf-8');\r\n return content;\r\n }).join('\\n');\r\n\r\n // 生成 CSS\r\n const result = await generator.generate(allContents);\r\n\r\n if (!result.css || result.css.trim().length === 0) {\r\n console.warn('[UnoCSS Hybrid] Generated CSS is empty');\r\n return resolvedOutputPath;\r\n }\r\n\r\n // 计算输出路径\r\n let finalOutputPath: string;\r\n if (isProd && enableHash) {\r\n // 生产环境:直接生成到 dist 目录,文件名带 hash\r\n const distDir = path.join(rootContext, 'dist');\r\n const hash = createHash('md5').update(result.css).digest('hex').substring(0, 8);\r\n finalOutputPath = path.join(distDir, `uno.${hash}.css`);\r\n currentCssPath = finalOutputPath;\r\n } else {\r\n // 开发环境:生成到插件目录的 generated 子目录,文件名固定\r\n finalOutputPath = resolvedOutputPath;\r\n currentCssPath = resolvedOutputPath;\r\n }\r\n\r\n // 确保输出目录存在\r\n const outputDir = path.dirname(finalOutputPath);\r\n if (!fs.existsSync(outputDir)) {\r\n fs.mkdirSync(outputDir, { recursive: true });\r\n }\r\n\r\n // 写入 CSS 文件\r\n fs.writeFileSync(finalOutputPath, result.css);\r\n\r\n const stats = fs.statSync(finalOutputPath);\r\n console.log(\r\n `[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`,\r\n );\r\n\r\n return finalOutputPath;\r\n } catch (err) {\r\n console.error('[UnoCSS Hybrid] Failed to generate CSS:', err);\r\n return resolvedOutputPath;\r\n }\r\n };\r\n\r\n // 生产环境:构建前生成 CSS\r\n if (isProd) {\r\n api.onBeforeBuild(async () => {\r\n await generateCSS();\r\n });\r\n }\r\n\r\n // 用于保存 CSS 版本号,强制浏览器重新加载\r\n let cssVersion = Date.now();\r\n\r\n // 自动注入:通过修改 HTML 标签来注入 CSS(不污染源码)\r\n if (autoInject) {\r\n api.modifyHTMLTags((tags) => {\r\n let cssPath: string;\r\n\r\n if (isProd && enableHash) {\r\n // 生产环境:使用带 hash 的文件名\r\n const cssFileName = path.basename(currentCssPath);\r\n cssPath = `/${cssFileName}`;\r\n } else {\r\n // 开发环境或未启用 hash:使用固定文件名\r\n cssPath = '/uno.css';\r\n }\r\n\r\n tags.headTags.unshift({\r\n tag: 'link',\r\n attrs: {\r\n rel: 'stylesheet',\r\n href: cssPath,\r\n },\r\n });\r\n\r\n console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);\r\n\r\n // 开发环境:注入热更新脚本\r\n if (!isProd) {\r\n const hotReloadScript = `\r\n (() => {\r\n window.__unocss_version__ = ${cssVersion};\r\n\r\n // 监听 WebSocket 消息\r\n const originalOnMessage = window.__whm__?.fns?.push;\r\n if (window.__whm__?.fns) {\r\n window.__whm__.fns.push(function(data) {\r\n // 监听自定义热更新事件\r\n if (data.type === 'unocss-css-update') {\r\n const { version } = data.data;\r\n if (version !== window.__unocss_version__) {\r\n window.__unocss_version__ = version;\r\n\r\n // 查找 UnoCSS 的 link 标签\r\n const link = document.querySelector('link[href*=\"/uno.css\"]');\r\n if (link) {\r\n // 更新 href 强制重新加载\r\n const href = link.getAttribute('href');\r\n if (href) {\r\n // 添加版本号作为查询参数\r\n const newHref = href.split('?')[0] + '?v=' + version;\r\n link.setAttribute('href', newHref);\r\n console.log('[UnoCSS] CSS hot updated:', newHref);\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n })();\r\n `;\r\n tags.bodyTags.push({\r\n tag: 'script',\r\n children: hotReloadScript,\r\n });\r\n console.log('[UnoCSS Hybrid] Hot reload script injected');\r\n }\r\n\r\n return tags;\r\n });\r\n }\r\n\r\n // 开发环境:配置静态文件服务和热更新\r\n if (!isProd) {\r\n\r\n api.modifyRsbuildConfig((config) => {\r\n const existingSetupMiddlewares = config.dev?.setupMiddlewares;\r\n const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares)\r\n ? existingSetupMiddlewares\r\n : existingSetupMiddlewares\r\n ? [existingSetupMiddlewares]\r\n : [];\r\n\r\n return {\r\n ...config,\r\n dev: {\r\n ...config.dev,\r\n setupMiddlewares: [\r\n ...setupMiddlewaresArray,\r\n (middlewares, devServer) => {\r\n // 保存 dev server 实例\r\n devServerInstance = devServer;\r\n\r\n // 添加自定义中间件来提供 CSS 文件\r\n middlewares.unshift(async (req, res, next) => {\r\n if (req.url?.startsWith('/uno.css')) {\r\n try {\r\n // 检查文件是否存在\r\n if (!fs.existsSync(resolvedOutputPath)) {\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('CSS file not found. Please restart the dev server to generate it.');\r\n console.warn('[UnoCSS Hybrid] CSS file not found at:', resolvedOutputPath);\r\n return;\r\n }\r\n\r\n // 设置正确的 Content-Type 和缓存控制\r\n res.setHeader('Content-Type', 'text/css; charset=utf-8');\r\n res.setHeader('Cache-Control', 'no-cache');\r\n\r\n const css = fs.readFileSync(resolvedOutputPath, 'utf-8');\r\n res.end(css);\r\n } catch (err) {\r\n console.error('[UnoCSS Hybrid] Error serving CSS:', err);\r\n res.statusCode = 500;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('Error loading CSS file. Check console for details.');\r\n }\r\n } else {\r\n next();\r\n }\r\n });\r\n },\r\n ],\r\n },\r\n };\r\n });\r\n\r\n // 启动时生成 CSS\r\n api.onBeforeStartDevServer(async () => {\r\n console.log('[UnoCSS Hybrid] Development mode: CLI generation enabled');\r\n await generateCSS();\r\n });\r\n\r\n // 合并启动后的操作\r\n api.onAfterStartDevServer(async () => {\r\n console.log('[UnoCSS Hybrid] Dev server started, CSS available at /uno.css');\r\n\r\n // Watch 模式\r\n if (watch) {\r\n try {\r\n // 动态导入 chokidar\r\n const chokidar = await import('chokidar');\r\n\r\n // 监听指定目录\r\n const watchDir = path.resolve(rootContext, watchDirectory);\r\n\r\n // 监听内容文件变化\r\n const watcher = chokidar.watch(watchDir, {\r\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\r\n ignoreInitial: true,\r\n persistent: true,\r\n });\r\n\r\n // 防抖:避免频繁重新生成\r\n let regenerateTimer: NodeJS.Timeout | null = null;\r\n\r\n watcher.on('all', async (event: string, filePath: string) => {\r\n // 检查文件扩展名\r\n const ext = path.extname(filePath);\r\n const shouldWatch = ['.html', '.js', '.ts', '.jsx', '.tsx'].includes(ext);\r\n\r\n // 监听文件添加、修改和删除\r\n if (shouldWatch && (event === 'change' || event === 'add' || event === 'unlink')) {\r\n console.log(`[UnoCSS Hybrid] File ${event}: ${path.relative(rootContext, filePath)}`);\r\n\r\n if (regenerateTimer) {\r\n clearTimeout(regenerateTimer);\r\n }\r\n\r\n regenerateTimer = setTimeout(async () => {\r\n console.log('[UnoCSS Hybrid] Regenerating CSS...');\r\n await generateCSS();\r\n\r\n // 更新版本号\r\n cssVersion = Date.now();\r\n\r\n // 触发 CSS 热更新(发送自定义事件)\r\n console.log('[UnoCSS Hybrid] Hot updating CSS in browser...');\r\n devServerInstance?.sockWrite('unocss-css-update', {\r\n version: cssVersion,\r\n path: '/uno.css',\r\n });\r\n }, 300);\r\n }\r\n });\r\n\r\n console.log('[UnoCSS Hybrid] Watch mode: enabled');\r\n } catch (err) {\r\n console.warn('[UnoCSS Hybrid] Watch mode not available:', (err as Error).message);\r\n }\r\n }\r\n });\r\n }\r\n\r\n // 构建完成后的日志\r\n api.onAfterBuild(() => {\r\n if (isProd && fs.existsSync(currentCssPath)) {\r\n const stats = fs.statSync(currentCssPath);\r\n const fileName = path.basename(currentCssPath);\r\n console.log(\r\n `[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`,\r\n );\r\n }\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default pluginUnocss;\r\n"]}
@@ -108,6 +108,7 @@ function pluginUnocss(options = {}) {
108
108
  await generateCSS();
109
109
  });
110
110
  }
111
+ let cssVersion = Date.now();
111
112
  if (autoInject) {
112
113
  api.modifyHTMLTags((tags) => {
113
114
  let cssPath;
@@ -125,6 +126,45 @@ function pluginUnocss(options = {}) {
125
126
  }
126
127
  });
127
128
  console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);
129
+ if (!isProd) {
130
+ const hotReloadScript = `
131
+ (() => {
132
+ window.__unocss_version__ = ${cssVersion};
133
+
134
+ // \u76D1\u542C WebSocket \u6D88\u606F
135
+ const originalOnMessage = window.__whm__?.fns?.push;
136
+ if (window.__whm__?.fns) {
137
+ window.__whm__.fns.push(function(data) {
138
+ // \u76D1\u542C\u81EA\u5B9A\u4E49\u70ED\u66F4\u65B0\u4E8B\u4EF6
139
+ if (data.type === 'unocss-css-update') {
140
+ const { version } = data.data;
141
+ if (version !== window.__unocss_version__) {
142
+ window.__unocss_version__ = version;
143
+
144
+ // \u67E5\u627E UnoCSS \u7684 link \u6807\u7B7E
145
+ const link = document.querySelector('link[href*="/uno.css"]');
146
+ if (link) {
147
+ // \u66F4\u65B0 href \u5F3A\u5236\u91CD\u65B0\u52A0\u8F7D
148
+ const href = link.getAttribute('href');
149
+ if (href) {
150
+ // \u6DFB\u52A0\u7248\u672C\u53F7\u4F5C\u4E3A\u67E5\u8BE2\u53C2\u6570
151
+ const newHref = href.split('?')[0] + '?v=' + version;
152
+ link.setAttribute('href', newHref);
153
+ console.log('[UnoCSS] CSS hot updated:', newHref);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ });
159
+ }
160
+ })();
161
+ `;
162
+ tags.bodyTags.push({
163
+ tag: "script",
164
+ children: hotReloadScript
165
+ });
166
+ console.log("[UnoCSS Hybrid] Hot reload script injected");
167
+ }
128
168
  return tags;
129
169
  });
130
170
  }
@@ -141,7 +181,7 @@ function pluginUnocss(options = {}) {
141
181
  (middlewares, devServer) => {
142
182
  devServerInstance = devServer;
143
183
  middlewares.unshift(async (req, res, next) => {
144
- if (req.url === "/uno.css") {
184
+ if (req.url?.startsWith("/uno.css")) {
145
185
  try {
146
186
  if (!fs.existsSync(resolvedOutputPath)) {
147
187
  res.statusCode = 404;
@@ -197,8 +237,12 @@ function pluginUnocss(options = {}) {
197
237
  regenerateTimer = setTimeout(async () => {
198
238
  console.log("[UnoCSS Hybrid] Regenerating CSS...");
199
239
  await generateCSS();
200
- console.log("[UnoCSS Hybrid] Refreshing CSS in browser...");
201
- devServerInstance?.sockWrite("static-changed", "/uno.css");
240
+ cssVersion = Date.now();
241
+ console.log("[UnoCSS Hybrid] Hot updating CSS in browser...");
242
+ devServerInstance?.sockWrite("unocss-css-update", {
243
+ version: cssVersion,
244
+ path: "/uno.css"
245
+ });
202
246
  }, 300);
203
247
  }
204
248
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","__dirname"],"mappings":"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","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"]}
1
+ {"version":3,"sources":["../plugin-unocss.ts"],"names":["__filename","__dirname"],"mappings":"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","file":"plugin-unocss.mjs","sourcesContent":["import type { RsbuildPlugin } from '@rsbuild/core';\r\nimport type { UserConfig } from 'unocss';\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport { fileURLToPath } from 'url';\r\nimport { createHash } from 'crypto';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\n\r\nexport interface PluginUnocssOptions {\r\n /** UnoCSS 配置文件路径或直接配置对象 (默认: './uno.config.ts') */\r\n unocssConfig?: string | UserConfig;\r\n\r\n /**\r\n * 生成的 CSS 文件输出路径\r\n *\r\n * 路径解析规则:\r\n * - 以 './' 开头: 相对于项目根目录 (推荐)\r\n * - 相对路径: 相对于插件目录\r\n * - 绝对路径: 直接使用\r\n * - 未配置: 默认为 'generated/uno.css' 相对于插件目录\r\n */\r\n outputPath?: string;\r\n\r\n /** 扫描的内容文件路径模式 (支持 glob 模式) */\r\n contentPatterns?: string[];\r\n\r\n /** 监听的目录路径 (用于开发环境的 watch 模式, 默认: 'src') */\r\n watchDirectory?: string;\r\n\r\n /** 是否自动在 HTML 中注入生成的 CSS link 标签 (默认: true) */\r\n autoInject?: boolean;\r\n\r\n /** 是否在开发环境启用文件监听模式 (默认: true) */\r\n watch?: boolean;\r\n\r\n /**\r\n * 是否在生产环境为 CSS 文件名添加 content hash\r\n *\r\n * 启用后, 文件名格式为 'uno.[hash].css', hash 基于 CSS 内容生成 (默认: true)\r\n */\r\n enableHash?: boolean;\r\n}\r\n\r\n/**\r\n * UnoCSS Plugin for Rsbuild\r\n *\r\n * 一个用于 Rsbuild 的 UnoCSS 插件,提供 CLI 预生成和自动注入功能.\r\n *\r\n * 特性:\r\n * - 扫描项目文件并生成独立的 CSS 文件\r\n * - 开发环境支持文件监听和热更新\r\n * - 生产环境支持 CSS 文件名 hash\r\n * - 自动在 HTML 中注入 CSS link 标签\r\n *\r\n * @param options - 插件配置选项\r\n * @returns Rsbuild 插件实例\r\n *\r\n * @example\r\n * ```ts\r\n * import { pluginUnocss } from '@ikkin/plugin-unocss';\r\n *\r\n * export default {\r\n * plugins: [\r\n * pluginUnocss({\r\n * outputPath: './src/generated/uno.css',\r\n * enableHash: true,\r\n * })\r\n * ]\r\n * };\r\n * ```\r\n */\r\nexport function pluginUnocss(\r\n options: PluginUnocssOptions = {},\r\n): RsbuildPlugin {\r\n const {\r\n unocssConfig = './uno.config.ts',\r\n outputPath = '',\r\n contentPatterns = [\r\n './src/**/*.{html,js,ts,jsx,tsx}',\r\n './index.html',\r\n ],\r\n watchDirectory = 'src',\r\n autoInject = true,\r\n watch = true,\r\n enableHash = true,\r\n } = options;\r\n\r\n return {\r\n name: 'unocss',\r\n\r\n setup(api) {\r\n const rootContext = api.context.rootPath;\r\n\r\n // 解析输出路径\r\n const pluginDir = __dirname;\r\n let resolvedOutputPath: string;\r\n\r\n if (!outputPath) {\r\n // 未配置:使用默认路径(相对于插件目录)\r\n resolvedOutputPath = path.resolve(pluginDir, './generated/uno.css');\r\n } else if (path.isAbsolute(outputPath)) {\r\n // 绝对路径:直接使用\r\n resolvedOutputPath = outputPath;\r\n } else if (outputPath.startsWith('./')) {\r\n // 以 ./ 开头:相对于项目根目录(推荐,更明确)\r\n resolvedOutputPath = path.resolve(rootContext, outputPath);\r\n } else {\r\n // 相对路径(不带 ./):相对于插件目录(更简洁)\r\n resolvedOutputPath = path.resolve(pluginDir, outputPath);\r\n }\r\n\r\n // 用于保存当前生成的 CSS 文件路径(可能包含 hash)\r\n let currentCssPath = resolvedOutputPath;\r\n\r\n // 用于保存 dev server 实例,以便在文件变化时触发刷新\r\n let devServerInstance: any = null;\r\n\r\n // 通过环境变量判断是否是生产环境\r\n const isProd = process.env.NODE_ENV === 'production';\r\n\r\n // 读取 UnoCSS 配置\r\n const loadConfig = async (): Promise<UserConfig> => {\r\n if (typeof unocssConfig === 'string') {\r\n const configPath = path.resolve(rootContext, unocssConfig);\r\n try {\r\n const configModule = await import(\r\n `file:///${configPath.replace(/\\\\/g, '/')}`\r\n );\r\n return configModule.default || configModule;\r\n } catch (err) {\r\n console.warn(\r\n `[UnoCSS Hybrid] Failed to load config from ${configPath}, using default config`,\r\n );\r\n return {};\r\n }\r\n }\r\n return unocssConfig;\r\n };\r\n\r\n // 生成 UnoCSS CSS\r\n const generateCSS = async (): Promise<string> => {\r\n console.log('[UnoCSS Hybrid] Generating CSS...');\r\n\r\n try {\r\n const config = await loadConfig();\r\n\r\n // 扫描文件\r\n const { globby } = await import('globby');\r\n const files = await globby(contentPatterns, {\r\n cwd: rootContext,\r\n absolute: true,\r\n });\r\n\r\n if (files.length === 0) {\r\n console.warn('[UnoCSS Hybrid] No files found to scan');\r\n return resolvedOutputPath;\r\n }\r\n\r\n console.log(`[UnoCSS Hybrid] Found ${files.length} files to scan`);\r\n console.log(`[UnoCSS Hybrid] Files:`, files.map(f => path.relative(rootContext, f)));\r\n\r\n // 使用 UnoCSS generator\r\n const { createGenerator } = await import('unocss');\r\n const generator = await createGenerator(config);\r\n\r\n // 读取所有文件内容并生成\r\n const allContents = files.map(file => {\r\n const content = fs.readFileSync(file, 'utf-8');\r\n return content;\r\n }).join('\\n');\r\n\r\n // 生成 CSS\r\n const result = await generator.generate(allContents);\r\n\r\n if (!result.css || result.css.trim().length === 0) {\r\n console.warn('[UnoCSS Hybrid] Generated CSS is empty');\r\n return resolvedOutputPath;\r\n }\r\n\r\n // 计算输出路径\r\n let finalOutputPath: string;\r\n if (isProd && enableHash) {\r\n // 生产环境:直接生成到 dist 目录,文件名带 hash\r\n const distDir = path.join(rootContext, 'dist');\r\n const hash = createHash('md5').update(result.css).digest('hex').substring(0, 8);\r\n finalOutputPath = path.join(distDir, `uno.${hash}.css`);\r\n currentCssPath = finalOutputPath;\r\n } else {\r\n // 开发环境:生成到插件目录的 generated 子目录,文件名固定\r\n finalOutputPath = resolvedOutputPath;\r\n currentCssPath = resolvedOutputPath;\r\n }\r\n\r\n // 确保输出目录存在\r\n const outputDir = path.dirname(finalOutputPath);\r\n if (!fs.existsSync(outputDir)) {\r\n fs.mkdirSync(outputDir, { recursive: true });\r\n }\r\n\r\n // 写入 CSS 文件\r\n fs.writeFileSync(finalOutputPath, result.css);\r\n\r\n const stats = fs.statSync(finalOutputPath);\r\n console.log(\r\n `[UnoCSS Hybrid] CSS generated: ${finalOutputPath} (${(stats.size / 1024).toFixed(2)} KB)`,\r\n );\r\n\r\n return finalOutputPath;\r\n } catch (err) {\r\n console.error('[UnoCSS Hybrid] Failed to generate CSS:', err);\r\n return resolvedOutputPath;\r\n }\r\n };\r\n\r\n // 生产环境:构建前生成 CSS\r\n if (isProd) {\r\n api.onBeforeBuild(async () => {\r\n await generateCSS();\r\n });\r\n }\r\n\r\n // 用于保存 CSS 版本号,强制浏览器重新加载\r\n let cssVersion = Date.now();\r\n\r\n // 自动注入:通过修改 HTML 标签来注入 CSS(不污染源码)\r\n if (autoInject) {\r\n api.modifyHTMLTags((tags) => {\r\n let cssPath: string;\r\n\r\n if (isProd && enableHash) {\r\n // 生产环境:使用带 hash 的文件名\r\n const cssFileName = path.basename(currentCssPath);\r\n cssPath = `/${cssFileName}`;\r\n } else {\r\n // 开发环境或未启用 hash:使用固定文件名\r\n cssPath = '/uno.css';\r\n }\r\n\r\n tags.headTags.unshift({\r\n tag: 'link',\r\n attrs: {\r\n rel: 'stylesheet',\r\n href: cssPath,\r\n },\r\n });\r\n\r\n console.log(`[UnoCSS Hybrid] Auto-injected CSS link: ${cssPath}`);\r\n\r\n // 开发环境:注入热更新脚本\r\n if (!isProd) {\r\n const hotReloadScript = `\r\n (() => {\r\n window.__unocss_version__ = ${cssVersion};\r\n\r\n // 监听 WebSocket 消息\r\n const originalOnMessage = window.__whm__?.fns?.push;\r\n if (window.__whm__?.fns) {\r\n window.__whm__.fns.push(function(data) {\r\n // 监听自定义热更新事件\r\n if (data.type === 'unocss-css-update') {\r\n const { version } = data.data;\r\n if (version !== window.__unocss_version__) {\r\n window.__unocss_version__ = version;\r\n\r\n // 查找 UnoCSS 的 link 标签\r\n const link = document.querySelector('link[href*=\"/uno.css\"]');\r\n if (link) {\r\n // 更新 href 强制重新加载\r\n const href = link.getAttribute('href');\r\n if (href) {\r\n // 添加版本号作为查询参数\r\n const newHref = href.split('?')[0] + '?v=' + version;\r\n link.setAttribute('href', newHref);\r\n console.log('[UnoCSS] CSS hot updated:', newHref);\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n })();\r\n `;\r\n tags.bodyTags.push({\r\n tag: 'script',\r\n children: hotReloadScript,\r\n });\r\n console.log('[UnoCSS Hybrid] Hot reload script injected');\r\n }\r\n\r\n return tags;\r\n });\r\n }\r\n\r\n // 开发环境:配置静态文件服务和热更新\r\n if (!isProd) {\r\n\r\n api.modifyRsbuildConfig((config) => {\r\n const existingSetupMiddlewares = config.dev?.setupMiddlewares;\r\n const setupMiddlewaresArray = Array.isArray(existingSetupMiddlewares)\r\n ? existingSetupMiddlewares\r\n : existingSetupMiddlewares\r\n ? [existingSetupMiddlewares]\r\n : [];\r\n\r\n return {\r\n ...config,\r\n dev: {\r\n ...config.dev,\r\n setupMiddlewares: [\r\n ...setupMiddlewaresArray,\r\n (middlewares, devServer) => {\r\n // 保存 dev server 实例\r\n devServerInstance = devServer;\r\n\r\n // 添加自定义中间件来提供 CSS 文件\r\n middlewares.unshift(async (req, res, next) => {\r\n if (req.url?.startsWith('/uno.css')) {\r\n try {\r\n // 检查文件是否存在\r\n if (!fs.existsSync(resolvedOutputPath)) {\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('CSS file not found. Please restart the dev server to generate it.');\r\n console.warn('[UnoCSS Hybrid] CSS file not found at:', resolvedOutputPath);\r\n return;\r\n }\r\n\r\n // 设置正确的 Content-Type 和缓存控制\r\n res.setHeader('Content-Type', 'text/css; charset=utf-8');\r\n res.setHeader('Cache-Control', 'no-cache');\r\n\r\n const css = fs.readFileSync(resolvedOutputPath, 'utf-8');\r\n res.end(css);\r\n } catch (err) {\r\n console.error('[UnoCSS Hybrid] Error serving CSS:', err);\r\n res.statusCode = 500;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('Error loading CSS file. Check console for details.');\r\n }\r\n } else {\r\n next();\r\n }\r\n });\r\n },\r\n ],\r\n },\r\n };\r\n });\r\n\r\n // 启动时生成 CSS\r\n api.onBeforeStartDevServer(async () => {\r\n console.log('[UnoCSS Hybrid] Development mode: CLI generation enabled');\r\n await generateCSS();\r\n });\r\n\r\n // 合并启动后的操作\r\n api.onAfterStartDevServer(async () => {\r\n console.log('[UnoCSS Hybrid] Dev server started, CSS available at /uno.css');\r\n\r\n // Watch 模式\r\n if (watch) {\r\n try {\r\n // 动态导入 chokidar\r\n const chokidar = await import('chokidar');\r\n\r\n // 监听指定目录\r\n const watchDir = path.resolve(rootContext, watchDirectory);\r\n\r\n // 监听内容文件变化\r\n const watcher = chokidar.watch(watchDir, {\r\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\r\n ignoreInitial: true,\r\n persistent: true,\r\n });\r\n\r\n // 防抖:避免频繁重新生成\r\n let regenerateTimer: NodeJS.Timeout | null = null;\r\n\r\n watcher.on('all', async (event: string, filePath: string) => {\r\n // 检查文件扩展名\r\n const ext = path.extname(filePath);\r\n const shouldWatch = ['.html', '.js', '.ts', '.jsx', '.tsx'].includes(ext);\r\n\r\n // 监听文件添加、修改和删除\r\n if (shouldWatch && (event === 'change' || event === 'add' || event === 'unlink')) {\r\n console.log(`[UnoCSS Hybrid] File ${event}: ${path.relative(rootContext, filePath)}`);\r\n\r\n if (regenerateTimer) {\r\n clearTimeout(regenerateTimer);\r\n }\r\n\r\n regenerateTimer = setTimeout(async () => {\r\n console.log('[UnoCSS Hybrid] Regenerating CSS...');\r\n await generateCSS();\r\n\r\n // 更新版本号\r\n cssVersion = Date.now();\r\n\r\n // 触发 CSS 热更新(发送自定义事件)\r\n console.log('[UnoCSS Hybrid] Hot updating CSS in browser...');\r\n devServerInstance?.sockWrite('unocss-css-update', {\r\n version: cssVersion,\r\n path: '/uno.css',\r\n });\r\n }, 300);\r\n }\r\n });\r\n\r\n console.log('[UnoCSS Hybrid] Watch mode: enabled');\r\n } catch (err) {\r\n console.warn('[UnoCSS Hybrid] Watch mode not available:', (err as Error).message);\r\n }\r\n }\r\n });\r\n }\r\n\r\n // 构建完成后的日志\r\n api.onAfterBuild(() => {\r\n if (isProd && fs.existsSync(currentCssPath)) {\r\n const stats = fs.statSync(currentCssPath);\r\n const fileName = path.basename(currentCssPath);\r\n console.log(\r\n `[UnoCSS Hybrid] Final CSS: ${fileName} (${(stats.size / 1024).toFixed(2)} KB)`,\r\n );\r\n }\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport default pluginUnocss;\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikkin/plugin-unocss",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "UnoCSS plugin for Rsbuild with CLI pre-generation and automatic injection",
5
5
  "main": "./dist/plugin-unocss.js",
6
6
  "module": "./dist/plugin-unocss.mjs",
@@ -40,11 +40,11 @@
40
40
  "license": "MIT",
41
41
  "repository": {
42
42
  "type": "git",
43
- "url": "https://github.com/ikkin/plugin-unocss.git"
43
+ "url": "https://gitcode.com/lenkaset/test-uno.git"
44
44
  },
45
- "homepage": "https://github.com/ikkin/plugin-unocss#readme",
45
+ "homepage": "https://gitcode.com/lenkaset/test-uno#readme",
46
46
  "bugs": {
47
- "url": "https://github.com/ikkin/plugin-unocss/issues"
47
+ "url": "https://gitcode.com/lenkaset/test-uno/issues"
48
48
  },
49
49
  "sideEffects": false,
50
50
  "peerDependencies": {