dsh-taiwind 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -33,7 +33,7 @@ flowchart LR
33
33
 
34
34
  - **CSS-first**:保留未编译的 `main.css`,支持 `@theme`、`@utility`、`@custom-variant`、`@apply`、`@source inline(...)`。
35
35
  - **官方编译器**:Tailwind 扫描器提取候选类,统一编译;不加载 Preflight,不重置宿主界面。
36
- - **单一入口**:首屏注入 `<head>`,客户端接管同一个 `<style data-plugin="dsh-taiwind" data-plugin-css="utilities">`。
36
+ - **单一入口**:首屏注入 `<head>`,客户端接管同一个 `<style data-plugin="dsh-taiwind" data-plugin-css="utilities">`;编译就绪前先输出阻塞式 `<link>`,接管后移除,页面不会先亮一帧无样式内容。
37
37
  - **热更新**:插件安装/卸载/启停,或客户端产物、`main.css` 改动后都会自动重新编译;已打开的页面无需刷新即可换上新样式,也不必重启宿主。
38
38
  - **条件请求**:带 ETag 的 CSS 接口,命中返回 304;内容没变就不读产物、不跑 Tailwind。
39
39
  - **完整清理**:停用移除路由、监听、定时器与客户端样式,并取消进行中的请求。
@@ -43,7 +43,7 @@ flowchart LR
43
43
  ### 1. 安装
44
44
 
45
45
  ```sh
46
- pnpm add dsh-taiwind
46
+ pnpm add dsh-taiwind@latest
47
47
  ```
48
48
 
49
49
  在业务插件的 `cordis.patch.yml` 里插入它(连同自身行):
@@ -90,8 +90,6 @@ pnpm add dsh-taiwind
90
90
 
91
91
  🚀 客户端直接使用 taiwind 类名,例如 `bg-notes-accent w-notes-panel notes-compact` 即可。
92
92
 
93
- 没有声明 `dsh.taiwind` 的包不参与样式编译;声明了但路径不是相对 `.css`、文件不存在或指向包外都会明确报错,不会去猜别的 `main.css`。
94
-
95
93
  ### 3. 发布时携带样式文件
96
94
 
97
95
  在 `package.json` 中添加 `files` 字段,发布时需要携带入口 CSS 及它引用的相对 CSS:
@@ -130,14 +128,15 @@ CSS 入口存在时**不会自动加载根目录 JS 配置**,需要时在 CSS
130
128
 
131
129
  | 项目 | 说明 |
132
130
  | --- | --- |
133
- | 发布 | 原始 CSS 入口及其相对导入必须进 npm 包;只发 `dist` 时一并复制,不要用展开后的构建 CSS 代替 |
134
- | 不支持 | TypeScript 配置(只认 `.js` / `.mjs` / `.cjs`)、npm CSS 包导入、路径别名、远程 CSS、`@plugin`、文件路径形式的 `@source`、自定义 `source(...)` 扫描目录、跨包 CSS 导入 |
135
- | 冲突检测 | 自定义 token、同名 `@utility` / `@custom-variant` 定义不一致会报错并指包名;非完整 CSS 语义等价判断 |
136
- | 主题合并 | 遵循 Tailwind 4:同 token 的 CSS 定义优先;所有插件共享全局主题,不按插件隔离 |
131
+ | 发布 | 原始 CSS 入口及其相对导入必须进 npm 包; |
132
+ | 不支持 | TypeScript 配置、npm CSS 包导入、路径别名、远程 CSS、`@plugin`、文件路径形式的 `@source`、自定义 `source(...)` 扫描目录、跨包 CSS 导入 |
133
+ | 冲突检测 | CSS token、同名 `@utility` / `@custom-variant` 定义不一致时自动合并,并输出包含冲突项和双方包名的 warn 日志;同一冲突不会在每次轮询时重复刷屏 |
134
+ | 主题合并 | 按插件 ID、入口路径排序后交由 Tailwind 4 合并,CSS 定义优先于 JS 配置,同名 CSS 定义遵循后者覆盖;所有插件共享全局主题,不按插件隔离 |
137
135
  | 自定义 CSS | 一起输出,但不自动限定作用域、去重或改写资源 URL;请用插件前缀选择器和可直接访问的资源地址 |
138
136
  | 动态值 | 适合 CSS 变量或内联样式,不要拼接不完整类名 |
139
- | 共享编译器成本 | 需安装 Tailwind、Oxide 原生扫描器等宿主依赖;有磁盘占用与宿主 CPU 开销 |
140
- | 共享不是隔离 | 共用主题与全局选项,冲突可能阻止整份样式更新;不适合要求完全独立 Tailwind 配置的插件 |
137
+ | 共享编译器成本 | 需安装 Tailwind、Oxide 原生扫描器等宿主依赖;有磁盘占用(约 8mb~10mb)与宿主 CPU 开销 |
138
+ | 共享不是隔离 | 共用主题与全局选项;CSS 定义冲突只告警,非法配置与不兼容的 JS 全局选项仍会阻止更新;不适合要求完全独立 Tailwind 配置的插件 |
139
+ | 首屏时序 | 编译未就绪时页面通过阻塞式 `<link>` 等样式,最多 15 秒;超时才放弃等待并显示无样式内容 |
141
140
 
142
141
  ## 🛠️ 开发与贡献
143
142
 
package/dist/client.cjs CHANGED
@@ -1,4 +1,4 @@
1
1
  window.__ModuleLoader__.load({id:"dsh-taiwind",factory:(require)=>{var module={exports:{}};var exports=module.exports;
2
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=`dsh-taiwind`;function t(){let t=document.head.querySelector(`[data-plugin="dsh-taiwind"][data-plugin-css="utilities"]`),n=t??document.createElement(`style`);n.dataset.plugin=e,n.dataset.pluginCss=`utilities`,t||document.head.append(n);let r=new AbortController,i=``,a=!1,o,s=``,c=async()=>{let t=new AbortController,l=setTimeout(()=>t.abort(),15e3),u=()=>t.abort();r.signal.addEventListener(`abort`,u,{once:!0});try{let e=await fetch(new URL(`plugins/taiwind.css`,document.baseURI),{credentials:`same-origin`,cache:`no-cache`,headers:i?{"If-None-Match":i}:{},signal:t.signal});if(e.status!==304){if(!e.ok)throw Error(`Stylesheet request failed (${e.status})`);let t=await e.text();a||(n.textContent!==t&&(n.textContent=t),i=e.headers.get(`ETag`)??``)}s=``}catch(t){if(!a){let n=t instanceof Error?t.message:String(t);s!==n&&(s=n,console.warn(`${e}: ${n}; keeping previous stylesheet`))}}finally{clearTimeout(l),r.signal.removeEventListener(`abort`,u),a||(o=setTimeout(()=>void c(),2e3))}};return c(),()=>{a=!0,r.abort(),clearTimeout(o),n.remove()}}function n(e){e.effect(t)}exports.apply=n;
2
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=`dsh-taiwind`;function t(){let t=document.head.querySelector(`[data-plugin="dsh-taiwind"][data-plugin-css="utilities"]`),n=t??document.createElement(`style`);n.dataset.plugin=e,n.dataset.pluginCss=`utilities`,t||document.head.append(n);let r=document.head.querySelector(`link[data-plugin="dsh-taiwind"][data-plugin-css="utilities"]`),i=new AbortController,a=``,o=!1,s,c=``,l=async()=>{let t=new AbortController,u=setTimeout(()=>t.abort(),15e3),d=()=>t.abort();i.signal.addEventListener(`abort`,d,{once:!0});try{let e=await fetch(new URL(`plugins/taiwind.css`,document.baseURI),{credentials:`same-origin`,cache:`no-cache`,headers:a?{"If-None-Match":a}:{},signal:t.signal});if(e.status!==304){if(!e.ok)throw Error(`Stylesheet request failed (${e.status})`);let t=await e.text();o||(n.textContent!==t&&(n.textContent=t),r?.remove(),a=e.headers.get(`ETag`)??``)}c=``}catch(t){if(!o){let n=t instanceof Error?t.message:String(t);c!==n&&(c=n,console.warn(`${e}: ${n}; keeping previous stylesheet`))}}finally{clearTimeout(u),i.signal.removeEventListener(`abort`,d),o||(s=setTimeout(()=>void l(),2e3))}};return l(),()=>{o=!0,i.abort(),clearTimeout(s),n.remove(),r?.remove()}}function n(e){e.effect(t)}exports.apply=n;
3
3
  return module.exports;}});
4
4
  //# sourceMappingURL=client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","names":[],"sources":["../src/constants.ts","../src/client/styles.ts","../src/client/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'dsh-taiwind'\nexport const STYLESHEET_PATH = 'plugins/taiwind.css'\nexport const STYLE_SELECTOR = '[data-plugin=\"dsh-taiwind\"][data-plugin-css=\"utilities\"]'\nexport const POLL_INTERVAL_MS = 2000\n","import { PLUGIN_ID, POLL_INTERVAL_MS, STYLE_SELECTOR, STYLESHEET_PATH } from '../constants'\n\nexport function mountStyles(): () => void {\n const existing = document.head.querySelector<HTMLStyleElement>(STYLE_SELECTOR)\n const style = existing ?? document.createElement('style')\n style.dataset.plugin = PLUGIN_ID\n style.dataset.pluginCss = 'utilities'\n if (!existing)\n document.head.append(style)\n\n const controller = new AbortController()\n let etag = ''\n let disposed = false\n let timer: ReturnType<typeof setTimeout> | undefined\n let lastError = ''\n\n const update = async (): Promise<void> => {\n const request = new AbortController()\n const timeout = setTimeout(() => request.abort(), 15000)\n const abort = (): void => request.abort()\n controller.signal.addEventListener('abort', abort, { once: true })\n try {\n const response = await fetch(new URL(STYLESHEET_PATH, document.baseURI), {\n credentials: 'same-origin',\n cache: 'no-cache',\n headers: etag ? { 'If-None-Match': etag } : {},\n signal: request.signal,\n })\n if (response.status !== 304) {\n if (!response.ok)\n throw new Error(`Stylesheet request failed (${response.status})`)\n const css = await response.text()\n if (!disposed) {\n if (style.textContent !== css)\n style.textContent = css\n etag = response.headers.get('ETag') ?? ''\n }\n }\n lastError = ''\n }\n catch (error) {\n if (!disposed) {\n const message = error instanceof Error ? error.message : String(error)\n if (lastError !== message) {\n lastError = message\n console.warn(`${PLUGIN_ID}: ${message}; keeping previous stylesheet`)\n }\n }\n }\n finally {\n clearTimeout(timeout)\n controller.signal.removeEventListener('abort', abort)\n if (!disposed)\n timer = setTimeout(() => void update(), POLL_INTERVAL_MS)\n }\n }\n void update()\n\n return () => {\n disposed = true\n controller.abort()\n clearTimeout(timer)\n style.remove()\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { mountStyles } from './styles'\n\nexport function apply(ctx: Context): void {\n ctx.effect(mountStyles)\n}\n"],"mappings":";mEAAA,MAAa,EAAY,cCEzB,SAAgB,GAA0B,CACxC,IAAM,EAAW,SAAS,KAAK,cAAgC,0DAAc,EACvE,EAAQ,GAAY,SAAS,cAAc,OAAO,EACxD,EAAM,QAAQ,OAAS,EACvB,EAAM,QAAQ,UAAY,YACrB,GACH,SAAS,KAAK,OAAO,CAAK,EAE5B,IAAM,EAAa,IAAI,gBACnB,EAAO,GACP,EAAW,GACX,EACA,EAAY,GAEV,EAAS,SAA2B,CACxC,IAAM,EAAU,IAAI,gBACd,EAAU,eAAiB,EAAQ,MAAM,EAAG,IAAK,EACjD,MAAoB,EAAQ,MAAM,EACxC,EAAW,OAAO,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EACjE,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,IAAI,IAAI,sBAAiB,SAAS,OAAO,EAAG,CACvE,YAAa,cACb,MAAO,WACP,QAAS,EAAO,CAAE,gBAAiB,CAAK,EAAI,CAAC,EAC7C,OAAQ,EAAQ,MAClB,CAAC,EACD,GAAI,EAAS,SAAW,IAAK,CAC3B,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,8BAA8B,EAAS,OAAO,EAAE,EAClE,IAAM,EAAM,MAAM,EAAS,KAAK,EAC3B,IACC,EAAM,cAAgB,IACxB,EAAM,YAAc,GACtB,EAAO,EAAS,QAAQ,IAAI,MAAM,GAAK,GAE3C,CACA,EAAY,EACd,OACO,EAAO,CACZ,GAAI,CAAC,EAAU,CACb,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACjE,IAAc,IAChB,EAAY,EACZ,QAAQ,KAAK,GAAG,EAAU,IAAI,EAAQ,8BAA8B,EAExE,CACF,QACQ,CACN,aAAa,CAAO,EACpB,EAAW,OAAO,oBAAoB,QAAS,CAAK,EAC/C,IACH,EAAQ,eAAiB,KAAK,EAAO,EAAG,GAAgB,EAC5D,CACF,EAGA,OAFA,EAAY,MAEC,CACX,EAAW,GACX,EAAW,MAAM,EACjB,aAAa,CAAK,EAClB,EAAM,OAAO,CACf,CACF,CC7DA,SAAgB,EAAM,EAAoB,CACxC,EAAI,OAAO,CAAW,CACxB"}
1
+ {"version":3,"file":"client.cjs","names":[],"sources":["../src/constants.ts","../src/client/styles.ts","../src/client/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'dsh-taiwind'\nexport const STYLESHEET_PATH = 'plugins/taiwind.css'\nexport const STYLE_SELECTOR = '[data-plugin=\"dsh-taiwind\"][data-plugin-css=\"utilities\"]'\nexport const LINK_SELECTOR = 'link[data-plugin=\"dsh-taiwind\"][data-plugin-css=\"utilities\"]'\nexport const POLL_INTERVAL_MS = 2000\n","import { LINK_SELECTOR, PLUGIN_ID, POLL_INTERVAL_MS, STYLE_SELECTOR, STYLESHEET_PATH } from '../constants'\n\nexport function mountStyles(): () => void {\n const existing = document.head.querySelector<HTMLStyleElement>(STYLE_SELECTOR)\n const style = existing ?? document.createElement('style')\n style.dataset.plugin = PLUGIN_ID\n style.dataset.pluginCss = 'utilities'\n if (!existing)\n document.head.append(style)\n // 首屏阻塞式 link 在样式接管后移除,避免同一份规则加载两遍。\n const preloaded = document.head.querySelector<HTMLLinkElement>(LINK_SELECTOR)\n\n const controller = new AbortController()\n let etag = ''\n let disposed = false\n let timer: ReturnType<typeof setTimeout> | undefined\n let lastError = ''\n\n const update = async (): Promise<void> => {\n const request = new AbortController()\n const timeout = setTimeout(() => request.abort(), 15000)\n const abort = (): void => request.abort()\n controller.signal.addEventListener('abort', abort, { once: true })\n try {\n const response = await fetch(new URL(STYLESHEET_PATH, document.baseURI), {\n credentials: 'same-origin',\n cache: 'no-cache',\n headers: etag ? { 'If-None-Match': etag } : {},\n signal: request.signal,\n })\n if (response.status !== 304) {\n if (!response.ok)\n throw new Error(`Stylesheet request failed (${response.status})`)\n const css = await response.text()\n if (!disposed) {\n if (style.textContent !== css)\n style.textContent = css\n preloaded?.remove()\n etag = response.headers.get('ETag') ?? ''\n }\n }\n lastError = ''\n }\n catch (error) {\n if (!disposed) {\n const message = error instanceof Error ? error.message : String(error)\n if (lastError !== message) {\n lastError = message\n console.warn(`${PLUGIN_ID}: ${message}; keeping previous stylesheet`)\n }\n }\n }\n finally {\n clearTimeout(timeout)\n controller.signal.removeEventListener('abort', abort)\n if (!disposed)\n timer = setTimeout(() => void update(), POLL_INTERVAL_MS)\n }\n }\n void update()\n\n return () => {\n disposed = true\n controller.abort()\n clearTimeout(timer)\n style.remove()\n preloaded?.remove()\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { mountStyles } from './styles'\n\nexport function apply(ctx: Context): void {\n ctx.effect(mountStyles)\n}\n"],"mappings":";mEAAA,MAAa,EAAY,cCEzB,SAAgB,GAA0B,CACxC,IAAM,EAAW,SAAS,KAAK,cAAgC,0DAAc,EACvE,EAAQ,GAAY,SAAS,cAAc,OAAO,EACxD,EAAM,QAAQ,OAAS,EACvB,EAAM,QAAQ,UAAY,YACrB,GACH,SAAS,KAAK,OAAO,CAAK,EAE5B,IAAM,EAAY,SAAS,KAAK,cAA+B,8DAAa,EAEtE,EAAa,IAAI,gBACnB,EAAO,GACP,EAAW,GACX,EACA,EAAY,GAEV,EAAS,SAA2B,CACxC,IAAM,EAAU,IAAI,gBACd,EAAU,eAAiB,EAAQ,MAAM,EAAG,IAAK,EACjD,MAAoB,EAAQ,MAAM,EACxC,EAAW,OAAO,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EACjE,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,IAAI,IAAI,sBAAiB,SAAS,OAAO,EAAG,CACvE,YAAa,cACb,MAAO,WACP,QAAS,EAAO,CAAE,gBAAiB,CAAK,EAAI,CAAC,EAC7C,OAAQ,EAAQ,MAClB,CAAC,EACD,GAAI,EAAS,SAAW,IAAK,CAC3B,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,8BAA8B,EAAS,OAAO,EAAE,EAClE,IAAM,EAAM,MAAM,EAAS,KAAK,EAC3B,IACC,EAAM,cAAgB,IACxB,EAAM,YAAc,GACtB,GAAW,OAAO,EAClB,EAAO,EAAS,QAAQ,IAAI,MAAM,GAAK,GAE3C,CACA,EAAY,EACd,OACO,EAAO,CACZ,GAAI,CAAC,EAAU,CACb,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACjE,IAAc,IAChB,EAAY,EACZ,QAAQ,KAAK,GAAG,EAAU,IAAI,EAAQ,8BAA8B,EAExE,CACF,QACQ,CACN,aAAa,CAAO,EACpB,EAAW,OAAO,oBAAoB,QAAS,CAAK,EAC/C,IACH,EAAQ,eAAiB,KAAK,EAAO,EAAG,GAAgB,EAC5D,CACF,EAGA,OAFA,EAAY,MAEC,CACX,EAAW,GACX,EAAW,MAAM,EACjB,aAAa,CAAK,EAClB,EAAM,OAAO,EACb,GAAW,OAAO,CACpB,CACF,CCjEA,SAAgB,EAAM,EAAoB,CACxC,EAAI,OAAO,CAAW,CACxB"}
package/dist/index.js CHANGED
@@ -149,7 +149,7 @@ async function cssEntry(root, owner) {
149
149
  if (!await stat(path).then((info) => info.isFile(), () => false)) throw new Error(`${owner}: dsh.taiwind entry not found: ${entry}`);
150
150
  return path;
151
151
  }
152
- async function compilePlugins(entries) {
152
+ async function compilePlugins(entries, onWarning) {
153
153
  const hash = createHash("sha256");
154
154
  const bundleFiles = [];
155
155
  const extend = Object.create(null);
@@ -160,6 +160,7 @@ async function compilePlugins(entries) {
160
160
  const stylesheets = /* @__PURE__ */ new Map();
161
161
  const cssImports = [];
162
162
  const cssDefinitions = /* @__PURE__ */ new Map();
163
+ const warnings = /* @__PURE__ */ new Set();
163
164
  const configsSeen = /* @__PURE__ */ new Set();
164
165
  const setGlobal = (key, value, owner) => {
165
166
  if (Object.hasOwn(merged, key) && canonical(merged[key]) !== canonical(value)) throw new Error(`Tailwind global configuration conflict at ${key}: ${owners.get(key)} and ${owner}`);
@@ -196,7 +197,7 @@ async function compilePlugins(entries) {
196
197
  };
197
198
  const checkDefinition = (key, value, owner) => {
198
199
  const previous = cssDefinitions.get(key);
199
- if (previous && previous.owner !== owner && previous.value !== value) throw new Error(`Tailwind CSS conflict at ${key}: ${previous.owner} and ${owner}`);
200
+ if (previous && previous.owner !== owner && previous.value !== value) warnings.add(`Tailwind CSS conflict at ${key}: ${previous.owner} and ${owner}; merging in plugin order`);
200
201
  cssDefinitions.set(key, {
201
202
  value,
202
203
  owner
@@ -293,6 +294,7 @@ async function compilePlugins(entries) {
293
294
  const utilities = await readFile(new URL(import.meta.resolve("tailwindcss/utilities.css")), "utf8");
294
295
  hash.update(JSON.stringify([theme, utilities]));
295
296
  const digest = hash.digest("hex");
297
+ for (const warning of warnings) onWarning?.(warning);
296
298
  if (cached?.signature === digest) return cached.css;
297
299
  const sources = [];
298
300
  for (const file of bundleFiles) sources.push({
@@ -354,20 +356,24 @@ async function apply(ctx) {
354
356
  pending = (async () => {
355
357
  while (true) {
356
358
  const current = generation;
357
- const compiled = await compilePlugins(ctx.clientModules.graph().entries.map(({ id }) => {
359
+ const entries = ctx.clientModules.graph().entries.map(({ id }) => {
358
360
  const path = ctx.clientModules.clientPath(id);
359
361
  if (!path) throw new Error(`Missing client bundle: ${id}`);
360
362
  return {
361
363
  id,
362
364
  path
363
365
  };
364
- }));
366
+ });
367
+ const warnings = [];
368
+ const compiled = await compilePlugins(entries, (message) => warnings.push(message));
365
369
  if (disposed) return;
366
370
  if (generation !== current) continue;
367
371
  css = compiled;
368
372
  etag = `"${createHash("sha256").update(css).digest("hex")}"`;
369
373
  failed = false;
370
- lastError = "";
374
+ const warning = warnings.join("\n");
375
+ if (warning && warning !== lastError) ctx.logger.warn(`${PLUGIN_ID}: ${warning}`);
376
+ lastError = warning;
371
377
  break;
372
378
  }
373
379
  })().finally(() => {
@@ -399,7 +405,7 @@ async function apply(ctx) {
399
405
  ctx.effect(() => ctx.webServer.register({
400
406
  kind: "exact",
401
407
  path: `/${STYLESHEET_PATH}`,
402
- handler: (req, res) => {
408
+ handler: async (req, res) => {
403
409
  const rejection = ctx.connection.requestRejection(req);
404
410
  if (rejection) {
405
411
  res.writeHead(rejection);
@@ -413,6 +419,7 @@ async function apply(ctx) {
413
419
  }
414
420
  res.setHeader("Cache-Control", "private, no-cache");
415
421
  res.setHeader("X-Content-Type-Options", "nosniff");
422
+ if (failed && pending) await pending.catch(() => {});
416
423
  if (failed) {
417
424
  res.writeHead(503, { "Retry-After": "2" });
418
425
  res.end();
@@ -433,7 +440,7 @@ async function apply(ctx) {
433
440
  rows.push({
434
441
  kind: "html",
435
442
  placement: "head",
436
- html: `<style data-plugin="${PLUGIN_ID}" data-plugin-css="utilities">${css.replace(/<\/style/gi, "<\\/style")}</style>`
443
+ html: css ? `<style data-plugin="${PLUGIN_ID}" data-plugin-css="utilities">${css.replace(/<\/style/gi, "<\\/style")}</style>` : `<link rel="stylesheet" data-plugin="${PLUGIN_ID}" data-plugin-css="utilities" href="${STYLESHEET_PATH}">`
437
444
  });
438
445
  });
439
446
  ctx.effect(() => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-taiwind",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.3.2",
5
5
  "description": "One shared Tailwind stylesheet for DSH plugins with per-plugin configuration",
6
6
  "author": "Hairy <wwu710632@gmail.com>",
7
7
  "license": "MIT",