From 4da2b86b836790607ac5ddc5837bdf716bbb0388 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 13:25:31 +0800 Subject: [PATCH 01/14] feat!: upgrade Babel 8 and default packages to ESM --- .changeset/babel-eight-module-packages.md | 15 ++ .../apps-generator-mode/compare/report.json | 16 +- .../apps-generator-mode/compare/report.md | 16 +- .../compare/report.zh-CN.md | 16 +- .../uni-app-vite-tailwindcss-v4/README.md | 4 +- .../artifacts/pages__index__index.css | 2 +- .../uni-app-vite-tailwindcss-v4/README.md | 4 +- .../artifacts/pages__index__index.css | 2 +- .../taro-vite-react-tailwindcss-v4/README.md | 10 +- .../artifacts/css__index.1.css | 2 +- .../artifacts/css__index.2.css | 2 +- .../artifacts/css__index.3.css | 2 +- .../artifacts/css__index.4.css | 2 +- .../taro-vite-vue3-tailwindcss-v4/README.md | 8 +- .../artifacts/css__index.1.css | 2 +- .../artifacts/css__index.2.css | 2 +- .../artifacts/css__index.3.css | 2 +- .../uni-app-vite-tailwindcss-v4/README.md | 12 +- .../artifacts/assets__index.1.css | 2 +- .../artifacts/assets__index.2.css | 2 +- .../artifacts/assets__index.3.css | 2 +- .../artifacts/assets__index.4.css | 2 +- .../artifacts/assets__index.5.css | 2 +- .../taro-vite-react-tailwindcss-v4/README.md | 10 +- .../artifacts/css__index.1.css | 2 +- .../artifacts/css__index.2.css | 2 +- .../artifacts/css__index.3.css | 2 +- .../artifacts/css__index.4.css | 2 +- .../taro-vite-vue3-tailwindcss-v4/README.md | 8 +- .../artifacts/css__index.1.css | 2 +- .../artifacts/css__index.2.css | 2 +- .../artifacts/css__index.3.css | 2 +- .../web/uni-app-vite-tailwindcss-v4/README.md | 12 +- .../artifacts/assets__index.1.css | 2 +- .../artifacts/assets__index.2.css | 2 +- .../artifacts/assets__index.3.css | 2 +- .../artifacts/assets__index.4.css | 2 +- .../artifacts/assets__index.5.css | 2 +- e2e/apps-generator-mode-compare.test.ts | 1 + e2e/snapshotUtils.test.ts | 11 +- e2e/snapshotUtils.ts | 26 +++- package.json | 7 +- .../theme-transition/package.json | 3 + .../theme-transition/tsdown.config.ts | 2 +- packages-runtime/typography/AGENTS.md | 2 +- packages-runtime/typography/package.json | 19 ++- .../typography/src/{index.js => index.cjs} | 4 +- .../typography/src/{styles.js => styles.cjs} | 0 .../typography/src/{utils.js => utils.cjs} | 0 .../typography/test/computed.test.ts | 2 +- .../typography/test/config-to-css.test.ts | 2 +- .../typography/test/index.test.ts | 2 +- .../typography/test/modern.test.ts | 2 +- .../typography/test/styles.test.ts | 2 +- .../typography/test/tsdown-config.test.ts | 37 +++++ .../typography/test/utils.test.ts | 2 +- packages-runtime/typography/tsdown.config.mts | 109 +++++++++---- packages/babel/package.json | 17 +- packages/babel/src/index.ts | 1 + packages/babel/test/evaluate.test.ts | 9 +- packages/babel/test/exports.test.ts | 18 +++ packages/babel/test/tsdown-config.test.ts | 39 +++++ packages/babel/tsdown.config.mts | 58 +++++-- packages/debug-uni-app-x/package.json | 15 +- packages/debug-uni-app-x/tsdown.config.mts | 4 +- packages/init/package.json | 9 +- packages/init/tsdown.config.mts | 2 +- packages/logger/package.json | 11 +- packages/logger/tsdown.config.mts | 4 +- packages/minify-preserve/package.json | 1 + .../test/bundler-config.test.ts | 5 +- packages/postcss/package.json | 36 +++-- packages/postcss/test/tsdown-config.test.ts | 34 ++++ packages/postcss/tsdown.config.mts | 58 +++++-- packages/reset/package.json | 5 +- packages/reset/tsdown.config.mts | 2 +- packages/shared/package.json | 21 ++- packages/shared/tsdown.config.mts | 4 +- packages/tailwindcss-config/package.json | 4 +- packages/tailwindcss-config/tsdown.config.ts | 2 +- packages/weapp-style-injector/package.json | 23 +-- .../weapp-style-injector/tsdown.config.mts | 2 +- ...p-tailwindcss.js => weapp-tailwindcss.cjs} | 2 +- packages/weapp-tailwindcss/package.json | 87 ++++++----- .../webpack/BaseUnifiedPlugin/v5-loaders.ts | 6 +- .../src/compiler/compilation-session-pool.ts | 2 +- packages/weapp-tailwindcss/src/constants.ts | 4 +- .../src/types/user-defined-options/general.ts | 2 +- .../test/build/dts-module-specifiers.test.ts | 70 +++++++++ .../test/build/tsdown-config.test.ts | 76 ++++++--- .../test/bundlers/rspack.unit.test.ts | 8 +- .../webpack.v5-runtime-metadata.unit.test.ts | 4 +- .../test/bundlers/webpack.v5.unit/shared.ts | 8 +- .../test/ci/package-module-exports.test.ts | 102 ++++++++++++ .../weapp-tailwindcss/test/cli/doctor.test.ts | 16 +- .../test/js/babel-utils.test.ts | 14 +- packages/weapp-tailwindcss/tsdown.shared.mts | 78 +++++++--- pnpm-lock.yaml | 145 +++++++++-------- pnpm-workspace.yaml | 6 + scripts/ensure-weapp-tailwindcss-built.mjs | 35 ++++- .../src/create-entry-dts.ts | 10 +- .../src/dts-module-specifiers.ts | 147 ++++++++++++++++++ .../src/rewrite-dts-aliases.ts | 24 ++- 103 files changed, 1183 insertions(+), 463 deletions(-) create mode 100644 .changeset/babel-eight-module-packages.md rename packages-runtime/typography/src/{index.js => index.cjs} (98%) rename packages-runtime/typography/src/{styles.js => styles.cjs} (100%) rename packages-runtime/typography/src/{utils.js => utils.cjs} (100%) create mode 100644 packages-runtime/typography/test/tsdown-config.test.ts create mode 100644 packages/babel/test/exports.test.ts create mode 100644 packages/babel/test/tsdown-config.test.ts create mode 100644 packages/postcss/test/tsdown-config.test.ts rename packages/weapp-tailwindcss/bin/{weapp-tailwindcss.js => weapp-tailwindcss.cjs} (69%) create mode 100644 packages/weapp-tailwindcss/test/build/dts-module-specifiers.test.ts create mode 100644 packages/weapp-tailwindcss/test/ci/package-module-exports.test.ts create mode 100644 tools/weapp-tailwindcss-scripts/src/dts-module-specifiers.ts diff --git a/.changeset/babel-eight-module-packages.md b/.changeset/babel-eight-module-packages.md new file mode 100644 index 0000000000..66a0a0564a --- /dev/null +++ b/.changeset/babel-eight-module-packages.md @@ -0,0 +1,15 @@ +--- +"weapp-tailwindcss": major +"@weapp-tailwindcss/debug-uni-app-x": patch +"@weapp-tailwindcss/init": patch +"@weapp-tailwindcss/logger": patch +"@weapp-tailwindcss/postcss": patch +"@weapp-tailwindcss/reset": patch +"@weapp-tailwindcss/shared": patch +"@weapp-tailwindcss/typography": patch +"tailwindcss-config": patch +"theme-transition": patch +"weapp-style-injector": patch +--- + +升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。 diff --git a/e2e/__snapshots__/apps-generator-mode/compare/report.json b/e2e/__snapshots__/apps-generator-mode/compare/report.json index d7e9e33753..bb795e4957 100644 --- a/e2e/__snapshots__/apps-generator-mode/compare/report.json +++ b/e2e/__snapshots__/apps-generator-mode/compare/report.json @@ -13565,7 +13565,7 @@ ], "status": "passed", "generator": { - "bytes": 448811, + "bytes": 448479, "selectors": [ "*", ".-translate-y-1", @@ -15902,7 +15902,7 @@ ], "status": "passed", "generator": { - "bytes": 434510, + "bytes": 434178, "selectors": [ "*", ".-translate-y-1", @@ -21911,7 +21911,7 @@ ], "status": "passed", "generator": { - "bytes": 333731, + "bytes": 333485, "selectors": [ "*", ".before\\:content-\\[\\'independent_subpackage_taro-vite-vue3-tailwindcss-v4\\'\\]:before", @@ -23705,7 +23705,7 @@ ], "status": "passed", "generator": { - "bytes": 327929, + "bytes": 327683, "selectors": [ "*", ".before\\:content-\\[\\'independent_subpackage_taro-vite-vue3-tailwindcss-v4\\'\\]:before", @@ -25508,7 +25508,7 @@ ], "status": "passed", "generator": { - "bytes": 74108, + "bytes": 73708, "selectors": [ "#app", "*", @@ -25939,7 +25939,7 @@ ], "status": "passed", "generator": { - "bytes": 72743, + "bytes": 72343, "selectors": [ "#app", "*", @@ -26371,7 +26371,7 @@ ], "status": "passed", "generator": { - "bytes": 36996, + "bytes": 36916, "selectors": [ "*", "*[data-v-04bcf89b]", @@ -26592,7 +26592,7 @@ ], "status": "passed", "generator": { - "bytes": 36996, + "bytes": 36916, "selectors": [ "*", "*[data-v-04bcf89b]", diff --git a/e2e/__snapshots__/apps-generator-mode/compare/report.md b/e2e/__snapshots__/apps-generator-mode/compare/report.md index 9a0f962982..291e69e2c6 100644 --- a/e2e/__snapshots__/apps-generator-mode/compare/report.md +++ b/e2e/__snapshots__/apps-generator-mode/compare/report.md @@ -16,16 +16,16 @@ This report is generated by `pnpm e2e:apps-generator`. It builds each retained d | weapp-vite-tailwindcss-v4 | demo | weapp | `weapp` | passed | `weapp-vite-tailwindcss-v4/dist/app.wxss` (+3) | 22937 | 100 | no | no | no | yes | yes | no | no | no | yes | | taro-webpack-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-webpack-react-tailwindcss-v4/dist` (+4) | 458112 | 2299 | yes | no | yes | yes | yes | no | no | yes | no | | taro-webpack-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-webpack-react-tailwindcss-v4/dist` (+4) | 441019 | 2299 | yes | no | yes | yes | yes | no | no | yes | no | -| taro-vite-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-react-tailwindcss-v4/dist` (+5) | 448811 | 2297 | yes | yes | yes | yes | yes | no | no | yes | no | -| taro-vite-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-react-tailwindcss-v4/dist` (+5) | 434510 | 2297 | yes | yes | yes | yes | yes | no | no | yes | no | +| taro-vite-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-react-tailwindcss-v4/dist` (+5) | 448479 | 2297 | yes | yes | yes | yes | yes | no | no | yes | no | +| taro-vite-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-react-tailwindcss-v4/dist` (+5) | 434178 | 2297 | yes | yes | yes | yes | yes | no | no | yes | no | | taro-webpack-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-webpack-vue3-tailwindcss-v4/dist` (+3) | 584311 | 1799 | yes | yes | yes | yes | yes | no | no | yes | no | | taro-webpack-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-webpack-vue3-tailwindcss-v4/dist` (+3) | 567561 | 1799 | yes | yes | yes | yes | yes | no | no | yes | no | -| taro-vite-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 333731 | 1756 | yes | yes | yes | yes | yes | no | no | yes | no | -| taro-vite-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 327929 | 1756 | yes | yes | yes | yes | yes | no | no | yes | no | -| uni-app-vite-tailwindcss-v4 | demo | web | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 74108 | 384 | yes | yes | yes | yes | yes | yes | no | yes | yes | -| uni-app-vite-tailwindcss-v4 | demo | web-compact | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 72743 | 387 | yes | yes | yes | yes | yes | yes | no | yes | yes | -| uni-app-vite-tailwindcss-v4 | demo | app-android | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36996 | 176 | yes | yes | yes | yes | yes | no | no | no | yes | -| uni-app-vite-tailwindcss-v4 | demo | app-ios | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36996 | 176 | yes | yes | yes | yes | yes | no | no | no | yes | +| taro-vite-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 333485 | 1756 | yes | yes | yes | yes | yes | no | no | yes | no | +| taro-vite-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | passed | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 327683 | 1756 | yes | yes | yes | yes | yes | no | no | yes | no | +| uni-app-vite-tailwindcss-v4 | demo | web | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 73708 | 384 | yes | yes | yes | yes | yes | yes | no | yes | yes | +| uni-app-vite-tailwindcss-v4 | demo | web-compact | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 72343 | 387 | yes | yes | yes | yes | yes | yes | no | yes | yes | +| uni-app-vite-tailwindcss-v4 | demo | app-android | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36916 | 176 | yes | yes | yes | yes | yes | no | no | no | yes | +| uni-app-vite-tailwindcss-v4 | demo | app-ios | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | passed | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36916 | 176 | yes | yes | yes | yes | yes | no | no | no | yes | ## Notes diff --git a/e2e/__snapshots__/apps-generator-mode/compare/report.zh-CN.md b/e2e/__snapshots__/apps-generator-mode/compare/report.zh-CN.md index 61f460e8e2..50f7c26169 100644 --- a/e2e/__snapshots__/apps-generator-mode/compare/report.zh-CN.md +++ b/e2e/__snapshots__/apps-generator-mode/compare/report.zh-CN.md @@ -16,16 +16,16 @@ | weapp-vite-tailwindcss-v4 | demo | weapp | `weapp` | 通过 | `weapp-vite-tailwindcss-v4/dist/app.wxss` (+3) | 22937 | 100 | 否 | 否 | 否 | 是 | 是 | 否 | 否 | 否 | 是 | | taro-webpack-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-webpack-react-tailwindcss-v4/dist` (+4) | 458112 | 2299 | 是 | 否 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | | taro-webpack-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-webpack-react-tailwindcss-v4/dist` (+4) | 441019 | 2299 | 是 | 否 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | -| taro-vite-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-react-tailwindcss-v4/dist` (+5) | 448811 | 2297 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | -| taro-vite-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-react-tailwindcss-v4/dist` (+5) | 434510 | 2297 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | +| taro-vite-react-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-react-tailwindcss-v4/dist` (+5) | 448479 | 2297 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | +| taro-vite-react-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-react-tailwindcss-v4/dist` (+5) | 434178 | 2297 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | | taro-webpack-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-webpack-vue3-tailwindcss-v4/dist` (+3) | 584311 | 1799 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | | taro-webpack-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-webpack-vue3-tailwindcss-v4/dist` (+3) | 567561 | 1799 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | -| taro-vite-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 333731 | 1756 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | -| taro-vite-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 327929 | 1756 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | -| uni-app-vite-tailwindcss-v4 | demo | web | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 74108 | 384 | 是 | 是 | 是 | 是 | 是 | 是 | 否 | 是 | 是 | -| uni-app-vite-tailwindcss-v4 | demo | web-compact | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 72743 | 387 | 是 | 是 | 是 | 是 | 是 | 是 | 否 | 是 | 是 | -| uni-app-vite-tailwindcss-v4 | demo | app-android | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36996 | 176 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | -| uni-app-vite-tailwindcss-v4 | demo | app-ios | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36996 | 176 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | +| taro-vite-vue3-tailwindcss-v4 | demo | web | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 333485 | 1756 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | +| taro-vite-vue3-tailwindcss-v4 | demo | web-compact | `weapp`, `swan`, `alipay`, `tt`, `h5`, `rn`, `qq`, `jd`, `harmony-hybrid` | 通过 | `taro-vite-vue3-tailwindcss-v4/dist` (+3) | 327683 | 1756 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 是 | 否 | +| uni-app-vite-tailwindcss-v4 | demo | web | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 73708 | 384 | 是 | 是 | 是 | 是 | 是 | 是 | 否 | 是 | 是 | +| uni-app-vite-tailwindcss-v4 | demo | web-compact | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/h5` (+5) | 72343 | 387 | 是 | 是 | 是 | 是 | 是 | 是 | 否 | 是 | 是 | +| uni-app-vite-tailwindcss-v4 | demo | app-android | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36916 | 176 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | +| uni-app-vite-tailwindcss-v4 | demo | app-ios | `app-android`, `app-ios`, `h5`, `h5:ssr`, `mp-alipay`, `mp-baidu`, `mp-jd`, `mp-kuaishou`, `mp-lark`, `mp-qq`, `mp-toutiao`, `mp-weixin`, `mp-xhs`, `quickapp-webview`, `quickapp-webview-huawei`, `quickapp-webview-union` | 通过 | `uni-app-vite-tailwindcss-v4/dist/build/app` (+3) | 36916 | 176 | 是 | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 是 | ## 说明 diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/README.md index a18138226f..b1ea4669ac 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/app | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 36996 | 176 | true | true | true | true | true | false | true | +| 36916 | 176 | true | true | true | true | true | false | true | ## Generator CSS Files @@ -25,4 +25,4 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/app | `app.css` | [artifacts/app.css](artifacts/app.css) | 31366 | 166 | true | true | true | true | true | false | true | | `pages-order/pages/home/home.css` | [artifacts/pages-order__pages__home__home.css](artifacts/pages-order__pages__home__home.css) | 1851 | 4 | true | false | true | false | false | false | false | | `pages-order/pages/user/user.css` | [artifacts/pages-order__pages__user__user.css](artifacts/pages-order__pages__user__user.css) | 1851 | 4 | true | false | true | false | false | false | false | -| `pages/index/index.css` | [artifacts/pages__index__index.css](artifacts/pages__index__index.css) | 1928 | 10 | false | false | false | false | false | false | true | +| `pages/index/index.css` | [artifacts/pages__index__index.css](artifacts/pages__index__index.css) | 1848 | 10 | false | false | false | false | false | false | true | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css b/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css index 0dbe09704c..f99d45b29e 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/app-android/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fcomponents%2FHelloWorld.vue */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fcomponents%2FHelloWorld.vue */ *[data-v-04bcf89b], [data-v-04bcf89b]::before, [data-v-04bcf89b]::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/README.md index e637c8e2ed..49aaf72a8e 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/app | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 36996 | 176 | true | true | true | true | true | false | true | +| 36916 | 176 | true | true | true | true | true | false | true | ## Generator CSS Files @@ -25,4 +25,4 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/app | `app.css` | [artifacts/app.css](artifacts/app.css) | 31366 | 166 | true | true | true | true | true | false | true | | `pages-order/pages/home/home.css` | [artifacts/pages-order__pages__home__home.css](artifacts/pages-order__pages__home__home.css) | 1851 | 4 | true | false | true | false | false | false | false | | `pages-order/pages/user/user.css` | [artifacts/pages-order__pages__user__user.css](artifacts/pages-order__pages__user__user.css) | 1851 | 4 | true | false | true | false | false | false | false | -| `pages/index/index.css` | [artifacts/pages__index__index.css](artifacts/pages__index__index.css) | 1928 | 10 | false | false | false | false | false | false | true | +| `pages/index/index.css` | [artifacts/pages__index__index.css](artifacts/pages__index__index.css) | 1848 | 10 | false | false | false | false | false | false | true | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css b/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css index 0dbe09704c..f99d45b29e 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/app-ios/uni-app-vite-tailwindcss-v4/artifacts/pages__index__index.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fcomponents%2FHelloWorld.vue */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fcomponents%2FHelloWorld.vue */ *[data-v-04bcf89b], [data-v-04bcf89b]::before, [data-v-04bcf89b]::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/README.md index 935ae7dc72..2d2760ba24 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: taro-vite-react-tailwindcss-v4/dist | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 434510 | 2297 | true | true | true | true | true | true | false | +| 434178 | 2297 | true | true | true | true | true | true | false | ## Generator CSS Files @@ -24,9 +24,9 @@ Entry: taro-vite-react-tailwindcss-v4/dist | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 13075 | 49 | true | false | true | false | false | true | false | -| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 380710 | 2230 | true | true | true | true | true | true | false | -| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 18887 | 86 | true | false | true | false | true | true | false | -| `css/index.4.css` | [artifacts/css__index.4.css](artifacts/css__index.4.css) | 7482 | 27 | true | false | true | false | false | true | false | +| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 12992 | 49 | true | false | true | false | false | true | false | +| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 380627 | 2230 | true | true | true | true | true | true | false | +| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 18804 | 86 | true | false | true | false | true | true | false | +| `css/index.4.css` | [artifacts/css__index.4.css](artifacts/css__index.4.css) | 7399 | 27 | true | false | true | false | false | true | false | | `css/index.5.css` | [artifacts/css__index.5.css](artifacts/css__index.5.css) | 50 | 1 | false | false | false | false | false | false | false | | `css/vendors.css` | [artifacts/css__vendors.css](artifacts/css__vendors.css) | 14306 | 59 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css index 1af25ebf1f..b7a4e04e9a 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ ::-webkit-backdrop { --tw-translate-x: 0; --tw-translate-y: 0; diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css index be58725d97..64b0f46e4b 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css @@ -1,4 +1,4 @@ -@charset "UTF-8"; /*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fapp.css */ +@charset "UTF-8"; /*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fapp.css */ ::-webkit-backdrop { --tw-space-y-reverse: 0; --tw-border-style: solid; diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css index 9af82badc6..d161d0091d 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fpages%2Fissue-998%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fpages%2Fissue-998%2Findex.css */ ::-webkit-backdrop { --tw-space-y-reverse: 0; --tw-border-style: solid; diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css index 0a06848232..66482b10b1 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ ::-webkit-backdrop { --tw-content: ''; } diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/README.md index e5060e2fea..f71849ff02 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: taro-vite-vue3-tailwindcss-v4/dist | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 327929 | 1756 | true | true | true | true | true | true | false | +| 327683 | 1756 | true | true | true | true | true | true | false | ## Generator CSS Files @@ -22,7 +22,7 @@ Entry: taro-vite-vue3-tailwindcss-v4/dist | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 7302 | 26 | true | false | true | false | false | true | false | -| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 7272 | 26 | true | false | true | false | false | true | false | -| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 292799 | 1582 | true | true | true | true | true | true | false | +| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 7220 | 26 | true | false | true | false | false | true | false | +| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 7190 | 26 | true | false | true | false | false | true | false | +| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 292717 | 1582 | true | true | true | true | true | true | false | | `css/vendors.css` | [artifacts/css__vendors.css](artifacts/css__vendors.css) | 20556 | 184 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css index ddfc99a775..0c687f7a0a 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ ::-webkit-backdrop { --tw-content: ''; } diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css index 3f81e9ed78..770eb86a8d 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ ::-webkit-backdrop { --tw-content: ''; } diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css index d4b6963b7d..cfacd51eb4 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fapp.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fapp.css */ ::-webkit-backdrop { --tw-gradient-from: #0000; --tw-gradient-via: #0000; diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/README.md index 84db8496c6..fb8258d70c 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/h5 | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 72743 | 387 | true | true | true | true | true | true | true | +| 72343 | 387 | true | true | true | true | true | true | true | ## Generator CSS Files @@ -24,9 +24,9 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/h5 | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `assets/index.1.css` | [artifacts/assets__index.1.css](artifacts/assets__index.1.css) | 40988 | 232 | true | true | true | true | true | true | false | -| `assets/index.2.css` | [artifacts/assets__index.2.css](artifacts/assets__index.2.css) | 13540 | 66 | true | false | true | false | false | true | false | -| `assets/index.3.css` | [artifacts/assets__index.3.css](artifacts/assets__index.3.css) | 2013 | 10 | false | false | false | false | false | false | true | -| `assets/index.4.css` | [artifacts/assets__index.4.css](artifacts/assets__index.4.css) | 3506 | 32 | true | false | false | false | false | true | false | -| `assets/index.5.css` | [artifacts/assets__index.5.css](artifacts/assets__index.5.css) | 3536 | 32 | true | false | false | false | false | true | false | +| `assets/index.1.css` | [artifacts/assets__index.1.css](artifacts/assets__index.1.css) | 40908 | 232 | true | true | true | true | true | true | false | +| `assets/index.2.css` | [artifacts/assets__index.2.css](artifacts/assets__index.2.css) | 13460 | 66 | true | false | true | false | false | true | false | +| `assets/index.3.css` | [artifacts/assets__index.3.css](artifacts/assets__index.3.css) | 1933 | 10 | false | false | false | false | false | false | true | +| `assets/index.4.css` | [artifacts/assets__index.4.css](artifacts/assets__index.4.css) | 3426 | 32 | true | false | false | false | false | true | false | +| `assets/index.5.css` | [artifacts/assets__index.5.css](artifacts/assets__index.5.css) | 3456 | 32 | true | false | false | false | false | true | false | | `assets/uni.css` | [artifacts/assets__uni.css](artifacts/assets__uni.css) | 9160 | 86 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css index 3c42bcd0cf..c5357c43e9 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css @@ -339,7 +339,7 @@ uni-page-head[uni-page-head-type='default'] ~ uni-page-wrapper { } .uni-page-head-shadow-yellow::after { background-image: url(https://cdn.dcloud.net.cn/img/shadow-yellow.png); -} /*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fmain.css */ +} /*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fmain.css */ *, ::before, ::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css index 286d0dd32f..8f97c29a64 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fpages-order%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fpages-order%2Findex.css */ *, ::before, ::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css index cc63330b3b..3145a00e4d 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fcomponents%2FHelloWorld.vue */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fcomponents%2FHelloWorld.vue */ *[data-v-04bcf89b], [data-v-04bcf89b]::before, [data-v-04bcf89b]::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css index ac91d93adb..d1e3bc6174 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ *[data-v-0a5a82ca], [data-v-0a5a82ca]::before, [data-v-0a5a82ca]::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css index aaa29c4249..7102be6ec6 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web-compact/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ *[data-v-b12531e8], [data-v-b12531e8]::before, [data-v-b12531e8]::after, diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/README.md index f3f1ab8536..dbb863a38c 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: taro-vite-react-tailwindcss-v4/dist | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 448811 | 2297 | true | true | true | true | true | true | false | +| 448479 | 2297 | true | true | true | true | true | true | false | ## Generator CSS Files @@ -24,9 +24,9 @@ Entry: taro-vite-react-tailwindcss-v4/dist | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 17345 | 49 | true | false | true | false | false | true | false | -| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 385373 | 2230 | true | true | true | true | true | true | false | -| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 22899 | 86 | true | false | true | false | true | true | false | -| `css/index.4.css` | [artifacts/css__index.4.css](artifacts/css__index.4.css) | 8838 | 27 | true | false | true | false | false | true | false | +| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 17262 | 49 | true | false | true | false | false | true | false | +| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 385290 | 2230 | true | true | true | true | true | true | false | +| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 22816 | 86 | true | false | true | false | true | true | false | +| `css/index.4.css` | [artifacts/css__index.4.css](artifacts/css__index.4.css) | 8755 | 27 | true | false | true | false | false | true | false | | `css/index.5.css` | [artifacts/css__index.5.css](artifacts/css__index.5.css) | 50 | 1 | false | false | false | false | false | false | false | | `css/vendors.css` | [artifacts/css__vendors.css](artifacts/css__vendors.css) | 14306 | 59 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css index 65acebc967..e90501e6c9 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.1.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css index 951d28519d..32a6d3c57b 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.2.css @@ -1,4 +1,4 @@ -@charset "UTF-8"; /*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fapp.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +@charset "UTF-8"; /*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fapp.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css index c00e443edb..30d6d4683f 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.3.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fpages%2Fissue-998%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fpages%2Fissue-998%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css index 4adbcfb1f1..305b150c35 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-react-tailwindcss-v4/artifacts/css__index.4.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-react-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/README.md index 22482ad21f..d754dca05d 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: taro-vite-vue3-tailwindcss-v4/dist | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 333731 | 1756 | true | true | true | true | true | true | false | +| 333485 | 1756 | true | true | true | true | true | true | false | ## Generator CSS Files @@ -22,7 +22,7 @@ Entry: taro-vite-vue3-tailwindcss-v4/dist | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 8650 | 26 | true | false | true | false | false | true | false | -| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 8620 | 26 | true | false | true | false | false | true | false | -| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 295905 | 1582 | true | true | true | true | true | true | false | +| `css/index.1.css` | [artifacts/css__index.1.css](artifacts/css__index.1.css) | 8568 | 26 | true | false | true | false | false | true | false | +| `css/index.2.css` | [artifacts/css__index.2.css](artifacts/css__index.2.css) | 8538 | 26 | true | false | true | false | false | true | false | +| `css/index.3.css` | [artifacts/css__index.3.css](artifacts/css__index.3.css) | 295823 | 1582 | true | true | true | true | true | true | false | | `css/vendors.css` | [artifacts/css__vendors.css](artifacts/css__vendors.css) | 20556 | 184 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css index 6df8c3c6ac..c133d5e1b2 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.1.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css index c7b39c9a70..fde628aa84 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.2.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css index 4939ebddda..c900f5f06f 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/taro-vite-vue3-tailwindcss-v4/artifacts/css__index.3.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Ftaro-vite-vue3-tailwindcss-v4%2Fsrc%2Fapp.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fapp.css */ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme,base,components,utilities; @layer theme { diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/README.md b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/README.md index 16db749ec1..f2c8173444 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/README.md +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/README.md @@ -7,7 +7,7 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/h5 | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| 74108 | 384 | true | true | true | true | true | true | true | +| 73708 | 384 | true | true | true | true | true | true | true | ## Generator CSS Files @@ -24,9 +24,9 @@ Entry: uni-app-vite-tailwindcss-v4/dist/build/h5 | File | Artifact | Bytes | Selectors | @supports | :hover | Tailwind banner | System dark media | Manual dark selector | Raw arbitrary selector | Weapp escaped arbitrary selector | | --- | --- | ---: | ---: | --- | --- | --- | --- | --- | --- | --- | -| `assets/index.1.css` | [artifacts/assets__index.1.css](artifacts/assets__index.1.css) | 41257 | 233 | true | true | true | true | true | true | false | -| `assets/index.2.css` | [artifacts/assets__index.2.css](artifacts/assets__index.2.css) | 14538 | 67 | true | false | true | false | false | true | false | -| `assets/index.3.css` | [artifacts/assets__index.3.css](artifacts/assets__index.3.css) | 3517 | 32 | true | false | false | false | false | true | false | -| `assets/index.4.css` | [artifacts/assets__index.4.css](artifacts/assets__index.4.css) | 3547 | 32 | true | false | false | false | false | true | false | -| `assets/index.5.css` | [artifacts/assets__index.5.css](artifacts/assets__index.5.css) | 2089 | 6 | false | false | false | false | false | false | true | +| `assets/index.1.css` | [artifacts/assets__index.1.css](artifacts/assets__index.1.css) | 41177 | 233 | true | true | true | true | true | true | false | +| `assets/index.2.css` | [artifacts/assets__index.2.css](artifacts/assets__index.2.css) | 14458 | 67 | true | false | true | false | false | true | false | +| `assets/index.3.css` | [artifacts/assets__index.3.css](artifacts/assets__index.3.css) | 3437 | 32 | true | false | false | false | false | true | false | +| `assets/index.4.css` | [artifacts/assets__index.4.css](artifacts/assets__index.4.css) | 3467 | 32 | true | false | false | false | false | true | false | +| `assets/index.5.css` | [artifacts/assets__index.5.css](artifacts/assets__index.5.css) | 2009 | 6 | false | false | false | false | false | false | true | | `assets/uni.css` | [artifacts/assets__uni.css](artifacts/assets__uni.css) | 9160 | 86 | false | false | false | false | false | false | false | diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css index ba289ee55b..86ad744dff 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.1.css @@ -1,4 +1,4 @@ -*{margin:0;-webkit-tap-highlight-color:transparent}html,body{-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%;height:100%}body{overflow-x:hidden;font-size:16px}uni-app,uni-page,uni-page-wrapper,uni-page-body{display:block;box-sizing:border-box;width:100%}uni-page-wrapper{position:relative}#app,uni-app,uni-page,uni-page-wrapper{height:100%}.uni-mask{position:fixed;z-index:999;top:0;right:0;left:0;bottom:0;background:rgba(0,0,0,.5)}.uni-fade-enter-active,.uni-fade-leave-active{transition-duration:.25s;transition-property:opacity;transition-timing-function:ease}.uni-fade-enter-from,.uni-fade-leave-active{opacity:0}.uni-loading,uni-button[loading]::before{background-color:transparent;background-image:url(data:image/svg+xml;base64,\ PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=);background-repeat:no-repeat}.uni-loading{width:20px;height:20px;display:inline-block;vertical-align:middle;animation:uni-loading 1s steps(12,end) infinite;background-size:100%}@keyframes uni-loading{0%{transform:rotate3d(0,0,1,0)}to{transform:rotate3d(0,0,1,360deg)}}html{--primary-color: #007aff;--UI-BG: #fff;--UI-BG-1: #f7f7f7;--UI-BG-2: #fff;--UI-BG-3: #f7f7f7;--UI-BG-4: #4c4c4c;--UI-BG-5: #fff;--UI-FG: #000;--UI-FG-0: rgba(0, 0, 0, .9);--UI-FG-HALF: rgba(0, 0, 0, .9);--UI-FG-1: rgba(0, 0, 0, .5);--UI-FG-2: rgba(0, 0, 0, .3);--UI-FG-3: rgba(0, 0, 0, .1)}uni-page[data-type] uni-page-body{background-color:transparent}body::after{position:fixed;content:"";left:-1000px;top:-1000px;animation:shadow-preload .1s;animation-delay:3s}@keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}to{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}.uni-async-error{position:absolute;left:0;right:0;top:0;bottom:0;color:#999;padding:100px 10px;text-align:center}.uni-async-loading{box-sizing:border-box;width:100%;padding:50px;text-align:center}.uni-async-loading .uni-loading{width:30px;height:30px}uni-page-head{display:block;box-sizing:border-box}.uni-page-head{position:fixed;left:var(--window-left);right:var(--window-right);height:44px;height:calc(44px + constant(safe-area-inset-top));height:calc(44px + env(safe-area-inset-top));padding:7px 3px;padding-top:calc(7px + constant(safe-area-inset-top));padding-top:calc(7px + env(safe-area-inset-top));display:flex;overflow:hidden;justify-content:space-between;box-sizing:border-box;z-index:998;color:#fff;background-color:#000;transition-property:all}.uni-page-head *{box-sizing:border-box}.uni-page-head .uni-btn-icon{overflow:hidden;min-width:1em;font-style:normal}.uni-page-head-titlePenetrate,.uni-page-head-titlePenetrate .uni-page-head-bd,.uni-page-head-titlePenetrate .uni-page-head-bd *{pointer-events:none}.uni-page-head-titlePenetrate *{pointer-events:auto}.uni-page-head.uni-page-head-transparent .uni-page-head-ft>div{justify-content:center}.uni-page-head~.uni-placeholder{width:100%;height:44px;height:calc(44px + constant(safe-area-inset-top));height:calc(44px + env(safe-area-inset-top))}.uni-placeholder-titlePenetrate{pointer-events:none}.uni-page-head-hd{display:flex;align-items:center;font-size:16px}.uni-page-head-bd{position:absolute;left:70px;right:70px;min-width:0;-webkit-user-select:auto;-moz-user-select:auto;user-select:auto}.uni-page-head-btn{position:relative;width:auto;margin:0 2px;word-break:keep-all;white-space:pre;cursor:pointer;font-size:0px}.uni-page-head-transparent .uni-page-head-btn{display:flex;align-items:center;width:32px;height:32px;border-radius:50%;background-color:rgba(0,0,0,.5)}.uni-page-head-btn-red-dot::after{content:attr(badge-text);position:absolute;right:0;top:0;background-color:red;color:#fff;width:18px;height:18px;line-height:18px;border-radius:18px;overflow:hidden;transform:scale(.5) translate(40%,-40%);transform-origin:100% 0}.uni-page-head-btn-red-dot[badge-text]::after{font-size:12px;width:auto;min-width:18px;max-width:42px;text-align:center;padding:0 3px;transform:scale(.7) translate(40%,-40%)}.uni-page-head-btn-select svg{vertical-align:middle;margin-left:2px;transform:rotate(270deg) scale(.8)}.uni-page-head-search{position:relative;display:flex;flex:1;margin:0 2px;line-height:30px;font-size:15px}.uni-page-head-search-input{width:100%;height:100%;padding-left:34px;text-align:left}.uni-page-head-search-input .uni-input-input:disabled{pointer-events:none}.uni-page-head-search-placeholder{position:absolute;max-width:100%;height:100%;padding-left:34px;overflow:hidden;word-break:keep-all;white-space:pre}.uni-page-head-search-placeholder-right{right:0}.uni-page-head-search-placeholder-center{left:50%;transform:translate(-50%)}.uni-page-head-search-icon{position:absolute;top:0;left:2px;width:30px;height:30px;display:flex;justify-content:center;align-items:center}.uni-page-head-ft{display:flex;align-items:center;flex-direction:row-reverse;font-size:13px}.uni-page-head__title{font-weight:700;font-size:16px;line-height:30px;text-align:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.uni-page-head__title .uni-loading{width:16px;height:16px;margin-top:-3px}.uni-page-head__title .uni-page-head__title_image{width:auto;height:26px;vertical-align:middle}.uni-page-head-shadow{overflow:visible}.uni-page-head-shadow::after{content:"";position:absolute;left:0;right:0;top:100%;height:5px;background-size:100% 100%}uni-page-head[uni-page-head-type=default]~uni-page-wrapper{height:calc(100% - 44px);height:calc(100% - 44px - constant(safe-area-inset-top));height:calc(100% - 44px - env(safe-area-inset-top))}.uni-page-head-shadow-grey::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}.uni-page-head-shadow-blue::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-blue.png)}.uni-page-head-shadow-green::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-green.png)}.uni-page-head-shadow-orange::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-orange.png)}.uni-page-head-shadow-red::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-red.png)}.uni-page-head-shadow-yellow::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-yellow.png)}/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fmain.css *//*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-300: oklch(80.8% .114 19.571);--color-red-500: oklch(63.7% .237 25.331);--color-green-200: oklch(92.5% .084 155.995);--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-200: oklch(90.5% .093 164.15);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-emerald-700: oklch(50.8% .118 165.612);--color-slate-50: oklch(98.4% .003 247.858);--color-slate-100: oklch(96.8% .007 247.896);--color-slate-200: oklch(92.9% .013 255.508);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-700: oklch(37.2% .044 257.287);--color-slate-800: oklch(27.9% .041 260.031);--color-slate-900: oklch(20.8% .042 265.755);--color-zinc-50: oklch(98.5% 0 none);--color-zinc-900: oklch(21% .006 285.885);--color-zinc-950: oklch(14.1% .005 285.823);--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono);--color-neutral-1B: #1b1b1b;--color-neutral-66: #666;--color-midnight: #121063;--color-tahiti: #3ab7bf;--color-bermuda: #78dcca}}@layer base{*,::after,::before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}uni-progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,uni-video,uni-canvas,uni-audio,iframe,embed,object{display:block;vertical-align:middle}img,uni-video{max-width:100%;height:auto}uni-button,uni-input,select,optgroup,uni-textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::-moz-placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}::placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}uni-button,uni-input:where([type=button],[type=reset],[type=submit]),::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{ +*{margin:0;-webkit-tap-highlight-color:transparent}html,body{-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%;height:100%}body{overflow-x:hidden;font-size:16px}uni-app,uni-page,uni-page-wrapper,uni-page-body{display:block;box-sizing:border-box;width:100%}uni-page-wrapper{position:relative}#app,uni-app,uni-page,uni-page-wrapper{height:100%}.uni-mask{position:fixed;z-index:999;top:0;right:0;left:0;bottom:0;background:rgba(0,0,0,.5)}.uni-fade-enter-active,.uni-fade-leave-active{transition-duration:.25s;transition-property:opacity;transition-timing-function:ease}.uni-fade-enter-from,.uni-fade-leave-active{opacity:0}.uni-loading,uni-button[loading]::before{background-color:transparent;background-image:url(data:image/svg+xml;base64,\ PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=);background-repeat:no-repeat}.uni-loading{width:20px;height:20px;display:inline-block;vertical-align:middle;animation:uni-loading 1s steps(12,end) infinite;background-size:100%}@keyframes uni-loading{0%{transform:rotate3d(0,0,1,0)}to{transform:rotate3d(0,0,1,360deg)}}html{--primary-color: #007aff;--UI-BG: #fff;--UI-BG-1: #f7f7f7;--UI-BG-2: #fff;--UI-BG-3: #f7f7f7;--UI-BG-4: #4c4c4c;--UI-BG-5: #fff;--UI-FG: #000;--UI-FG-0: rgba(0, 0, 0, .9);--UI-FG-HALF: rgba(0, 0, 0, .9);--UI-FG-1: rgba(0, 0, 0, .5);--UI-FG-2: rgba(0, 0, 0, .3);--UI-FG-3: rgba(0, 0, 0, .1)}uni-page[data-type] uni-page-body{background-color:transparent}body::after{position:fixed;content:"";left:-1000px;top:-1000px;animation:shadow-preload .1s;animation-delay:3s}@keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}to{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}.uni-async-error{position:absolute;left:0;right:0;top:0;bottom:0;color:#999;padding:100px 10px;text-align:center}.uni-async-loading{box-sizing:border-box;width:100%;padding:50px;text-align:center}.uni-async-loading .uni-loading{width:30px;height:30px}uni-page-head{display:block;box-sizing:border-box}.uni-page-head{position:fixed;left:var(--window-left);right:var(--window-right);height:44px;height:calc(44px + constant(safe-area-inset-top));height:calc(44px + env(safe-area-inset-top));padding:7px 3px;padding-top:calc(7px + constant(safe-area-inset-top));padding-top:calc(7px + env(safe-area-inset-top));display:flex;overflow:hidden;justify-content:space-between;box-sizing:border-box;z-index:998;color:#fff;background-color:#000;transition-property:all}.uni-page-head *{box-sizing:border-box}.uni-page-head .uni-btn-icon{overflow:hidden;min-width:1em;font-style:normal}.uni-page-head-titlePenetrate,.uni-page-head-titlePenetrate .uni-page-head-bd,.uni-page-head-titlePenetrate .uni-page-head-bd *{pointer-events:none}.uni-page-head-titlePenetrate *{pointer-events:auto}.uni-page-head.uni-page-head-transparent .uni-page-head-ft>div{justify-content:center}.uni-page-head~.uni-placeholder{width:100%;height:44px;height:calc(44px + constant(safe-area-inset-top));height:calc(44px + env(safe-area-inset-top))}.uni-placeholder-titlePenetrate{pointer-events:none}.uni-page-head-hd{display:flex;align-items:center;font-size:16px}.uni-page-head-bd{position:absolute;left:70px;right:70px;min-width:0;-webkit-user-select:auto;-moz-user-select:auto;user-select:auto}.uni-page-head-btn{position:relative;width:auto;margin:0 2px;word-break:keep-all;white-space:pre;cursor:pointer;font-size:0px}.uni-page-head-transparent .uni-page-head-btn{display:flex;align-items:center;width:32px;height:32px;border-radius:50%;background-color:rgba(0,0,0,.5)}.uni-page-head-btn-red-dot::after{content:attr(badge-text);position:absolute;right:0;top:0;background-color:red;color:#fff;width:18px;height:18px;line-height:18px;border-radius:18px;overflow:hidden;transform:scale(.5) translate(40%,-40%);transform-origin:100% 0}.uni-page-head-btn-red-dot[badge-text]::after{font-size:12px;width:auto;min-width:18px;max-width:42px;text-align:center;padding:0 3px;transform:scale(.7) translate(40%,-40%)}.uni-page-head-btn-select svg{vertical-align:middle;margin-left:2px;transform:rotate(270deg) scale(.8)}.uni-page-head-search{position:relative;display:flex;flex:1;margin:0 2px;line-height:30px;font-size:15px}.uni-page-head-search-input{width:100%;height:100%;padding-left:34px;text-align:left}.uni-page-head-search-input .uni-input-input:disabled{pointer-events:none}.uni-page-head-search-placeholder{position:absolute;max-width:100%;height:100%;padding-left:34px;overflow:hidden;word-break:keep-all;white-space:pre}.uni-page-head-search-placeholder-right{right:0}.uni-page-head-search-placeholder-center{left:50%;transform:translate(-50%)}.uni-page-head-search-icon{position:absolute;top:0;left:2px;width:30px;height:30px;display:flex;justify-content:center;align-items:center}.uni-page-head-ft{display:flex;align-items:center;flex-direction:row-reverse;font-size:13px}.uni-page-head__title{font-weight:700;font-size:16px;line-height:30px;text-align:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.uni-page-head__title .uni-loading{width:16px;height:16px;margin-top:-3px}.uni-page-head__title .uni-page-head__title_image{width:auto;height:26px;vertical-align:middle}.uni-page-head-shadow{overflow:visible}.uni-page-head-shadow::after{content:"";position:absolute;left:0;right:0;top:100%;height:5px;background-size:100% 100%}uni-page-head[uni-page-head-type=default]~uni-page-wrapper{height:calc(100% - 44px);height:calc(100% - 44px - constant(safe-area-inset-top));height:calc(100% - 44px - env(safe-area-inset-top))}.uni-page-head-shadow-grey::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}.uni-page-head-shadow-blue::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-blue.png)}.uni-page-head-shadow-green::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-green.png)}.uni-page-head-shadow-orange::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-orange.png)}.uni-page-head-shadow-red::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-red.png)}.uni-page-head-shadow-yellow::after{background-image:url(https://cdn.dcloud.net.cn/img/shadow-yellow.png)}/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fmain.css *//*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-300: oklch(80.8% .114 19.571);--color-red-500: oklch(63.7% .237 25.331);--color-green-200: oklch(92.5% .084 155.995);--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-200: oklch(90.5% .093 164.15);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-emerald-700: oklch(50.8% .118 165.612);--color-slate-50: oklch(98.4% .003 247.858);--color-slate-100: oklch(96.8% .007 247.896);--color-slate-200: oklch(92.9% .013 255.508);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-700: oklch(37.2% .044 257.287);--color-slate-800: oklch(27.9% .041 260.031);--color-slate-900: oklch(20.8% .042 265.755);--color-zinc-50: oklch(98.5% 0 none);--color-zinc-900: oklch(21% .006 285.885);--color-zinc-950: oklch(14.1% .005 285.823);--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono);--color-neutral-1B: #1b1b1b;--color-neutral-66: #666;--color-midnight: #121063;--color-tahiti: #3ab7bf;--color-bermuda: #78dcca}}@layer base{*,::after,::before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}uni-progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,uni-video,uni-canvas,uni-audio,iframe,embed,object{display:block;vertical-align:middle}img,uni-video{max-width:100%;height:auto}uni-button,uni-input,select,optgroup,uni-textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::-moz-placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}::placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}uni-button,uni-input:where([type=button],[type=reset],[type=submit]),::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{ /*tokens: m-3 <= src/pages/index/index.vue */ .m-3{margin:calc(var(--spacing) * 3)} /*tokens: mt-1 <= src/pages/index/index.vue */ diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css index f1a571c29d..663d143461 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.2.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fpages-order%2Findex.css *//*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-slate-50: oklch(98.4% .003 247.858);--color-slate-200: oklch(92.9% .013 255.508);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-800: oklch(27.9% .041 260.031);--color-slate-900: oklch(20.8% .042 265.755);--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,::after,::before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}uni-progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,uni-video,uni-canvas,uni-audio,iframe,embed,object{display:block;vertical-align:middle}img,uni-video{max-width:100%;height:auto}uni-button,uni-input,select,optgroup,uni-textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::-moz-placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}::placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}uni-button,uni-input:where([type=button],[type=reset],[type=submit]),::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fpages-order%2Findex.css *//*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-slate-50: oklch(98.4% .003 247.858);--color-slate-200: oklch(92.9% .013 255.508);--color-slate-500: oklch(55.4% .046 257.417);--color-slate-800: oklch(27.9% .041 260.031);--color-slate-900: oklch(20.8% .042 265.755);--color-white: #fff;--spacing: .25rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--text-xl: 1.25rem;--text-xl--line-height: calc(1.75 / 1.25);--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,::after,::before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}uni-progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,uni-video,uni-canvas,uni-audio,iframe,embed,object{display:block;vertical-align:middle}img,uni-video{max-width:100%;height:auto}uni-button,uni-input,select,optgroup,uni-textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::-moz-placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}::placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}uni-button,uni-input:where([type=button],[type=reset],[type=submit]),::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{ /*tokens: mt-2 <= src/pages-order/pages/user/user.vue, src/pages/index/index.vue */ .mt-2{margin-top:calc(var(--spacing) * 2)} /*tokens: mt-4 <= src/pages-order/pages/home/home.vue, src/pages/index/index.vue */ diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css index b5e72eb7c8..fca5ae0a46 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.3.css @@ -1,3 +1,3 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */@layer properties;@layer theme,base,components,utilities;@layer base{*[data-v-0a5a82ca],[data-v-0a5a82ca]::after,[data-v-0a5a82ca]::before,[data-v-0a5a82ca]::backdrop,[data-v-0a5a82ca]::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}code[data-v-0a5a82ca],kbd[data-v-0a5a82ca],samp[data-v-0a5a82ca],pre[data-v-0a5a82ca]{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}:-moz-focusring:where([data-v-0a5a82ca]:not(iframe)){outline:auto}img[data-v-0a5a82ca],svg[data-v-0a5a82ca],uni-video[data-v-0a5a82ca],uni-canvas[data-v-0a5a82ca],uni-audio[data-v-0a5a82ca],iframe[data-v-0a5a82ca],embed[data-v-0a5a82ca],object[data-v-0a5a82ca]{display:block;vertical-align:middle}img[data-v-0a5a82ca],uni-video[data-v-0a5a82ca]{max-width:100%;height:auto}uni-button[data-v-0a5a82ca],uni-input[data-v-0a5a82ca],select[data-v-0a5a82ca],optgroup[data-v-0a5a82ca],uni-textarea[data-v-0a5a82ca],[data-v-0a5a82ca]::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup[data-v-0a5a82ca]{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option[data-v-0a5a82ca]{padding-inline-start:20px}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea[data-v-0a5a82ca]{resize:vertical}[data-v-0a5a82ca]:-moz-ui-invalid{box-shadow:none}uni-button[data-v-0a5a82ca],uni-input:where([type=button][data-v-0a5a82ca],[type=reset][data-v-0a5a82ca],[type=submit][data-v-0a5a82ca]),[data-v-0a5a82ca]::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}[hidden]:where([data-v-0a5a82ca]:not([hidden=until-found])){display:none!important}}@layer utilities{ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-normal%2Fpages%2Findex.css */@layer properties;@layer theme,base,components,utilities;@layer base{*[data-v-0a5a82ca],[data-v-0a5a82ca]::after,[data-v-0a5a82ca]::before,[data-v-0a5a82ca]::backdrop,[data-v-0a5a82ca]::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}code[data-v-0a5a82ca],kbd[data-v-0a5a82ca],samp[data-v-0a5a82ca],pre[data-v-0a5a82ca]{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}:-moz-focusring:where([data-v-0a5a82ca]:not(iframe)){outline:auto}img[data-v-0a5a82ca],svg[data-v-0a5a82ca],uni-video[data-v-0a5a82ca],uni-canvas[data-v-0a5a82ca],uni-audio[data-v-0a5a82ca],iframe[data-v-0a5a82ca],embed[data-v-0a5a82ca],object[data-v-0a5a82ca]{display:block;vertical-align:middle}img[data-v-0a5a82ca],uni-video[data-v-0a5a82ca]{max-width:100%;height:auto}uni-button[data-v-0a5a82ca],uni-input[data-v-0a5a82ca],select[data-v-0a5a82ca],optgroup[data-v-0a5a82ca],uni-textarea[data-v-0a5a82ca],[data-v-0a5a82ca]::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup[data-v-0a5a82ca]{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option[data-v-0a5a82ca]{padding-inline-start:20px}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea[data-v-0a5a82ca]{resize:vertical}[data-v-0a5a82ca]:-moz-ui-invalid{box-shadow:none}uni-button[data-v-0a5a82ca],uni-input:where([type=button][data-v-0a5a82ca],[type=reset][data-v-0a5a82ca],[type=submit][data-v-0a5a82ca]),[data-v-0a5a82ca]::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}[hidden]:where([data-v-0a5a82ca]:not([hidden=until-found])){display:none!important}}@layer utilities{ /*tokens: bg-normal-subpackage-marker <= src/sub-normal/pages/index.vue */ .bg-normal-subpackage-marker[data-v-0a5a82ca]{background-color:#2563eb}.before\:content-\[\'normal_subpackage_uni-app-vite-tailwindcss-v4\'\][data-v-0a5a82ca]::before{--tw-content: "normal subpackage uni-app-vite-tailwindcss-v4";content:var(--tw-content)}.before\:content-\[\'现在,让我们开始神奇的_tailwindcss_开发之旅吧!\'\][data-v-0a5a82ca]::before{--tw-content: "现在,让我们开始神奇的 tailwindcss 开发之旅吧!";content:var(--tw-content)}.before\:content-\[\'现在,让我们继续神奇的_tailwindcss_HMR_回归之旅吧!\'\][data-v-0a5a82ca]::before{--tw-content: "现在,让我们继续神奇的 tailwindcss HMR 回归之旅吧!";content:var(--tw-content)}}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*[data-v-0a5a82ca],[data-v-0a5a82ca]::before,[data-v-0a5a82ca]::after,[data-v-0a5a82ca]::backdrop{--tw-content: ""}}} diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css index 02e72a8395..47e4c3f341 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.4.css @@ -1,3 +1,3 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */@layer properties;@layer theme,base,components,utilities;@layer base{*[data-v-b12531e8],[data-v-b12531e8]::after,[data-v-b12531e8]::before,[data-v-b12531e8]::backdrop,[data-v-b12531e8]::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}code[data-v-b12531e8],kbd[data-v-b12531e8],samp[data-v-b12531e8],pre[data-v-b12531e8]{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}:-moz-focusring:where([data-v-b12531e8]:not(iframe)){outline:auto}img[data-v-b12531e8],svg[data-v-b12531e8],uni-video[data-v-b12531e8],uni-canvas[data-v-b12531e8],uni-audio[data-v-b12531e8],iframe[data-v-b12531e8],embed[data-v-b12531e8],object[data-v-b12531e8]{display:block;vertical-align:middle}img[data-v-b12531e8],uni-video[data-v-b12531e8]{max-width:100%;height:auto}uni-button[data-v-b12531e8],uni-input[data-v-b12531e8],select[data-v-b12531e8],optgroup[data-v-b12531e8],uni-textarea[data-v-b12531e8],[data-v-b12531e8]::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup[data-v-b12531e8]{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option[data-v-b12531e8]{padding-inline-start:20px}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea[data-v-b12531e8]{resize:vertical}[data-v-b12531e8]:-moz-ui-invalid{box-shadow:none}uni-button[data-v-b12531e8],uni-input:where([type=button][data-v-b12531e8],[type=reset][data-v-b12531e8],[type=submit][data-v-b12531e8]),[data-v-b12531e8]::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}[hidden]:where([data-v-b12531e8]:not([hidden=until-found])){display:none!important}}@layer utilities{ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fsub-independent%2Fpages%2Findex.css */@layer properties;@layer theme,base,components,utilities;@layer base{*[data-v-b12531e8],[data-v-b12531e8]::after,[data-v-b12531e8]::before,[data-v-b12531e8]::backdrop,[data-v-b12531e8]::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}code[data-v-b12531e8],kbd[data-v-b12531e8],samp[data-v-b12531e8],pre[data-v-b12531e8]{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}:-moz-focusring:where([data-v-b12531e8]:not(iframe)){outline:auto}img[data-v-b12531e8],svg[data-v-b12531e8],uni-video[data-v-b12531e8],uni-canvas[data-v-b12531e8],uni-audio[data-v-b12531e8],iframe[data-v-b12531e8],embed[data-v-b12531e8],object[data-v-b12531e8]{display:block;vertical-align:middle}img[data-v-b12531e8],uni-video[data-v-b12531e8]{max-width:100%;height:auto}uni-button[data-v-b12531e8],uni-input[data-v-b12531e8],select[data-v-b12531e8],optgroup[data-v-b12531e8],uni-textarea[data-v-b12531e8],[data-v-b12531e8]::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup[data-v-b12531e8]{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option[data-v-b12531e8]{padding-inline-start:20px}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}@supports (color: color-mix(in lab,red,red)){{color:color-mix(in oklab,currentcolor 50%,transparent)}}}uni-textarea[data-v-b12531e8]{resize:vertical}[data-v-b12531e8]:-moz-ui-invalid{box-shadow:none}uni-button[data-v-b12531e8],uni-input:where([type=button][data-v-b12531e8],[type=reset][data-v-b12531e8],[type=submit][data-v-b12531e8]),[data-v-b12531e8]::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}[hidden]:where([data-v-b12531e8]:not([hidden=until-found])){display:none!important}}@layer utilities{ /*tokens: bg-independent-subpackage-marker <= src/sub-independent/pages/index.vue */ .bg-independent-subpackage-marker[data-v-b12531e8]{background-color:#dc2626}.before\:content-\[\'independent_subpackage_uni-app-vite-tailwindcss-v4\'\][data-v-b12531e8]::before{--tw-content: "independent subpackage uni-app-vite-tailwindcss-v4";content:var(--tw-content)}.before\:content-\[\'现在,让我们开始神奇的_tailwindcss_开发之旅吧!\'\][data-v-b12531e8]::before{--tw-content: "现在,让我们开始神奇的 tailwindcss 开发之旅吧!";content:var(--tw-content)}.before\:content-\[\'现在,让我们继续神奇的_tailwindcss_HMR_回归之旅吧!\'\][data-v-b12531e8]::before{--tw-content: "现在,让我们继续神奇的 tailwindcss HMR 回归之旅吧!";content:var(--tw-content)}}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*[data-v-b12531e8],[data-v-b12531e8]::before,[data-v-b12531e8]::after,[data-v-b12531e8]::backdrop{--tw-content: ""}}} diff --git a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css index 1e47bb3233..e285f77232 100644 --- a/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css +++ b/e2e/__snapshots__/apps-generator-mode/css-output/web/uni-app-vite-tailwindcss-v4/artifacts/assets__index.5.css @@ -1,4 +1,4 @@ -/*! weapp-tailwindcss vite-generated-css:%2FUsers%2Ficebreaker%2FProjects%2Fgithub%2Fweapp-tailwindcss%2Fdemo%2Funi-app-vite-tailwindcss-v4%2Fsrc%2Fcomponents%2FHelloWorld.vue */ +/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fcomponents%2FHelloWorld.vue */ @layer properties; @layer theme,base,components,utilities; @layer theme; diff --git a/e2e/apps-generator-mode-compare.test.ts b/e2e/apps-generator-mode-compare.test.ts index 497828de68..984554cc4a 100644 --- a/e2e/apps-generator-mode-compare.test.ts +++ b/e2e/apps-generator-mode-compare.test.ts @@ -509,6 +509,7 @@ async function collectOutputDirectoryCssSnapshots(projectRoot: string, project: .map(async (file) => { const entries = await collectCssSnapshots(outputRoot, file, { classList, + generatedCssSourceRoot: projectRoot, rootSnapshotName: normalizeOutputCssFileName(file), normalizeTailwindV4RootVariableNoise: shouldNormalizeTailwindV4RootVariableNoise(projectRoot), }) diff --git a/e2e/snapshotUtils.test.ts b/e2e/snapshotUtils.test.ts index 7f2dfd4f9a..60eb2f3a07 100644 --- a/e2e/snapshotUtils.test.ts +++ b/e2e/snapshotUtils.test.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os' import path from 'pathe' import { describe, expect, it } from 'vitest' import { replaceWxml } from '../packages/weapp-tailwindcss/src/wxml' -import { collectCssSnapshots, formatRawCssSnapshotText, normalizeCssSnapshot, normalizeFontDataUrlsForSnapshot, normalizeFormattedCssSnapshot, normalizeRawCssSnapshotText, normalizeSnapshotName } from './snapshotUtils' +import { collectCssSnapshots, formatRawCssSnapshotText, normalizeCssSnapshot, normalizeFontDataUrlsForSnapshot, normalizeFormattedCssSnapshot, normalizeGeneratedCssSourceMarkers, normalizeRawCssSnapshotText, normalizeSnapshotName } from './snapshotUtils' describe('normalizeCssSnapshot', () => { it('normalizes generated css file hashes in path segments', () => { @@ -40,6 +40,15 @@ describe('normalizeCssSnapshot', () => { ].join('\n'))).resolves.toContain('url(data:font/woff2;base64,) format(\'truetype\')') }) + it('normalizes generated css source markers across worktree paths', () => { + const source = '/*! weapp-tailwindcss vite-generated-css:%2Ftmp%2Frepo-worktree%2Fdemo%2Fapp%2Fsrc%2Fapp.css */' + + expect(normalizeGeneratedCssSourceMarkers(source, '/tmp/repo-worktree/demo/app')).toBe( + '/*! weapp-tailwindcss vite-generated-css:%3Cproject-root%3E%2Fsrc%2Fapp.css */', + ) + expect(normalizeGeneratedCssSourceMarkers(source, '/tmp/other-project')).toBe(source) + }) + it('falls back to PostCSS normalization for unsupported nested declaration blocks', async () => { const css = '@supports (color: color-mix(in lab,red,red)){{color:red}}' diff --git a/e2e/snapshotUtils.ts b/e2e/snapshotUtils.ts index 12b1265311..1b6c27c326 100644 --- a/e2e/snapshotUtils.ts +++ b/e2e/snapshotUtils.ts @@ -15,6 +15,7 @@ export interface CssTokenSource { export interface CssSnapshotOptions { classList?: string[] + generatedCssSourceRoot?: string normalizeWebpackAppSplitNoise?: boolean normalizeTailwindV4RootVariableNoise?: boolean rootSnapshotName?: string @@ -192,6 +193,26 @@ export function normalizeFontDataUrlsForSnapshot(source: string) { }) } +const GENERATED_CSS_SOURCE_MARKER_RE = /(\/\*!\s*weapp-tailwindcss vite-generated-css:)([^\s*]+)(\s*\*\/)/g + +export function normalizeGeneratedCssSourceMarkers(source: string, projectRoot: string) { + const normalizedProjectRoot = path.resolve(projectRoot) + return source.replace(GENERATED_CSS_SOURCE_MARKER_RE, (marker, prefix, encodedSource, suffix) => { + try { + const sourceFile = decodeURIComponent(encodedSource) + const relativeSource = safeRelative(normalizedProjectRoot, path.resolve(sourceFile)) + if (!relativeSource) { + return marker + } + const stableSource = path.posix.join('', relativeSource.replace(/\\/g, '/')) + return `${prefix}${encodeURIComponent(stableSource)}${suffix}` + } + catch { + return marker + } + }) +} + export function normalizeFormattedCssSnapshot(source: string) { return source .replace(/\}\s+(\/\*\s*tokens?:)/g, '}\n$1') @@ -1146,7 +1167,10 @@ export async function collectCssSnapshots(projectRoot: string, cssRelativePath: visited.add(normalizedPath) - const source = await fs.readFile(normalizedPath, 'utf8') + const source = normalizeGeneratedCssSourceMarkers( + await fs.readFile(normalizedPath, 'utf8'), + options.generatedCssSourceRoot ?? projectRoot, + ) const cssNormalizeOptions: CssSnapshotOptions = {} if (options.normalizeWebpackAppSplitNoise) { cssNormalizeOptions.normalizeWebpackAppSplitNoise = true diff --git a/package.json b/package.json index c677f84c2f..d092c39803 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "gulp-plugin" ], "engines": { - "node": ">=22.12.0" + "node": "^22.18.0 || >=24.11.0" }, "scripts": { "build": "cross-env WEAPP_TW_SKIP_INTERACTIVE_TARO_BUILD=1 WEAPP_TW_SKIP_INTERACTIVE_UNI_BUILD=1 turbo run build", @@ -245,8 +245,8 @@ }, "devDependencies": { "@ampproject/remapping": "^2.3.0", - "@babel/core": "catalog:babelCore7285", - "@babel/generator": "~7.29.7", + "@babel/core": "catalog:babel8", + "@babel/generator": "catalog:babel8", "@changesets/changelog-github": "^0.7.0", "@changesets/cli": "^2.31.1", "@commitlint/cli": "^21.2.1", @@ -306,7 +306,6 @@ "@weapp-vite/miniprogram-automator": "^1.2.7", "anymatch": "^3.1.3", "autoprefixer": "catalog:autoprefixer10", - "babel-loader": "^10.1.1", "boxen": "^8.0.1", "browserslist": "^4.28.6", "chokidar": "^5.0.0", diff --git a/packages-runtime/theme-transition/package.json b/packages-runtime/theme-transition/package.json index 263fe65061..ad292b86a8 100644 --- a/packages-runtime/theme-transition/package.json +++ b/packages-runtime/theme-transition/package.json @@ -60,6 +60,9 @@ "optional": true } }, + "dependencies": { + "defu": "^6.1.7" + }, "publishConfig": { "exports": { ".": { diff --git a/packages-runtime/theme-transition/tsdown.config.ts b/packages-runtime/theme-transition/tsdown.config.ts index ca17be01e3..8e0c108a03 100644 --- a/packages-runtime/theme-transition/tsdown.config.ts +++ b/packages-runtime/theme-transition/tsdown.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ dts: true, deps: { neverBundle: [/^tailwindcss(\/|$)/], - onlyBundle: ['defu'], + onlyBundle: false, }, outputOptions: { exports: 'named', diff --git a/packages-runtime/typography/AGENTS.md b/packages-runtime/typography/AGENTS.md index fd31b2c957..fe3fb86bd0 100644 --- a/packages-runtime/typography/AGENTS.md +++ b/packages-runtime/typography/AGENTS.md @@ -7,7 +7,7 @@ ## 核心职责 -- `src/index.js`:typography 插件主体(variant 注册、selector 变换、`legacy/modern` 目标处理)。 +- `src/index.cjs`:typography 插件主体(variant 注册、selector 变换、`legacy/modern` 目标处理)。 - `src/transform.ts`:HTML 结构注入 class 的转换函数(基于 `htmlparser2` + `magic-string`)。 ## 变更原则 diff --git a/packages-runtime/typography/package.json b/packages-runtime/typography/package.json index d48d7ef851..832372641b 100644 --- a/packages-runtime/typography/package.json +++ b/packages-runtime/typography/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/typography", + "type": "module", "version": "1.0.0", "description": "The tailwindcss typography plugin for weapp", "author": "ice breaker <1324318532@qq.com>", @@ -22,18 +23,18 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" }, "./transform": { "types": "./dist/transform.d.ts", - "import": "./dist/transform.mjs", - "require": "./dist/transform.js" + "import": "./dist/transform.js", + "require": "./dist/transform.cjs" }, "./*": "./*" }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "typesVersions": { "*": { @@ -58,8 +59,7 @@ "release": "pnpm publish", "sync": "cnpm sync @weapp-tailwindcss/typography" }, - "devDependencies": { - "@weapp-tailwindcss/test-helper": "workspace:*", + "dependencies": { "htmlparser2": "^12.0.0", "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", @@ -67,6 +67,9 @@ "magic-string": "^1.0.0", "postcss-selector-parser": "^7.1.4" }, + "devDependencies": { + "@weapp-tailwindcss/test-helper": "workspace:*" + }, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages-runtime/typography/src/index.js b/packages-runtime/typography/src/index.cjs similarity index 98% rename from packages-runtime/typography/src/index.js rename to packages-runtime/typography/src/index.cjs index c8d541c58f..6e7026e771 100644 --- a/packages-runtime/typography/src/index.js +++ b/packages-runtime/typography/src/index.cjs @@ -2,8 +2,8 @@ const castArray = require('lodash.castarray') const merge = require('lodash.merge') const parser = require('postcss-selector-parser') const plugin = require('tailwindcss/plugin') -const styles = require('./styles') -const { commonTrailingPseudos } = require('./utils') +const styles = require('./styles.cjs') +const { commonTrailingPseudos } = require('./utils.cjs') const parseSelector = parser() const computed = { diff --git a/packages-runtime/typography/src/styles.js b/packages-runtime/typography/src/styles.cjs similarity index 100% rename from packages-runtime/typography/src/styles.js rename to packages-runtime/typography/src/styles.cjs diff --git a/packages-runtime/typography/src/utils.js b/packages-runtime/typography/src/utils.cjs similarity index 100% rename from packages-runtime/typography/src/utils.js rename to packages-runtime/typography/src/utils.cjs diff --git a/packages-runtime/typography/test/computed.test.ts b/packages-runtime/typography/test/computed.test.ts index d99930a76f..1bdc83a38a 100644 --- a/packages-runtime/typography/test/computed.test.ts +++ b/packages-runtime/typography/test/computed.test.ts @@ -1,7 +1,7 @@ /* eslint-disable ts/no-require-imports */ import { generateCss4 } from '@weapp-tailwindcss/test-helper' -const typographyPlugin: any = require('../src/index') +const typographyPlugin: any = require('../src/index.cjs') describe('computed hooks', () => { afterEach(() => { diff --git a/packages-runtime/typography/test/config-to-css.test.ts b/packages-runtime/typography/test/config-to-css.test.ts index eb0fff66d2..bff6bb7ca2 100644 --- a/packages-runtime/typography/test/config-to-css.test.ts +++ b/packages-runtime/typography/test/config-to-css.test.ts @@ -1,5 +1,5 @@ /* eslint-disable ts/no-require-imports */ -const typographyPlugin: any = require('../src/index') +const typographyPlugin: any = require('../src/index.cjs') describe('configToCss helper', () => { it('handles non-nested values for modern targets and modifiers', () => { diff --git a/packages-runtime/typography/test/index.test.ts b/packages-runtime/typography/test/index.test.ts index 09c05f11e4..147eb32144 100644 --- a/packages-runtime/typography/test/index.test.ts +++ b/packages-runtime/typography/test/index.test.ts @@ -2,7 +2,7 @@ import type { Config } from 'tailwindcss' import { generateCss4 } from '@weapp-tailwindcss/test-helper' -const typographyPlugin = require('../src/index') +const typographyPlugin = require('../src/index.cjs') // import typographyPlugin from '@/index' // const path = require('node:path') diff --git a/packages-runtime/typography/test/modern.test.ts b/packages-runtime/typography/test/modern.test.ts index 0a0848458a..12b402481a 100644 --- a/packages-runtime/typography/test/modern.test.ts +++ b/packages-runtime/typography/test/modern.test.ts @@ -2,7 +2,7 @@ import type { Config } from 'tailwindcss' import { generateCss4 } from '@weapp-tailwindcss/test-helper' -const typographyPlugin = require('../src/index') +const typographyPlugin = require('../src/index.cjs') const html = String.raw diff --git a/packages-runtime/typography/test/styles.test.ts b/packages-runtime/typography/test/styles.test.ts index 8415f0ac36..8e14fddd03 100644 --- a/packages-runtime/typography/test/styles.test.ts +++ b/packages-runtime/typography/test/styles.test.ts @@ -1,4 +1,4 @@ -import styles from '../src/styles' +import styles from '../src/styles.cjs' describe('styles', () => { it('snap', () => { diff --git a/packages-runtime/typography/test/tsdown-config.test.ts b/packages-runtime/typography/test/tsdown-config.test.ts new file mode 100644 index 0000000000..3273f87440 --- /dev/null +++ b/packages-runtime/typography/test/tsdown-config.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest' +import { + createTypographyTsdownConfigs, + htmlparser2EsmOnlyDependencies, + typographyCjsBundledDependencies, + typographyExternalDependencies, +} from '../tsdown.config.mts' + +describe('typography tsdown config', () => { + it('keeps dependencies external in ESM and only bundles htmlparser2 for CJS', () => { + const [pluginEsm, pluginCjs, transformEsm, transformCjs] = createTypographyTsdownConfigs() + + expect(pluginEsm.format).toEqual(['esm']) + expect(pluginEsm.entry).toEqual(['src/index.cjs']) + expect(pluginEsm.deps?.neverBundle).toEqual([ + ...htmlparser2EsmOnlyDependencies, + 'magic-string', + ...typographyExternalDependencies, + ]) + expect(pluginCjs.format).toEqual(['cjs']) + expect(pluginCjs.deps?.alwaysBundle).toBe(typographyCjsBundledDependencies) + expect(pluginCjs.deps?.neverBundle).toBe(typographyExternalDependencies) + expect(transformEsm.dts).toBe(true) + expect(transformCjs.dts).toBe(false) + }) + + it('emits .js/.cjs and only cleans once outside watch mode', () => { + const configs = createTypographyTsdownConfigs() + const outExtensions = configs[0].outExtensions + + expect(configs[0].clean).toBe(true) + expect(configs.slice(1).every(config => config.clean === false)).toBe(true) + expect(outExtensions?.({ format: 'es' } as never).js).toBe('.js') + expect(outExtensions?.({ format: 'cjs' } as never).js).toBe('.cjs') + expect(createTypographyTsdownConfigs({ watch: true }).every(config => config.clean === false)).toBe(true) + }) +}) diff --git a/packages-runtime/typography/test/utils.test.ts b/packages-runtime/typography/test/utils.test.ts index f19a75308a..ae243265ed 100644 --- a/packages-runtime/typography/test/utils.test.ts +++ b/packages-runtime/typography/test/utils.test.ts @@ -1,5 +1,5 @@ /* eslint-disable ts/no-require-imports */ -const utils = require('../src/utils') +const utils = require('../src/utils.cjs') describe('typography utils', () => { it('detects usable palette entries', () => { diff --git a/packages-runtime/typography/tsdown.config.mts b/packages-runtime/typography/tsdown.config.mts index cab1997649..592dbd1612 100644 --- a/packages-runtime/typography/tsdown.config.mts +++ b/packages-runtime/typography/tsdown.config.mts @@ -1,40 +1,95 @@ import { defineConfig } from 'tsdown' +interface WatchAwareOptions { + watch?: boolean | string | Array +} + +export const htmlparser2EsmOnlyDependencies = [ + 'htmlparser2', + 'domhandler', + 'domutils', + 'domelementtype', + 'entities', +] + +export const typographyCjsBundledDependencies = [ + ...htmlparser2EsmOnlyDependencies, + 'magic-string', +] + +export const typographyExternalDependencies = [ + 'lodash.castarray', + 'lodash.isplainobject', + 'lodash.merge', + 'postcss-selector-parser', + /^tailwindcss(\/|$)/, +] + const sharedOptions = { // 禁用 Node.js shim,保持 ESM 产物适合浏览器侧 bundler 直接使用。 shims: false, - format: ['cjs', 'esm'], - deps: { - alwaysBundle: [ - 'htmlparser2', - 'lodash.castarray', - 'lodash.isplainobject', - 'lodash.merge', - 'magic-string', - 'postcss-selector-parser', - ], - neverBundle: [/^tailwindcss(\/|$)/], - }, target: 'es6', outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, } satisfies Parameters[0] -export default defineConfig([ - { - ...sharedOptions, - entry: ['src/index.js'], - clean: true, - dts: false, - }, - { - ...sharedOptions, - entry: ['src/transform.ts'], - clean: false, - dts: true, - }, -]) +export function createTypographyTsdownConfigs(options: WatchAwareOptions = {}) { + const esmOptions = { + deps: { + neverBundle: [ + ...htmlparser2EsmOnlyDependencies, + 'magic-string', + ...typographyExternalDependencies, + ], + onlyBundle: false, + }, + } + const cjsOptions = { + deps: { + alwaysBundle: typographyCjsBundledDependencies, + neverBundle: typographyExternalDependencies, + onlyBundle: false, + }, + } + + return [ + { + ...sharedOptions, + ...esmOptions, + entry: ['src/index.cjs'], + format: ['esm'], + clean: !options.watch, + dts: false, + }, + { + ...sharedOptions, + ...cjsOptions, + entry: ['src/index.cjs'], + format: ['cjs'], + clean: false, + dts: false, + }, + { + ...sharedOptions, + ...esmOptions, + entry: ['src/transform.ts'], + format: ['esm'], + clean: false, + dts: true, + }, + { + ...sharedOptions, + ...cjsOptions, + entry: ['src/transform.ts'], + format: ['cjs'], + clean: false, + dts: false, + }, + ] +} + +export default defineConfig((options = {}) => createTypographyTsdownConfigs(options)) diff --git a/packages/babel/package.json b/packages/babel/package.json index b4e3a53c1d..54ea16166f 100644 --- a/packages/babel/package.json +++ b/packages/babel/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/babel", + "type": "module", "version": "0.0.3", "private": true, "description": "weapp-tailwindcss babel package", @@ -22,7 +23,7 @@ "dist" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^22.18.0 || >=24.11.0" }, "scripts": { "dev": "tsdown --watch --sourcemap", @@ -34,20 +35,20 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@babel/parser": "~7.29.7", - "@babel/traverse": "~7.29.7", - "@babel/types": "~7.29.7" + "@babel/parser": "catalog:babel8", + "@babel/traverse": "catalog:babel8", + "@babel/types": "catalog:babel8" }, "publishConfig": { "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" } }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts" } } diff --git a/packages/babel/src/index.ts b/packages/babel/src/index.ts index e69de29bb2..fa96d336dc 100644 --- a/packages/babel/src/index.ts +++ b/packages/babel/src/index.ts @@ -0,0 +1 @@ +export * from './babel' diff --git a/packages/babel/test/evaluate.test.ts b/packages/babel/test/evaluate.test.ts index bb731b8cdb..680d90c094 100644 --- a/packages/babel/test/evaluate.test.ts +++ b/packages/babel/test/evaluate.test.ts @@ -1,4 +1,5 @@ -import babel from '@babel/core' +import type { PluginItem } from '@babel/core' +import { transformSync } from '@babel/core' import fs from 'fs-extra' import path from 'pathe' @@ -6,7 +7,7 @@ function getCase(name: string) { return fs.readFileSync(path.resolve(import.meta.dirname, './fixtures/evaluate', name), 'utf8') } -const plugin: babel.PluginItem = { +const plugin: PluginItem = { visitor: { BinaryExpression(path) { // 尝试计算二元表达式的常量值 @@ -68,7 +69,7 @@ const plugin: babel.PluginItem = { } describe('evaluate', () => { it('0.js', () => { - const res = babel.transform( + const res = transformSync( getCase('0.js'), { plugins: [ @@ -82,7 +83,7 @@ describe('evaluate', () => { }) it('1.js', () => { - const res = babel.transform( + const res = transformSync( getCase('1.js'), { plugins: [ diff --git a/packages/babel/test/exports.test.ts b/packages/babel/test/exports.test.ts new file mode 100644 index 0000000000..8a4a72d606 --- /dev/null +++ b/packages/babel/test/exports.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest' +import { parse, parseExpression, traverse } from '../src/index' + +describe('Babel 8 exports', () => { + it('parses and traverses a real module', () => { + const ast = parse('const answer = 42', { sourceType: 'module' }) + const identifiers: string[] = [] + + traverse(ast, { + Identifier(path) { + identifiers.push(path.node.name) + }, + }) + + expect(identifiers).toEqual(['answer']) + expect(parseExpression('answer + 1').type).toBe('BinaryExpression') + }) +}) diff --git a/packages/babel/test/tsdown-config.test.ts b/packages/babel/test/tsdown-config.test.ts new file mode 100644 index 0000000000..f86aa4335f --- /dev/null +++ b/packages/babel/test/tsdown-config.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest' +import { + babelEsmOnlyDependencies, + babelOutExtensions, + createBabelTsdownConfigs, +} from '../tsdown.config.mts' + +function matchesDependency(patterns: Array, id: string) { + return patterns.some(pattern => typeof pattern === 'string' ? pattern === id : pattern.test(id)) +} + +describe('Babel tsdown config', () => { + it('emits ESM .js, CJS .cjs and declarations once', () => { + const [esm, cjs] = createBabelTsdownConfigs() + + expect(esm.format).toEqual(['esm']) + expect(esm.clean).toBe(true) + expect(esm.dts).toBe(true) + expect(cjs.format).toEqual(['cjs']) + expect(cjs.clean).toBe(false) + expect(cjs.dts).toBe(false) + expect(babelOutExtensions({ format: 'es' }).js).toBe('.js') + expect(babelOutExtensions({ format: 'cjs' }).js).toBe('.cjs') + }) + + it('externalizes Babel 8 from ESM and bundles its ESM-only graph into CJS', () => { + const [esm, cjs] = createBabelTsdownConfigs() + + expect(esm.deps?.neverBundle).toBe(babelEsmOnlyDependencies) + expect(cjs.deps?.alwaysBundle).toBe(babelEsmOnlyDependencies) + expect(matchesDependency(babelEsmOnlyDependencies, '@babel/parser')).toBe(true) + expect(matchesDependency(babelEsmOnlyDependencies, '@babel/traverse')).toBe(true) + expect(matchesDependency(babelEsmOnlyDependencies, 'obug')).toBe(true) + }) + + it('disables clean while watching', () => { + expect(createBabelTsdownConfigs({ watch: true }).every(config => config.clean === false)).toBe(true) + }) +}) diff --git a/packages/babel/tsdown.config.mts b/packages/babel/tsdown.config.mts index 34ee48db48..55d106eff6 100644 --- a/packages/babel/tsdown.config.mts +++ b/packages/babel/tsdown.config.mts @@ -1,15 +1,47 @@ import { defineConfig } from 'tsdown' -export default defineConfig({ - entry: ['src/index.ts'], - shims: true, - format: ['cjs', 'esm'], - clean: true, - dts: true, - outExtensions({ format }) { - return { - js: format === 'es' ? '.mjs' : '.js', - dts: '.d.ts', - } - }, -}) +interface WatchAwareOptions { + watch?: boolean | string | Array +} + +export const babelEsmOnlyDependencies = [/^@babel\//, 'obug'] + +export function babelOutExtensions({ format }: { format: string }) { + return { + js: format === 'es' ? '.js' : '.cjs', + dts: '.d.ts', + } +} + +export function createBabelTsdownConfigs(options: WatchAwareOptions = {}) { + const shouldClean = !options.watch + + return [ + { + entry: ['src/index.ts'], + shims: true, + format: ['esm'], + clean: shouldClean, + dts: true, + deps: { + neverBundle: babelEsmOnlyDependencies, + onlyBundle: false, + }, + outExtensions: babelOutExtensions, + }, + { + entry: ['src/index.ts'], + shims: true, + format: ['cjs'], + clean: false, + dts: false, + deps: { + alwaysBundle: babelEsmOnlyDependencies, + onlyBundle: false, + }, + outExtensions: babelOutExtensions, + }, + ] +} + +export default defineConfig((options = {}) => createBabelTsdownConfigs(options)) diff --git a/packages/debug-uni-app-x/package.json b/packages/debug-uni-app-x/package.json index 4a86887538..21d1f2c836 100644 --- a/packages/debug-uni-app-x/package.json +++ b/packages/debug-uni-app-x/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/debug-uni-app-x", + "type": "module", "version": "1.0.1", "author": "ice breaker <1324318532@qq.com>", "license": "MIT", @@ -18,12 +19,12 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", + "import": "./dist/index.js", "require": "./dist/index.cjs" } }, "main": "./dist/index.cjs", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "engines": { "node": "^20.19.0 || >=22.12.0" @@ -39,22 +40,24 @@ "lint": "eslint .", "lint:fix": "eslint . --fix" }, - "devDependencies": { + "dependencies": { "defu": "6.1.7", "fs-extra": "11.3.6", - "pathe": "2.0.3", + "pathe": "2.0.3" + }, + "devDependencies": { "vite": "7.2.7" }, "publishConfig": { "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", + "import": "./dist/index.js", "require": "./dist/index.cjs" } }, "main": "./dist/index.cjs", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "access": "public", "registry": "https://registry.npmjs.org" diff --git a/packages/debug-uni-app-x/tsdown.config.mts b/packages/debug-uni-app-x/tsdown.config.mts index 61e06a42b2..f512bc5218 100644 --- a/packages/debug-uni-app-x/tsdown.config.mts +++ b/packages/debug-uni-app-x/tsdown.config.mts @@ -7,12 +7,12 @@ export default defineConfig({ dts: true, shims: true, deps: { - alwaysBundle: ['defu', 'fs-extra', 'pathe'], neverBundle: ['vite'], + onlyBundle: false, }, outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.cjs', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/init/package.json b/packages/init/package.json index 01eb469187..16ee64975e 100644 --- a/packages/init/package.json +++ b/packages/init/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/init", + "type": "module", "version": "1.0.12", "description": "@weapp-tailwindcss/init", "author": "ice breaker <1324318532@qq.com>", @@ -17,12 +18,12 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" } }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ "dist" diff --git a/packages/init/tsdown.config.mts b/packages/init/tsdown.config.mts index 34ee48db48..6b3d894601 100644 --- a/packages/init/tsdown.config.mts +++ b/packages/init/tsdown.config.mts @@ -8,7 +8,7 @@ export default defineConfig({ dts: true, outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/logger/package.json b/packages/logger/package.json index 91ca3041bd..1d2a8fa65f 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/logger", + "type": "module", "version": "2.0.0", "description": "@weapp-tailwindcss/logger", "author": "ice breaker <1324318532@qq.com>", @@ -17,12 +18,12 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" } }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ "dist" @@ -40,7 +41,7 @@ "lint:fix": "eslint . --fix" }, "publishConfig": {}, - "devDependencies": { + "dependencies": { "consola": "^3.4.2", "picocolors": "^1.1.1" } diff --git a/packages/logger/tsdown.config.mts b/packages/logger/tsdown.config.mts index 94aaaff5b9..eb62d2d8ab 100644 --- a/packages/logger/tsdown.config.mts +++ b/packages/logger/tsdown.config.mts @@ -7,11 +7,11 @@ export default defineConfig({ clean: true, dts: true, deps: { - alwaysBundle: ['consola', 'picocolors'], + onlyBundle: false, }, outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/minify-preserve/package.json b/packages/minify-preserve/package.json index b61d43d29a..4a738c9988 100644 --- a/packages/minify-preserve/package.json +++ b/packages/minify-preserve/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/minify-preserve", + "type": "module", "version": "0.0.0", "private": true, "description": "Examples for keeping weapp-tailwindcss helper names during minification.", diff --git a/packages/minify-preserve/test/bundler-config.test.ts b/packages/minify-preserve/test/bundler-config.test.ts index 3dbb4ef34b..84ff6c830d 100644 --- a/packages/minify-preserve/test/bundler-config.test.ts +++ b/packages/minify-preserve/test/bundler-config.test.ts @@ -1,4 +1,5 @@ import type { PluginObj, PluginPass } from '@babel/core' +import { transformAsync } from '@babel/core' import type { Configuration, Stats } from 'webpack' import { mkdtemp, readdir, readFile, rm, writeFile } from 'node:fs/promises' import { createRequire } from 'node:module' @@ -235,8 +236,6 @@ async function bundleWithSwc(keepFnNames: boolean) { return result.code.trim() } -const babel = require('@babel/core') as typeof import('@babel/core') - interface ManglePluginOptions { keepNames?: boolean } @@ -265,7 +264,7 @@ function babelManglePlugin(): PluginObj { } async function bundleWithBabel(keepFnNames: boolean) { - const result = await babel.transformAsync(BABEL_SOURCE, { + const result = await transformAsync(BABEL_SOURCE, { configFile: false, babelrc: false, sourceType: 'module', diff --git a/packages/postcss/package.json b/packages/postcss/package.json index ef0dd6a1b7..2679761bc9 100644 --- a/packages/postcss/package.json +++ b/packages/postcss/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/postcss", + "type": "module", "version": "3.1.12", "description": "@weapp-tailwindcss/postcss", "author": "ice breaker <1324318532@qq.com>", @@ -17,28 +18,28 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" }, "./types": { "types": "./dist/types.d.ts", - "import": "./dist/types.mjs", - "require": "./dist/types.js" + "import": "./dist/types.js", + "require": "./dist/types.cjs" }, "./html-transform": { "types": "./dist/html-transform.d.ts", - "import": "./dist/html-transform.mjs", - "require": "./dist/html-transform.js" + "import": "./dist/html-transform.js", + "require": "./dist/html-transform.cjs" }, "./css-macro/postcss": { "types": "./dist/css-macro/postcss.d.ts", - "import": "./dist/css-macro/postcss.mjs", - "require": "./dist/css-macro/postcss.js" + "import": "./dist/css-macro/postcss.js", + "require": "./dist/css-macro/postcss.cjs" }, "./package.json": "./package.json" }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "typesVersions": { "*": { @@ -65,8 +66,8 @@ }, "scripts": { "dev": "tsdown --watch --sourcemap", - "build": "tsdown && tsc -p tsconfig.build.json", - "build:types": "tsc -p tsconfig.build.json", + "build": "tsdown && tsc -p tsconfig.build.json && tsx ../../tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts .", + "build:types": "tsc -p tsconfig.build.json && tsx ../../tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts .", "test": "vitest run", "bench": "vitest bench", "test:dev": "vitest", @@ -75,15 +76,20 @@ "lint:fix": "eslint . --fix" }, "dependencies": { + "@csstools/css-color-parser": "^4.1.9", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", "@tailwindcss-mangle/engine": "catalog:tailwindcssMangleEngine", "@weapp-core/escape": "~8.0.0", "@weapp-tailwindcss/postcss-calc": "workspace:^", "@weapp-tailwindcss/shared": "workspace:*", "autoprefixer": "catalog:autoprefixer10", + "es-toolkit": "^1.49.0", "lru-cache": "11.5.2", "micromatch": "^4.0.8", "postcss": "catalog:postcss85tilde", "postcss-load-config": "^6.0.1", + "postcss-preset-env": "^11.3.2", "postcss-pxtrans": "^1.0.4", "postcss-rem-to-responsive-pixel": "catalog:postcssRem", "postcss-rule-unit-converter": "^0.2.2", @@ -92,13 +98,9 @@ "tailwindcss-config": "workspace:*" }, "devDependencies": { - "@csstools/css-color-parser": "^4.1.9", - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-is-pseudo-class": "^6.0.0", "fast-check": "^4.9.0", "postcss-calc": "link:packages/postcss-calc", - "postcss-custom-properties": "^15.0.1", - "postcss-preset-env": "^11.3.2" + "postcss-custom-properties": "^15.0.1" } } diff --git a/packages/postcss/test/tsdown-config.test.ts b/packages/postcss/test/tsdown-config.test.ts new file mode 100644 index 0000000000..156fe5a00b --- /dev/null +++ b/packages/postcss/test/tsdown-config.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from 'vitest' +import { + createPostcssTsdownConfigs, + postcssEsmOnlyDependencies, +} from '../tsdown.config.mts' + +function matchesDependency(patterns: Array, id: string) { + return patterns.some(pattern => typeof pattern === 'string' ? pattern === id : pattern.test(id)) +} + +describe('postcss tsdown config', () => { + it('externalizes ESM dependencies and bundles synchronous ESM-only CJS dependencies', () => { + const [esm, cjs] = createPostcssTsdownConfigs() + + expect(esm.format).toEqual(['esm']) + expect(esm.clean).toBe(true) + expect(esm.dts).toBe(false) + expect(esm.deps?.neverBundle).toBe(postcssEsmOnlyDependencies) + expect(cjs.format).toEqual(['cjs']) + expect(cjs.clean).toBe(false) + expect(cjs.dts).toBe(false) + expect(cjs.deps?.alwaysBundle).toBe(postcssEsmOnlyDependencies) + expect(matchesDependency(postcssEsmOnlyDependencies, '@csstools/css-color-parser')).toBe(true) + expect(matchesDependency(postcssEsmOnlyDependencies, 'postcss-preset-env')).toBe(true) + }) + + it('emits .js/.cjs and disables clean while watching', () => { + const [esm] = createPostcssTsdownConfigs() + + expect(esm.outExtensions?.({ format: 'es' } as never).js).toBe('.js') + expect(esm.outExtensions?.({ format: 'cjs' } as never).js).toBe('.cjs') + expect(createPostcssTsdownConfigs({ watch: true }).every(config => config.clean === false)).toBe(true) + }) +}) diff --git a/packages/postcss/tsdown.config.mts b/packages/postcss/tsdown.config.mts index 56467a2091..aba85ba286 100644 --- a/packages/postcss/tsdown.config.mts +++ b/packages/postcss/tsdown.config.mts @@ -1,28 +1,54 @@ import { defineConfig } from 'tsdown' -export default defineConfig({ +interface WatchAwareOptions { + watch?: boolean | string | Array +} + +export const postcssEsmOnlyDependencies = [ + /^@csstools\//, + 'css-blank-pseudo', + 'css-has-pseudo', + 'css-prefers-color-scheme', + 'postcss-selector-parser', + 'postcss-preset-env', +] + +const sharedOptions = { entry: ['src/index.ts', 'src/types.ts', 'src/html-transform.ts', 'src/css-macro/postcss.ts'], shims: true, - format: ['cjs', 'esm'], - deps: { - alwaysBundle: [ - /^@csstools\//, - 'css-blank-pseudo', - 'css-has-pseudo', - 'css-prefers-color-scheme', - 'postcss-selector-parser', - 'postcss-preset-env', - ], - }, - clean: true, dts: false, outputOptions: { minifyInternalExports: false, }, - outExtensions({ format }) { + outExtensions({ format }: { format: string }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, -}) +} + +export function createPostcssTsdownConfigs(options: WatchAwareOptions = {}) { + return [ + { + ...sharedOptions, + format: ['esm'], + clean: !options.watch, + deps: { + neverBundle: postcssEsmOnlyDependencies, + onlyBundle: false, + }, + }, + { + ...sharedOptions, + format: ['cjs'], + clean: false, + deps: { + alwaysBundle: postcssEsmOnlyDependencies, + onlyBundle: false, + }, + }, + ] +} + +export default defineConfig((options = {}) => createPostcssTsdownConfigs(options)) diff --git a/packages/reset/package.json b/packages/reset/package.json index 13597c6f35..ed0feb26dc 100644 --- a/packages/reset/package.json +++ b/packages/reset/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/reset", + "type": "module", "version": "0.1.1", "description": "weapp-tailwindcss 的静态 reset 样式资源集合", "author": "ice breaker <1324318532@qq.com>", @@ -26,14 +27,14 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", + "import": "./dist/index.js", "require": "./dist/index.cjs" }, "./*": "./*", "./package.json": "./package.json" }, "main": "./dist/index.cjs", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ "README.md", diff --git a/packages/reset/tsdown.config.mts b/packages/reset/tsdown.config.mts index b746ed035b..bafb34681f 100644 --- a/packages/reset/tsdown.config.mts +++ b/packages/reset/tsdown.config.mts @@ -12,7 +12,7 @@ export default defineConfig({ target: ['es2020'], outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.cjs', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/shared/package.json b/packages/shared/package.json index 974fa21b73..c97fa16dd0 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,5 +1,6 @@ { "name": "@weapp-tailwindcss/shared", + "type": "module", "version": "2.0.0", "description": "@weapp-tailwindcss/shared", "author": "ice breaker <1324318532@qq.com>", @@ -17,22 +18,22 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" }, "./extractors": { "types": "./dist/extractors.d.ts", - "import": "./dist/extractors.mjs", - "require": "./dist/extractors.js" + "import": "./dist/extractors.js", + "require": "./dist/extractors.cjs" }, "./node": { "types": "./dist/node.d.ts", - "import": "./dist/node.mjs", - "require": "./dist/node.js" + "import": "./dist/node.js", + "require": "./dist/node.cjs" } }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ "dist" @@ -53,9 +54,7 @@ "dependencies": { "defu": "^6.1.7", "get-value": "^4.1.0", + "pathe": "^2.0.3", "set-value": "^4.1.0" - }, - "devDependencies": { - "pathe": "^2.0.3" } } diff --git a/packages/shared/tsdown.config.mts b/packages/shared/tsdown.config.mts index f227bf804f..c928cfa200 100644 --- a/packages/shared/tsdown.config.mts +++ b/packages/shared/tsdown.config.mts @@ -11,11 +11,11 @@ export default defineConfig({ clean: true, dts: true, deps: { - alwaysBundle: ['pathe'], + onlyBundle: false, }, outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/tailwindcss-config/package.json b/packages/tailwindcss-config/package.json index b91ba02153..ef6c1cfaf1 100644 --- a/packages/tailwindcss-config/package.json +++ b/packages/tailwindcss-config/package.json @@ -61,9 +61,7 @@ }, "dependencies": { "@weapp-tailwindcss/shared": "workspace:*", - "jiti": "2.7.0" - }, - "devDependencies": { + "jiti": "2.7.0", "lilconfig": "^3.1.3" } } diff --git a/packages/tailwindcss-config/tsdown.config.ts b/packages/tailwindcss-config/tsdown.config.ts index 8d31da0c12..736bf2625e 100644 --- a/packages/tailwindcss-config/tsdown.config.ts +++ b/packages/tailwindcss-config/tsdown.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ clean: true, dts: false, deps: { - alwaysBundle: ['lilconfig'], + onlyBundle: false, }, target: ['es2020'], outExtensions({ format }) { diff --git a/packages/weapp-style-injector/package.json b/packages/weapp-style-injector/package.json index 10bc8e509e..bae9ddd85b 100644 --- a/packages/weapp-style-injector/package.json +++ b/packages/weapp-style-injector/package.json @@ -1,5 +1,6 @@ { "name": "weapp-style-injector", + "type": "module", "version": "1.0.1", "description": "weapp-style-injector", "author": "ice breaker <1324318532@qq.com>", @@ -17,47 +18,47 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", + "import": "./dist/index.js", "require": "./dist/index.cjs" }, "./vite": { "types": "./dist/vite.d.ts", - "import": "./dist/vite.mjs", + "import": "./dist/vite.js", "require": "./dist/vite.cjs" }, "./vite/uni-app": { "types": "./dist/vite/uni-app.d.ts", - "import": "./dist/vite/uni-app.mjs", + "import": "./dist/vite/uni-app.js", "require": "./dist/vite/uni-app.cjs" }, "./vite/taro": { "types": "./dist/vite/taro.d.ts", - "import": "./dist/vite/taro.mjs", + "import": "./dist/vite/taro.js", "require": "./dist/vite/taro.cjs" }, "./webpack": { "types": "./dist/webpack.d.ts", - "import": "./dist/webpack.mjs", + "import": "./dist/webpack.js", "require": "./dist/webpack.cjs" }, "./webpack/uni-app": { "types": "./dist/webpack/uni-app.d.ts", - "import": "./dist/webpack/uni-app.mjs", + "import": "./dist/webpack/uni-app.js", "require": "./dist/webpack/uni-app.cjs" }, "./webpack/taro": { "types": "./dist/webpack/taro.d.ts", - "import": "./dist/webpack/taro.mjs", + "import": "./dist/webpack/taro.js", "require": "./dist/webpack/taro.cjs" }, "./webpack/mpx": { "types": "./dist/webpack/mpx.d.ts", - "import": "./dist/webpack/mpx.mjs", + "import": "./dist/webpack/mpx.js", "require": "./dist/webpack/mpx.cjs" } }, "main": "./dist/index.cjs", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "files": [ "dist" @@ -67,8 +68,8 @@ }, "scripts": { "dev": "tsdown --watch --sourcemap", - "build": "tsdown && tsc -p tsconfig.build.json", - "build:types": "tsc -p tsconfig.build.json", + "build": "tsdown && tsc -p tsconfig.build.json && tsx ../../tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts .", + "build:types": "tsc -p tsconfig.build.json && tsx ../../tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts .", "test": "vitest run", "test:dev": "vitest", "release": "pnpm publish", diff --git a/packages/weapp-style-injector/tsdown.config.mts b/packages/weapp-style-injector/tsdown.config.mts index 9fdaf10ee9..8cc08be555 100644 --- a/packages/weapp-style-injector/tsdown.config.mts +++ b/packages/weapp-style-injector/tsdown.config.mts @@ -20,7 +20,7 @@ export default defineConfig({ }, outExtensions({ format }) { return { - js: format === 'es' ? '.mjs' : '.cjs', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } }, diff --git a/packages/weapp-tailwindcss/bin/weapp-tailwindcss.js b/packages/weapp-tailwindcss/bin/weapp-tailwindcss.cjs similarity index 69% rename from packages/weapp-tailwindcss/bin/weapp-tailwindcss.js rename to packages/weapp-tailwindcss/bin/weapp-tailwindcss.cjs index 4374bdf863..f82195e242 100755 --- a/packages/weapp-tailwindcss/bin/weapp-tailwindcss.js +++ b/packages/weapp-tailwindcss/bin/weapp-tailwindcss.cjs @@ -2,7 +2,7 @@ const fs = require('node:fs') const path = require('node:path') -const cliPath = path.resolve(__dirname, '../dist/cli.js') +const cliPath = path.resolve(__dirname, '../dist/cli.cjs') if (fs.existsSync(cliPath)) { require(cliPath) } diff --git a/packages/weapp-tailwindcss/package.json b/packages/weapp-tailwindcss/package.json index 974980736a..d895a4bc93 100644 --- a/packages/weapp-tailwindcss/package.json +++ b/packages/weapp-tailwindcss/package.json @@ -1,5 +1,6 @@ { "name": "weapp-tailwindcss", + "type": "module", "version": "5.1.16", "description": "把 tailwindcss 原子化样式思想,带给小程序开发者们! bring tailwindcss to miniprogram developers!", "author": "ice breaker <1324318532@qq.com>", @@ -42,88 +43,88 @@ ".": { "style": "./index.css", "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" + "import": "./dist/index.js", + "require": "./dist/index.cjs" }, "./escape": { "types": "./dist/escape.d.ts", - "import": "./dist/escape.mjs", - "require": "./dist/escape.js" + "import": "./dist/escape.js", + "require": "./dist/escape.cjs" }, "./vite": { "types": "./dist/vite.d.ts", - "import": "./dist/vite.mjs", - "require": "./dist/vite.js" + "import": "./dist/vite.js", + "require": "./dist/vite.cjs" }, "./webpack": { "types": "./dist/webpack.d.ts", - "import": "./dist/webpack.mjs", - "require": "./dist/webpack.js" + "import": "./dist/webpack.js", + "require": "./dist/webpack.cjs" }, "./rspack": { "types": "./dist/rspack.d.ts", - "import": "./dist/rspack.mjs", - "require": "./dist/rspack.js" + "import": "./dist/rspack.js", + "require": "./dist/rspack.cjs" }, "./core": { "types": "./dist/core.d.ts", - "import": "./dist/core.mjs", - "require": "./dist/core.js" + "import": "./dist/core.js", + "require": "./dist/core.cjs" }, "./gulp": { "types": "./dist/gulp.d.ts", - "import": "./dist/gulp.mjs", - "require": "./dist/gulp.js" + "import": "./dist/gulp.js", + "require": "./dist/gulp.cjs" }, "./generator": { "types": "./dist/generator.d.ts", - "import": "./dist/generator.mjs", - "require": "./dist/generator.js" + "import": "./dist/generator.js", + "require": "./dist/generator.cjs" }, "./postcss": { "types": "./dist/postcss.d.ts", - "import": "./dist/postcss.mjs", - "require": "./dist/postcss.js" + "import": "./dist/postcss.js", + "require": "./dist/postcss.cjs" }, "./defaults": { "types": "./dist/defaults.d.ts", - "import": "./dist/defaults.mjs", - "require": "./dist/defaults.js" + "import": "./dist/defaults.js", + "require": "./dist/defaults.cjs" }, "./framework": { "types": "./dist/framework.d.ts", - "import": "./dist/framework.mjs", - "require": "./dist/framework.js" + "import": "./dist/framework.js", + "require": "./dist/framework.cjs" }, "./presets": { "types": "./dist/presets.d.ts", - "import": "./dist/presets.mjs", - "require": "./dist/presets.js" + "import": "./dist/presets.js", + "require": "./dist/presets.cjs" }, "./reset": { "types": "./dist/reset.d.ts", - "import": "./dist/reset.mjs", - "require": "./dist/reset.js" + "import": "./dist/reset.js", + "require": "./dist/reset.cjs" }, "./css-macro/postcss": { "types": "./dist/css-macro/postcss.d.ts", - "import": "./dist/css-macro/postcss.mjs", - "require": "./dist/css-macro/postcss.js" + "import": "./dist/css-macro/postcss.js", + "require": "./dist/css-macro/postcss.cjs" }, "./css-macro": { "types": "./dist/css-macro.d.ts", - "import": "./dist/css-macro.mjs", - "require": "./dist/css-macro.js" + "import": "./dist/css-macro.js", + "require": "./dist/css-macro.cjs" }, "./types": { "types": "./dist/types.d.ts", - "import": "./dist/types.mjs", - "require": "./dist/types.js" + "import": "./dist/types.js", + "require": "./dist/types.cjs" }, "./postcss-html-transform": { "types": "./dist/postcss-html-transform.d.ts", - "import": "./dist/postcss-html-transform.mjs", - "require": "./dist/postcss-html-transform.js" + "import": "./dist/postcss-html-transform.js", + "require": "./dist/postcss-html-transform.cjs" }, "./package.json": "./package.json", "./index.css": "./index.css", @@ -141,8 +142,8 @@ "./css": "./css/index.css", "./*": "./*" }, - "main": "./dist/index.js", - "module": "./dist/index.mjs", + "main": "./dist/index.cjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "style": "index.css", "typesVersions": { @@ -154,8 +155,8 @@ } }, "bin": { - "weapp-tailwindcss": "bin/weapp-tailwindcss.js", - "weapp-tw": "bin/weapp-tailwindcss.js" + "weapp-tailwindcss": "bin/weapp-tailwindcss.cjs", + "weapp-tw": "bin/weapp-tailwindcss.cjs" }, "files": [ "bin", @@ -170,7 +171,7 @@ "with-layer.css" ], "engines": { - "node": ">=22.12.0" + "node": "^22.18.0 || >=24.11.0" }, "scripts": { "dev": "tsdown --watch --sourcemap", @@ -224,9 +225,9 @@ } }, "dependencies": { - "@babel/parser": "~7.29.7", - "@babel/traverse": "~7.29.7", - "@babel/types": "~7.29.7", + "@babel/parser": "catalog:babel8", + "@babel/traverse": "catalog:babel8", + "@babel/types": "catalog:babel8", "@tailwindcss-mangle/engine": "catalog:tailwindcssMangleEngine", "@vue/compiler-dom": "catalog:vue3", "@weapp-core/escape": "~8.0.0", @@ -237,6 +238,7 @@ "comment-json": "^5.0.0", "debug": "~4.4.3", "fast-glob": "^3.3.3", + "htmlparser2": "12.0.0", "local-pkg": "^1.2.1", "lru-cache": "11.5.2", "magic-string": "1.0.0", @@ -248,7 +250,6 @@ }, "devDependencies": { "@mpxjs/webpack-plugin": "^2.11.0", - "htmlparser2": "12.0.0", "webpack": "5.105.4" } } diff --git a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-loaders.ts b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-loaders.ts index 844d9e2425..dcefe8d997 100644 --- a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-loaders.ts +++ b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-loaders.ts @@ -86,7 +86,7 @@ export function setupWebpackV5Loaders(options: SetupWebpackV5LoadersOptions) { } const runtimeClassSetLoader = runtimeLoaderPath - ?? path.resolve(__dirname, './weapp-tw-runtime-classset-loader.js') + ?? path.resolve(__dirname, './weapp-tw-runtime-classset-loader.cjs') const shouldInjectRuntimeClassSetLoader = !generatorBranch.isWeb const shouldInjectCssGenerationLoader = generatorOptions.enabled && runtimeState.tailwindRuntime.majorVersion === 4 @@ -94,10 +94,10 @@ export function setupWebpackV5Loaders(options: SetupWebpackV5LoadersOptions) { const shouldInjectCssImportRewriteLoader = shouldRewriteCssImports || shouldInjectCssGenerationLoader const runtimeCssGenerationLoader = shouldInjectCssGenerationLoader - ? path.resolve(__dirname, './weapp-tw-css-generation-loader.js') + ? path.resolve(__dirname, './weapp-tw-css-generation-loader.cjs') : undefined const runtimeCssImportRewriteLoader = shouldInjectCssImportRewriteLoader - ? path.resolve(__dirname, './weapp-tw-css-import-rewrite-loader.js') + ? path.resolve(__dirname, './weapp-tw-css-import-rewrite-loader.cjs') : undefined const runtimeClassSetLoaderExists = fs.existsSync(runtimeClassSetLoader) const runtimeCssGenerationLoaderExists = runtimeCssGenerationLoader diff --git a/packages/weapp-tailwindcss/src/compiler/compilation-session-pool.ts b/packages/weapp-tailwindcss/src/compiler/compilation-session-pool.ts index 879050caa4..1361053f89 100644 --- a/packages/weapp-tailwindcss/src/compiler/compilation-session-pool.ts +++ b/packages/weapp-tailwindcss/src/compiler/compilation-session-pool.ts @@ -1,4 +1,4 @@ -import type { CompilationDependencyChange, CompilationScopeDependency, CompilationScopeSnapshotSource } from './compilation-scope-graph' +import type { CompilationDependencyChange, CompilationScopeDependency, CompilationScopeGraphSource, CompilationScopeSnapshotSource } from './compilation-scope-graph' import type { CompilationChange, CompilationResult, SourceKind, SourceScope } from './types' import { CompilationDependencyState } from './compilation-dependency-state' import { createCompilationScopeGraph, createCompilationScopeSnapshot, dependencyNodeId, dependencySignature, mergeCompilationScopeDependencies, sourceNodeId } from './compilation-scope-graph' diff --git a/packages/weapp-tailwindcss/src/constants.ts b/packages/weapp-tailwindcss/src/constants.ts index dc01c486f7..0eb85c9f6f 100644 --- a/packages/weapp-tailwindcss/src/constants.ts +++ b/packages/weapp-tailwindcss/src/constants.ts @@ -9,8 +9,8 @@ export const pluginName = 'weapp-tailwindcss' export const vitePluginName = 'weapp-tailwindcss:adaptor' -export const WEAPP_TW_REQUIRED_NODE_VERSION = '22.12.0' -export const WEAPP_TW_REQUIRED_NODE_VERSION_RANGE = '>=22.12.0' +export const WEAPP_TW_REQUIRED_NODE_VERSION = '22.18.0' +export const WEAPP_TW_REQUIRED_NODE_VERSION_RANGE = '^22.18.0 || >=24.11.0' export const WEAPP_TW_VERSION = pkg.version export const DEFAULT_RUNTIME_PACKAGE_REPLACEMENTS = { diff --git a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts index a5ba88d76d..245f00bd40 100644 --- a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts +++ b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts @@ -201,7 +201,7 @@ export interface UserDefinedOptionsGeneralPart { * @experimental * @remarks * 当前仅在调用侧关闭 source map,且没有模块图、模块替换、ignore 调用/标签模板语义时尝试 OXC。 - * `weapp-tailwindcss@5.2.0` 起要求 Node `>=22.12.0`。OXC 加载失败时仍会自动回退到 Babel。 + * Babel 8 链路要求 Node `^22.18.0 || >=24.11.0`。OXC 加载失败时仍会自动回退到 Babel。 */ experimentalJsFastPath?: boolean | 'oxc' | undefined diff --git a/packages/weapp-tailwindcss/test/build/dts-module-specifiers.test.ts b/packages/weapp-tailwindcss/test/build/dts-module-specifiers.test.ts new file mode 100644 index 0000000000..5cb2ec77de --- /dev/null +++ b/packages/weapp-tailwindcss/test/build/dts-module-specifiers.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it } from 'vitest' +import { rewriteDeclarationModuleSpecifiers } from '../../../../tools/weapp-tailwindcss-scripts/src/dts-module-specifiers' + +describe('declaration module specifiers', () => { + it('rewrites aliases and extensionless relative imports for type module packages', () => { + const content = [ + "import type { Foo } from '@/types/foo'", + "export * from './framework/index'", + "export type { Bar } from '../shared/bar.js'", + "type Lazy = import('./lazy').Lazy", + "export type { External } from 'external-package'", + ].join('\n') + + const declarationFiles = new Set([ + '/repo/packages/weapp-tailwindcss/dist/types/foo.d.ts', + '/repo/packages/weapp-tailwindcss/dist/nested/framework/index.d.ts', + '/repo/packages/weapp-tailwindcss/dist/nested/lazy.d.ts', + ]) + + expect(rewriteDeclarationModuleSpecifiers( + content, + '/repo/packages/weapp-tailwindcss/dist/nested/index.d.ts', + '/repo/packages/weapp-tailwindcss/dist', + declarationFiles, + )).toBe([ + "import type { Foo } from '../types/foo.js'", + "export * from './framework/index.js'", + "export type { Bar } from '../shared/bar.js'", + "type Lazy = import('./lazy.js').Lazy", + "export type { External } from 'external-package'", + ].join('\n')) + }) + + it('uses the matching runtime extension for declaration module kinds', () => { + expect(rewriteDeclarationModuleSpecifiers( + "export * from './entry'", + '/repo/dist/index.d.cts', + '/repo/dist', + )).toBe("export * from './entry.cjs'") + expect(rewriteDeclarationModuleSpecifiers( + "export * from './entry'", + '/repo/dist/index.d.mts', + '/repo/dist', + )).toBe("export * from './entry.mjs'") + }) + + it('resolves directory and parent entry declarations', () => { + const declarationFiles = new Set([ + '/repo/dist/index.d.ts', + '/repo/dist/compiler/index.d.ts', + '/repo/dist/runtime/index.d.cts', + ]) + const content = [ + "export type { Root } from '../..'", + "export type { Compiler } from '../../compiler'", + "export type { Runtime } from '../../runtime'", + ].join('\n') + + expect(rewriteDeclarationModuleSpecifiers( + content, + '/repo/dist/bundlers/gulp/index.d.ts', + '/repo/dist', + declarationFiles, + )).toBe([ + "export type { Root } from '../../index.js'", + "export type { Compiler } from '../../compiler/index.js'", + "export type { Runtime } from '../../runtime/index.cjs'", + ].join('\n')) + }) +}) diff --git a/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts b/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts index a7874f8126..2d78ffd5e4 100644 --- a/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts +++ b/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts @@ -1,25 +1,32 @@ import { describe, expect, it } from 'vitest' import tsconfigBuild from '../../tsconfig.build.json' with { type: 'json' } import { + bundleCjsRuntimeDeps, cliEntries, createTsdownConfigs, + externalizeEsmRuntimeDeps, + moduleOutExtensions, runtimeEntries, } from '../../tsdown.shared.mts' describe('tsdown build layout', () => { it('separates cli entry from runtime entries to avoid shared chunk pollution', () => { const configs = createTsdownConfigs() - const runtimeConfig = configs[0] - const cliConfig = configs[1] + const runtimeEsmConfig = configs[0] + const runtimeCjsConfig = configs[1] + const cliEsmConfig = configs[2] + const cliCjsConfig = configs[3] - expect(runtimeConfig.entry).toEqual(runtimeEntries) - expect(runtimeConfig.entry).not.toHaveProperty('cli') - expect(runtimeConfig.entry).toHaveProperty('framework') - expect(runtimeConfig.entry).toHaveProperty('generator') - expect(runtimeConfig.entry).toHaveProperty('postcss') + expect(runtimeEsmConfig.entry).toEqual(runtimeEntries) + expect(runtimeCjsConfig.entry).toEqual(runtimeEntries) + expect(runtimeEsmConfig.entry).not.toHaveProperty('cli') + expect(runtimeEsmConfig.entry).toHaveProperty('framework') + expect(runtimeEsmConfig.entry).toHaveProperty('generator') + expect(runtimeEsmConfig.entry).toHaveProperty('postcss') - expect(cliConfig.entry).toEqual(cliEntries) - expect(Object.keys(cliConfig.entry)).toEqual(['cli']) + expect(cliEsmConfig.entry).toEqual(cliEntries) + expect(cliCjsConfig.entry).toEqual(cliEntries) + expect(Object.keys(cliEsmConfig.entry)).toEqual(['cli']) }) it('keeps runtime config as the only cleanable build during non-watch runs', () => { @@ -35,21 +42,48 @@ describe('tsdown build layout', () => { expect(configs.every(config => config.clean === false)).toBe(true) }) - it('bundles uni-app x template compiler deps while keeping shared runtime deps external', () => { + it('uses module-safe extensions and keeps webpack loaders as physical cjs files', () => { const configs = createTsdownConfigs() - const runtimeConfig = configs[0] - const alwaysBundle = runtimeConfig.deps?.alwaysBundle - const neverBundle = runtimeConfig.deps?.neverBundle + const loaderConfig = configs[5] - expect(typeof alwaysBundle).toBe('function') - expect(typeof neverBundle).toBe('function') + expect(configs[0].format).toEqual(['esm']) + expect(configs[1].format).toEqual(['cjs']) + expect(configs[2].format).toEqual(['esm']) + expect(configs[3].format).toEqual(['cjs']) + expect(loaderConfig.format).toEqual(['cjs']) + expect(loaderConfig.deps?.alwaysBundle).toBe(bundleCjsRuntimeDeps) + expect(moduleOutExtensions({ format: 'es' }).js).toBe('.js') + expect(moduleOutExtensions({ format: 'cjs' }).js).toBe('.cjs') + }) + + it('externalizes ESM dependencies and only bundles ESM-only graphs into CJS', () => { + const configs = createTsdownConfigs() + const runtimeEsmConfig = configs[0] + const runtimeCjsConfig = configs[1] + const esmNeverBundle = runtimeEsmConfig.deps?.neverBundle + const cjsAlwaysBundle = runtimeCjsConfig.deps?.alwaysBundle + const cjsNeverBundle = runtimeCjsConfig.deps?.neverBundle + + expect(typeof esmNeverBundle).toBe('function') + expect(typeof cjsAlwaysBundle).toBe('function') + expect(typeof cjsNeverBundle).toBe('function') - expect(alwaysBundle?.('@vue/compiler-dom', undefined)).toBe(true) - expect(alwaysBundle?.('@vue/shared', undefined)).toBe(true) - expect(neverBundle?.('@vue/compiler-dom')).toBe(false) - expect(neverBundle?.('postcss')).toBe(true) - expect(neverBundle?.('webpack')).toBe(true) - expect(runtimeConfig.deps?.onlyBundle).toBe(false) + expect(bundleCjsRuntimeDeps('@babel/parser')).toBe(true) + expect(bundleCjsRuntimeDeps('@babel/traverse')).toBe(true) + expect(bundleCjsRuntimeDeps('obug')).toBe(true) + expect(bundleCjsRuntimeDeps('htmlparser2')).toBe(true) + expect(bundleCjsRuntimeDeps('magic-string')).toBe(true) + expect(bundleCjsRuntimeDeps('@vue/compiler-dom')).toBe(false) + expect(externalizeEsmRuntimeDeps('@vue/compiler-dom')).toBe(true) + expect(esmNeverBundle?.('@babel/types')).toBe(true) + expect(cjsAlwaysBundle?.('@babel/types', undefined)).toBe(true) + expect(cjsAlwaysBundle?.('htmlparser2', undefined)).toBe(true) + expect(cjsAlwaysBundle?.('magic-string', undefined)).toBe(true) + expect(cjsAlwaysBundle?.('@vue/compiler-dom', undefined)).toBe(false) + expect(cjsNeverBundle?.('@vue/compiler-dom')).toBe(true) + expect(cjsNeverBundle?.('postcss')).toBe(true) + expect(cjsNeverBundle?.('webpack')).toBe(true) + expect(runtimeCjsConfig.deps?.onlyBundle).toBe(false) }) it('keeps declaration builds from emitting workspace dependency dts into source folders', () => { diff --git a/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts index b9b6c40540..97d46d1bd6 100644 --- a/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts @@ -27,7 +27,7 @@ describe('bundlers/rspack patchRspackConfig', () => { patchRspackConfig(config, { cssImportRewriteLoader: { - loader: '/virtual/weapp-tw-css-import-rewrite-loader.js', + loader: '/virtual/weapp-tw-css-import-rewrite-loader.cjs', }, }) @@ -35,7 +35,7 @@ describe('bundlers/rspack patchRspackConfig', () => { 'css-extract-loader', 'css-loader', 'builtin:lightningcss-loader', - '/virtual/weapp-tw-css-import-rewrite-loader.js', + '/virtual/weapp-tw-css-import-rewrite-loader.cjs', ]) }) @@ -75,7 +75,7 @@ describe('bundlers/rspack patchRspackConfig', () => { use: [ { loader: 'css-loader' }, { - loader: '/virtual/weapp-tw-css-import-rewrite-loader.js', + loader: '/virtual/weapp-tw-css-import-rewrite-loader.cjs', options: { tailwindcssImportRewriteRuntimeKey: 'legacy', }, @@ -94,7 +94,7 @@ describe('bundlers/rspack patchRspackConfig', () => { expect(getUseLoaders(config)).toEqual([ 'css-loader', 'builtin:lightningcss-loader', - '/virtual/weapp-tw-css-import-rewrite-loader.js', + '/virtual/weapp-tw-css-import-rewrite-loader.cjs', ]) }) diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5-runtime-metadata.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5-runtime-metadata.unit.test.ts index 2ddc56f254..c5f7659269 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5-runtime-metadata.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5-runtime-metadata.unit.test.ts @@ -99,8 +99,8 @@ function createContext(): TestContext { htmlMatcher: (file: string) => file.endsWith('.wxml'), jsMatcher: (file: string) => file.endsWith('.js'), wxsMatcher: () => false, - runtimeLoaderPath: '/virtual/weapp-tw-runtime-classset-loader.js', - runtimeCssImportRewriteLoaderPath: '/virtual/weapp-tw-css-import-rewrite-loader.js', + runtimeLoaderPath: '/virtual/weapp-tw-runtime-classset-loader.cjs', + runtimeCssImportRewriteLoaderPath: '/virtual/weapp-tw-css-import-rewrite-loader.cjs', } } diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/shared.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/shared.ts index ac2c05cfae..713f45a91b 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/shared.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/shared.ts @@ -52,15 +52,15 @@ export interface LoaderModule { export const CSS_IMPORT_REWRITE_LOADER_PATH = path.resolve( __dirname, - '../../../src/bundlers/webpack/BaseUnifiedPlugin/weapp-tw-css-import-rewrite-loader.js', + '../../../src/bundlers/webpack/BaseUnifiedPlugin/weapp-tw-css-import-rewrite-loader.cjs', ) export function isCssImportRewriteLoader(entry: { loader?: string }) { - return entry.loader?.includes('weapp-tw-css-import-rewrite-loader.js') ?? false + return entry.loader?.includes('weapp-tw-css-import-rewrite-loader.cjs') ?? false } export function isCssGenerationLoader(entry: { loader?: string }) { - return entry.loader?.includes('weapp-tw-css-generation-loader.js') ?? false + return entry.loader?.includes('weapp-tw-css-generation-loader.cjs') ?? false } interface TestContext { @@ -135,7 +135,7 @@ export function createContext(overrides: Partial = {}): TestContext htmlMatcher: (file: string) => file.endsWith('.wxml'), jsMatcher: (file: string) => file.endsWith('.js'), wxsMatcher: (_file: string) => false, - runtimeLoaderPath: '/virtual/weapp-tw-runtime-classset-loader.js', + runtimeLoaderPath: '/virtual/weapp-tw-runtime-classset-loader.cjs', appType: overrides.appType, ...overrides, } diff --git a/packages/weapp-tailwindcss/test/ci/package-module-exports.test.ts b/packages/weapp-tailwindcss/test/ci/package-module-exports.test.ts new file mode 100644 index 0000000000..e34ba6b05f --- /dev/null +++ b/packages/weapp-tailwindcss/test/ci/package-module-exports.test.ts @@ -0,0 +1,102 @@ +import { readdir, readFile } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { describe, expect, it } from 'vitest' + +interface PackageJson { + name: string + type?: string + main?: string + module?: string + devDependencies?: Record + exports?: Record + publishConfig?: { + exports?: Record + } +} + +const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url)) +const packageRoots = ['packages', 'packages-runtime'] +const migratedPackages = new Set([ + '@weapp-tailwindcss/babel', + '@weapp-tailwindcss/debug-uni-app-x', + '@weapp-tailwindcss/init', + '@weapp-tailwindcss/logger', + '@weapp-tailwindcss/postcss', + '@weapp-tailwindcss/reset', + '@weapp-tailwindcss/shared', + '@weapp-tailwindcss/typography', + 'weapp-style-injector', + 'weapp-tailwindcss', +]) + +async function readWorkspacePackages() { + const packages: PackageJson[] = [] + for (const root of packageRoots) { + const directory = path.join(repoRoot, root) + for (const entry of await readdir(directory, { withFileTypes: true })) { + if (!entry.isDirectory()) { + continue + } + const packageJsonPath = path.join(directory, entry.name, 'package.json') + packages.push(JSON.parse(await readFile(packageJsonPath, 'utf8')) as PackageJson) + } + } + return packages +} + +function expectModuleExtensions(exports: Record) { + for (const target of Object.values(exports)) { + if (!target || typeof target !== 'object' || Array.isArray(target)) { + continue + } + const conditions = target as Record + if (typeof conditions.import === 'string') { + expect(conditions.import).toMatch(/\.js$/) + } + if (typeof conditions.require === 'string') { + expect(conditions.require).toMatch(/\.cjs$/) + } + } +} + +describe('package module metadata', () => { + it('keeps Babel 7 framework loaders isolated from the root Babel 8 toolchain', async () => { + const rootPackage = JSON.parse( + await readFile(path.join(repoRoot, 'package.json'), 'utf8'), + ) as PackageJson + const mpxPackage = JSON.parse( + await readFile(path.join(repoRoot, 'demo/mpx-tailwindcss-v4/package.json'), 'utf8'), + ) as PackageJson + + expect(rootPackage.devDependencies?.['@babel/core']).toBe('catalog:babel8') + expect(rootPackage.devDependencies?.['babel-loader']).toBeUndefined() + expect(mpxPackage.devDependencies?.['@babel/core']).toBe('catalog:babelCore7285') + }) + + it('declares type module for every package workspace', async () => { + const packages = await readWorkspacePackages() + + expect(packages.length).toBeGreaterThan(0) + expect(packages.filter(pkg => pkg.type !== 'module').map(pkg => pkg.name)).toEqual([]) + }) + + it('uses physical .js/.cjs files for migrated dual packages', async () => { + const packages = await readWorkspacePackages() + const migrated = packages.filter(pkg => migratedPackages.has(pkg.name)) + + expect(migrated.map(pkg => pkg.name).sort()).toEqual([...migratedPackages].sort()) + for (const pkg of migrated) { + const publishExports = pkg.publishConfig?.exports + const exports = publishExports ?? pkg.exports + expect(exports, pkg.name).toBeDefined() + expectModuleExtensions(exports ?? {}) + if (pkg.main) { + expect(pkg.main, pkg.name).toMatch(/\.cjs$/) + } + if (pkg.module) { + expect(pkg.module, pkg.name).toMatch(/\.js$/) + } + } + }) +}) diff --git a/packages/weapp-tailwindcss/test/cli/doctor.test.ts b/packages/weapp-tailwindcss/test/cli/doctor.test.ts index bd4dfdf320..d6c7c0a7fb 100644 --- a/packages/weapp-tailwindcss/test/cli/doctor.test.ts +++ b/packages/weapp-tailwindcss/test/cli/doctor.test.ts @@ -53,7 +53,7 @@ describe('createDoctorReport', () => { await writePackage(root, 'tailwindcss', '4.1.0') await writePackage(root, 'weapp-tailwindcss', '4.12.0') - const report = createDoctorReport({ cwd: root, nodeVersion: '22.12.0' }) + const report = createDoctorReport({ cwd: root, nodeVersion: '22.18.0' }) expect(report.detected.packageManager).toBe('pnpm@11.5.0') expect(report.detected.frameworks).toEqual(['uni-app']) @@ -73,7 +73,7 @@ describe('createDoctorReport', () => { await writeFile(path.join(root, 'postcss.config.cjs'), 'module.exports = {}\n', 'utf8') await writePackage(root, 'tailwindcss', '4.0.0') - const report = createDoctorReport({ cwd: root, nodeVersion: '22.12.0' }) + const report = createDoctorReport({ cwd: root, nodeVersion: '22.18.0' }) const check = findCheck(report, 'tailwindcss-v4-postcss') expect(check.status).toBe('warn') @@ -108,11 +108,19 @@ describe('createDoctorReport', () => { 'node-version', ).status).toBe('error') expect(findCheck( - createDoctorReport({ cwd: root, nodeVersion: '22.11.0' }), + createDoctorReport({ cwd: root, nodeVersion: '22.17.0' }), 'node-version', ).status).toBe('error') expect(findCheck( - createDoctorReport({ cwd: root, nodeVersion: '22.12.0' }), + createDoctorReport({ cwd: root, nodeVersion: '22.18.0' }), + 'node-version', + ).status).toBe('ok') + expect(findCheck( + createDoctorReport({ cwd: root, nodeVersion: '24.10.0' }), + 'node-version', + ).status).toBe('error') + expect(findCheck( + createDoctorReport({ cwd: root, nodeVersion: '24.11.0' }), 'node-version', ).status).toBe('ok') }) diff --git a/packages/weapp-tailwindcss/test/js/babel-utils.test.ts b/packages/weapp-tailwindcss/test/js/babel-utils.test.ts index f5ac458e07..6ec83cff57 100644 --- a/packages/weapp-tailwindcss/test/js/babel-utils.test.ts +++ b/packages/weapp-tailwindcss/test/js/babel-utils.test.ts @@ -1,26 +1,23 @@ import type { NodePath } from '@babel/traverse' import type { CallExpression } from '@babel/types' -import * as parser from '@babel/parser' import { MappingChars2String } from '@weapp-core/escape' -import { afterEach, describe, expect, it, vi } from 'vitest' +import { afterEach, describe, expect, it } from 'vitest' import { parse, traverse } from '@/babel' import * as babel from '@/js/babel' describe('babel helpers additional coverage', () => { afterEach(() => { - vi.restoreAllMocks() babel.parseCache.clear() }) it('memoises parsed ASTs when parser caching is enabled', () => { const code = 'const value = 1' - const spy = vi.spyOn(parser, 'parse') const parserOptions = { sourceType: 'module' as const, cache: true } const first = babel.babelParse(code, parserOptions) const second = babel.babelParse(code, parserOptions) - expect(spy).toHaveBeenCalledTimes(1) expect(second).toBe(first) + expect(babel.parseCache.size).toBe(1) }) it('uses hashed parser cache keys instead of retaining source text in keys', () => { @@ -33,7 +30,6 @@ describe('babel helpers additional coverage', () => { it('skips parser caching for sources over the configured source length limit', () => { const code = 'const value = "text-red-500"' - const spy = vi.spyOn(parser, 'parse') const first = babel.babelParse(code, { sourceType: 'module' as const, cache: true, @@ -45,14 +41,11 @@ describe('babel helpers additional coverage', () => { cacheMaxSourceLength: code.length - 1, }) - expect(spy).toHaveBeenCalledTimes(2) expect(second).not.toBe(first) expect(babel.parseCache.size).toBe(0) }) it('trims parser cache entries to the configured entry limit', () => { - const spy = vi.spyOn(parser, 'parse') - const first = babel.babelParse('const first = 1', { sourceType: 'module' as const, cache: true, @@ -69,7 +62,6 @@ describe('babel helpers additional coverage', () => { cacheMaxEntries: 1, }) - expect(spy).toHaveBeenCalledTimes(3) expect(second).not.toBe(first) expect(third).not.toBe(first) expect(babel.parseCache.size).toBe(1) @@ -77,11 +69,9 @@ describe('babel helpers additional coverage', () => { it('does not retain parsed ASTs when parser caching is disabled', () => { const code = 'const value = 1' - const spy = vi.spyOn(parser, 'parse') const first = babel.babelParse(code, { sourceType: 'module' as const, cache: false }) const second = babel.babelParse(code, { sourceType: 'module' as const, cache: false }) - expect(spy).toHaveBeenCalledTimes(2) expect(second).not.toBe(first) expect(babel.parseCache.size).toBe(0) }) diff --git a/packages/weapp-tailwindcss/tsdown.shared.mts b/packages/weapp-tailwindcss/tsdown.shared.mts index e520957085..afa742f94a 100644 --- a/packages/weapp-tailwindcss/tsdown.shared.mts +++ b/packages/weapp-tailwindcss/tsdown.shared.mts @@ -37,27 +37,41 @@ export const webpackLoaderEntries = { 'weapp-tw-css-import-rewrite-loader': 'src/bundlers/webpack/loaders/weapp-tw-css-import-rewrite-loader.ts', } as const -function externalizeRuntimeDeps(id: string) { +function externalizeCommonRuntimeDeps(id: string) { return id === 'webpack' || id === 'tailwindcss/plugin' || id === 'postcss' + || id === '@vue/compiler-dom' + || id === '@vue/shared' || /[\\/]node_modules[\\/]\.pnpm[\\/]postcss@/.test(id) || /[\\/]node_modules[\\/]postcss[\\/]/.test(id) } -function alwaysBundleRuntimeDeps(id: string) { +function isBabelEsmOnlyDependency(id: string) { + return id === 'obug' || /^@babel(?:\/|$)/.test(id) +} + +function isHtmlparser2EsmOnlyDependency(id: string) { return id === 'htmlparser2' || id === 'domhandler' || id === 'domutils' || id === 'domelementtype' || id === 'entities' - || id === '@vue/compiler-dom' - || id === '@vue/shared' } -function preserveJsExports({ format }: { format: string }) { +export function bundleCjsRuntimeDeps(id: string) { + return id === 'magic-string' + || isBabelEsmOnlyDependency(id) + || isHtmlparser2EsmOnlyDependency(id) +} + +export function externalizeEsmRuntimeDeps(id: string) { + return externalizeCommonRuntimeDeps(id) || bundleCjsRuntimeDeps(id) +} + +export function moduleOutExtensions({ format }: { format: string }) { return { - js: format === 'es' ? '.mjs' : '.js', + js: format === 'es' ? '.js' : '.cjs', dts: '.d.ts', } } @@ -72,29 +86,55 @@ export function createTsdownConfigs(options: WatchAwareOptions = {}) { dts: false, clean: shouldClean, shims: true, - format: ['cjs', 'esm'], + format: ['esm'], deps: { - alwaysBundle: alwaysBundleRuntimeDeps, - neverBundle: externalizeRuntimeDeps, + neverBundle: externalizeEsmRuntimeDeps, onlyBundle: false, }, target: ['es2020'], - outExtensions: preserveJsExports, + outExtensions: moduleOutExtensions, }, { - // CLI 单独构建,避免未来引入 ESM-only 依赖时污染 runtime 入口共享 chunk。 + entry: runtimeEntries, + dts: false, + clean: false, + shims: true, + format: ['cjs'], + deps: { + alwaysBundle: bundleCjsRuntimeDeps, + neverBundle: externalizeCommonRuntimeDeps, + onlyBundle: false, + }, + target: ['es2020'], + outExtensions: moduleOutExtensions, + }, + { + // CLI 单独构建,避免依赖污染 runtime 入口共享 chunk。 entry: cliEntries, dts: false, clean: false, shims: true, - format: ['cjs', 'esm'], + format: ['esm'], deps: { - alwaysBundle: alwaysBundleRuntimeDeps, - neverBundle: externalizeRuntimeDeps, + neverBundle: externalizeEsmRuntimeDeps, onlyBundle: false, }, target: ['es2020'], - outExtensions: preserveJsExports, + outExtensions: moduleOutExtensions, + }, + { + entry: cliEntries, + dts: false, + clean: false, + shims: true, + format: ['cjs'], + deps: { + alwaysBundle: bundleCjsRuntimeDeps, + neverBundle: externalizeCommonRuntimeDeps, + onlyBundle: false, + }, + target: ['es2020'], + outExtensions: moduleOutExtensions, }, { entry: escapeEntries, @@ -104,7 +144,7 @@ export function createTsdownConfigs(options: WatchAwareOptions = {}) { shims: false, format: ['cjs', 'esm'], target: ['es2020'], - outExtensions: preserveJsExports, + outExtensions: moduleOutExtensions, }, { entry: webpackLoaderEntries, @@ -113,9 +153,11 @@ export function createTsdownConfigs(options: WatchAwareOptions = {}) { shims: true, format: ['cjs'], deps: { - neverBundle: ['webpack'], + alwaysBundle: bundleCjsRuntimeDeps, + neverBundle: externalizeCommonRuntimeDeps, + onlyBundle: false, }, - outExtensions: preserveJsExports, + outExtensions: moduleOutExtensions, }, ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32c87ba9f4..d0432be39c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,22 @@ catalogs: autoprefixer: specifier: ^10.5.4 version: 10.5.4 + babel8: + '@babel/core': + specifier: ^8.0.1 + version: 8.0.1 + '@babel/generator': + specifier: ^8.0.0 + version: 8.0.0 + '@babel/parser': + specifier: ^8.0.4 + version: 8.0.4 + '@babel/traverse': + specifier: ^8.0.4 + version: 8.0.4 + '@babel/types': + specifier: ^8.0.4 + version: 8.0.4 babelCore7285: '@babel/core': specifier: ^7.29.7 @@ -410,11 +426,11 @@ importers: specifier: ^2.3.0 version: 2.3.0 '@babel/core': - specifier: catalog:babelCore7285 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.1 '@babel/generator': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.0 '@changesets/changelog-github': specifier: ^0.7.0 version: 0.7.0(encoding@0.1.13) @@ -592,9 +608,6 @@ importers: autoprefixer: specifier: catalog:autoprefixer10 version: 10.5.4(postcss@8.5.20) - babel-loader: - specifier: ^10.1.1 - version: 10.1.1(@babel/core@7.29.7)(@rspack/core@2.1.4(@swc/helpers@0.5.23))(webpack@5.105.4(@swc/core@1.15.46(@swc/helpers@0.5.23))(clean-css@5.3.3)(esbuild@0.28.1)(html-minifier-terser@7.2.0)(lightningcss@1.32.0)(postcss@8.5.20)) boxen: specifier: ^8.0.1 version: 8.0.1 @@ -3821,15 +3834,15 @@ importers: packages-runtime/theme-transition: dependencies: + defu: + specifier: ^6.1.7 + version: 6.1.7 tailwindcss: specifier: '>=3 <5' version: 4.1.18 packages-runtime/typography: - devDependencies: - '@weapp-tailwindcss/test-helper': - specifier: workspace:* - version: link:../../packages/test-helper + dependencies: htmlparser2: specifier: ^12.0.0 version: 12.0.0 @@ -3848,6 +3861,10 @@ importers: postcss-selector-parser: specifier: ^7.1.4 version: 7.1.4 + devDependencies: + '@weapp-tailwindcss/test-helper': + specifier: workspace:* + version: link:../../packages/test-helper packages-runtime/ui: dependencies: @@ -3916,14 +3933,14 @@ importers: packages/babel: dependencies: '@babel/parser': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 '@babel/traverse': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 '@babel/types': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 packages/build-all: dependencies: @@ -3980,7 +3997,7 @@ importers: version: link:../wetw packages/debug-uni-app-x: - devDependencies: + dependencies: defu: specifier: 6.1.7 version: 6.1.7 @@ -3990,6 +4007,7 @@ importers: pathe: specifier: 2.0.3 version: 2.0.3 + devDependencies: vite: specifier: 7.2.7 version: 7.2.7(@types/node@26.1.1)(jiti@2.7.0)(less@4.6.6)(lightningcss@1.32.0)(sass-embedded@1.100.0)(sass@1.101.0)(stylus@0.63.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) @@ -4027,7 +4045,7 @@ importers: version: 2.0.3 packages/logger: - devDependencies: + dependencies: consola: specifier: ^3.4.2 version: 3.4.2 @@ -4043,6 +4061,15 @@ importers: packages/postcss: dependencies: + '@csstools/css-color-parser': + specifier: ^4.1.9 + version: 4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': + specifier: ^4.0.0 + version: 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': + specifier: ^4.0.0 + version: 4.0.0 '@tailwindcss-mangle/engine': specifier: catalog:tailwindcssMangleEngine version: 0.2.0(tailwindcss@4.3.3) @@ -4058,6 +4085,9 @@ importers: autoprefixer: specifier: catalog:autoprefixer10 version: 10.5.4(postcss@8.5.20) + es-toolkit: + specifier: ^1.49.0 + version: 1.49.0 lru-cache: specifier: 11.5.2 version: 11.5.2 @@ -4070,6 +4100,9 @@ importers: postcss-load-config: specifier: ^6.0.1 version: 6.0.1(jiti@2.7.0)(postcss@8.5.20)(tsx@4.23.1)(yaml@2.9.0) + postcss-preset-env: + specifier: ^11.3.2 + version: 11.3.2(postcss@8.5.20) postcss-pxtrans: specifier: ^1.0.4 version: 1.0.4(postcss@8.5.20) @@ -4089,15 +4122,6 @@ importers: specifier: workspace:* version: link:../tailwindcss-config devDependencies: - '@csstools/css-color-parser': - specifier: ^4.1.9 - version: 4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': - specifier: ^4.0.0 - version: 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': - specifier: ^4.0.0 - version: 4.0.0 '@csstools/postcss-is-pseudo-class': specifier: ^6.0.0 version: 6.0.0(postcss@8.5.20) @@ -4110,9 +4134,6 @@ importers: postcss-custom-properties: specifier: ^15.0.1 version: 15.0.1(postcss@8.5.20) - postcss-preset-env: - specifier: ^11.3.2 - version: 11.3.2(postcss@8.5.20) packages/postcss-calc: dependencies: @@ -4169,13 +4190,12 @@ importers: get-value: specifier: ^4.1.0 version: 4.1.0 - set-value: - specifier: ^4.1.0 - version: 4.1.0 - devDependencies: pathe: specifier: ^2.0.3 version: 2.0.3 + set-value: + specifier: ^4.1.0 + version: 4.1.0 packages/tailwindcss-config: dependencies: @@ -4185,7 +4205,6 @@ importers: jiti: specifier: 2.7.0 version: 2.7.0 - devDependencies: lilconfig: specifier: ^3.1.3 version: 3.1.3 @@ -4234,14 +4253,14 @@ importers: packages/weapp-tailwindcss: dependencies: '@babel/parser': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 '@babel/traverse': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 '@babel/types': - specifier: ~7.29.7 - version: 7.29.7 + specifier: catalog:babel8 + version: 8.0.4 '@tailwindcss-mangle/engine': specifier: catalog:tailwindcssMangleEngine version: 0.2.0(tailwindcss@4.3.3) @@ -4272,6 +4291,9 @@ importers: fast-glob: specifier: ^3.3.3 version: 3.3.3 + htmlparser2: + specifier: 12.0.0 + version: 12.0.0 local-pkg: specifier: ^1.2.1 version: 1.2.1 @@ -4300,9 +4322,6 @@ importers: '@mpxjs/webpack-plugin': specifier: ^2.11.0 version: 2.11.0(@mpxjs/core@2.11.0)(vue@2.7.16)(webpack@5.105.4(@swc/core@1.15.46(@swc/helpers@0.5.23))(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.20)) - htmlparser2: - specifier: 12.0.0 - version: 12.0.0 webpack: specifier: 5.105.4 version: 5.105.4(@swc/core@1.15.46(@swc/helpers@0.5.23))(cssnano@5.1.15(postcss@8.5.20))(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.20) @@ -5167,10 +5186,6 @@ packages: resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} @@ -32633,7 +32648,7 @@ snapshots: gensync: 1.0.0-beta.2 import-meta-resolve: 4.2.0 json5: 2.2.3 - obug: 2.1.3 + obug: 2.1.4 semver: 7.8.5 '@babel/eslint-parser@7.28.5(@babel/core@7.29.7)(eslint@10.7.0(jiti@2.7.0))': @@ -32651,14 +32666,6 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 2.5.2 - '@babel/generator@7.28.5': - dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - '@babel/generator@7.29.7': dependencies: '@babel/parser': 7.29.7 @@ -41389,7 +41396,7 @@ snapshots: agent-base: 9.0.0 http-proxy-agent: 9.0.0 https-proxy-agent: 9.0.0 - lru-cache: 11.5.1 + lru-cache: 11.5.2 socks-proxy-agent: 10.0.0 transitivePeerDependencies: - supports-color @@ -50747,14 +50754,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@10.1.1(@babel/core@7.29.7)(@rspack/core@2.1.4(@swc/helpers@0.5.23))(webpack@5.105.4(@swc/core@1.15.46(@swc/helpers@0.5.23))(clean-css@5.3.3)(esbuild@0.28.1)(html-minifier-terser@7.2.0)(lightningcss@1.32.0)(postcss@8.5.20)): - dependencies: - '@babel/core': 7.29.7 - find-up: 5.0.0 - optionalDependencies: - '@rspack/core': 2.1.4(@swc/helpers@0.5.23) - webpack: 5.105.4(@swc/core@1.15.46(@swc/helpers@0.5.23))(clean-css@5.3.3)(esbuild@0.28.1)(html-minifier-terser@7.2.0)(lightningcss@1.32.0)(postcss@8.5.20) - babel-loader@10.1.1(@babel/core@7.29.7)(@rspack/core@2.1.4(@swc/helpers@0.5.23))(webpack@5.105.4): dependencies: '@babel/core': 7.29.7 @@ -51640,7 +51639,7 @@ snapshots: '@npmcli/fs': 6.0.0 fs-minipass: 3.0.3 glob: 13.0.6 - lru-cache: 11.5.1 + lru-cache: 11.5.2 minipass: 7.1.3 minipass-collect: 2.0.1 minipass-flush: 1.0.7 @@ -57276,7 +57275,7 @@ snapshots: hosted-git-info@10.1.1: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 hosted-git-info@2.8.9: {} @@ -62448,12 +62447,12 @@ snapshots: path-scurry@2.0.1: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 minipass: 7.1.3 path-scurry@2.0.2: dependencies: - lru-cache: 11.5.1 + lru-cache: 11.5.2 minipass: 7.1.3 path-temp@2.0.0: @@ -68417,7 +68416,7 @@ snapshots: unplugin-vue-router@0.19.2(@vue/compiler-sfc@3.5.40)(vue-router@4.6.4(vue@3.5.40(typescript@6.0.3)))(vue@3.5.40(typescript@6.0.3)): dependencies: - '@babel/generator': 7.28.5 + '@babel/generator': 7.29.7 '@vue-macros/common': 3.1.1(vue@3.5.40(typescript@6.0.3)) '@vue/compiler-sfc': 3.5.40 '@vue/language-core': 3.2.1 @@ -68831,7 +68830,7 @@ snapshots: dependencies: cac: 6.7.14 es-module-lexer: 2.3.0 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(less@4.6.6)(lightningcss@1.32.0)(sass-embedded@1.100.0)(sass@1.101.0)(stylus@0.63.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) transitivePeerDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bfd9cb1445..a765f3a8cc 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -46,6 +46,12 @@ catalogs: autoprefixer: ^10.5.4 babelCore7285: '@babel/core': ^7.29.7 + babel8: + '@babel/core': ^8.0.1 + '@babel/generator': ^8.0.0 + '@babel/parser': ^8.0.4 + '@babel/traverse': ^8.0.4 + '@babel/types': ^8.0.4 babelPresetReact7285: '@babel/preset-react': ^7.29.7 babelRuntime7284: diff --git a/scripts/ensure-weapp-tailwindcss-built.mjs b/scripts/ensure-weapp-tailwindcss-built.mjs index 745e8e88a0..6946ed9a0f 100644 --- a/scripts/ensure-weapp-tailwindcss-built.mjs +++ b/scripts/ensure-weapp-tailwindcss-built.mjs @@ -59,7 +59,9 @@ const runtimeBuildTargets = [ packageRoot: path.join(repoRoot, 'packages-runtime/typography'), stamps: [ 'dist/index.js', - 'dist/index.mjs', + 'dist/index.cjs', + 'dist/transform.js', + 'dist/transform.cjs', 'dist/index.d.ts', ], }, @@ -71,9 +73,9 @@ const buildTargets = [ packageRoot: path.join(repoRoot, 'packages/shared'), stamps: [ 'dist/index.js', - 'dist/index.mjs', + 'dist/index.cjs', 'dist/node.js', - 'dist/node.mjs', + 'dist/node.cjs', ], }, { @@ -82,7 +84,7 @@ const buildTargets = [ packageRoot: path.join(repoRoot, 'packages/logger'), stamps: [ 'dist/index.js', - 'dist/index.mjs', + 'dist/index.cjs', 'dist/index.d.ts', ], }, @@ -92,7 +94,7 @@ const buildTargets = [ packageRoot: path.join(repoRoot, 'packages/postcss-calc'), stamps: [ 'dist/index.cjs', - 'dist/index.mjs', + 'dist/index.js', 'dist/index.d.ts', ], }, @@ -122,7 +124,7 @@ const buildTargets = [ packageRoot: path.join(repoRoot, 'packages/postcss'), stamps: [ 'dist/index.js', - 'dist/index.mjs', + 'dist/index.cjs', 'dist/index.d.ts', ], }, @@ -132,19 +134,38 @@ const buildTargets = [ packageRoot: path.join(repoRoot, 'packages/debug-uni-app-x'), stamps: [ 'dist/index.cjs', - 'dist/index.mjs', + 'dist/index.js', 'dist/index.d.ts', ], }, + { + filter: 'weapp-style-injector', + label: 'weapp-style-injector', + packageRoot: path.join(repoRoot, 'packages/weapp-style-injector'), + stamps: [ + 'dist/index.js', + 'dist/index.cjs', + 'dist/vite.js', + 'dist/vite.cjs', + 'dist/webpack.js', + 'dist/webpack.cjs', + ], + }, { filter: 'weapp-tailwindcss', label: '核心包', packageRoot: path.join(repoRoot, 'packages/weapp-tailwindcss'), stamps: [ 'dist/vite.js', + 'dist/vite.cjs', 'dist/webpack.js', + 'dist/webpack.cjs', 'dist/gulp.js', + 'dist/gulp.cjs', 'dist/index.js', + 'dist/index.cjs', + 'dist/cli.cjs', + 'dist/weapp-tw-runtime-classset-loader.cjs', ], }, ] diff --git a/tools/weapp-tailwindcss-scripts/src/create-entry-dts.ts b/tools/weapp-tailwindcss-scripts/src/create-entry-dts.ts index a79feb1409..0b285cb111 100644 --- a/tools/weapp-tailwindcss-scripts/src/create-entry-dts.ts +++ b/tools/weapp-tailwindcss-scripts/src/create-entry-dts.ts @@ -6,11 +6,11 @@ import { corePackageRoot } from './paths' const root = corePackageRoot const entryShims = { - 'css-macro.d.ts': { target: './css-macro/index', defaultExport: true }, - 'framework.d.ts': { target: './framework/index' }, - 'generator.d.ts': { target: './generator/index' }, - 'reset.d.ts': { target: './reset/index', defaultExport: true }, - 'types.d.ts': { target: './types/index' }, + 'css-macro.d.ts': { target: './css-macro/index.js', defaultExport: true }, + 'framework.d.ts': { target: './framework/index.js' }, + 'generator.d.ts': { target: './generator/index.js' }, + 'reset.d.ts': { target: './reset/index.js', defaultExport: true }, + 'types.d.ts': { target: './types/index.js' }, } async function main() { diff --git a/tools/weapp-tailwindcss-scripts/src/dts-module-specifiers.ts b/tools/weapp-tailwindcss-scripts/src/dts-module-specifiers.ts new file mode 100644 index 0000000000..6836692125 --- /dev/null +++ b/tools/weapp-tailwindcss-scripts/src/dts-module-specifiers.ts @@ -0,0 +1,147 @@ +import { dirname, join, normalize, relative, resolve, sep } from 'node:path' +import ts from 'typescript' + +interface ModuleSpecifierReplacement { + end: number + start: number + value: string +} + +function declarationRuntimeExtension(filepath: string) { + if (filepath.endsWith('.d.cts')) { + return '.cjs' + } + if (filepath.endsWith('.d.mts')) { + return '.mjs' + } + return '.js' +} + +function declarationRuntimePath(filepath: string) { + return filepath + .replace(/\.d\.cts$/, '.cjs') + .replace(/\.d\.mts$/, '.mjs') + .replace(/\.d\.ts$/, '.js') +} + +function hasExplicitExtension(specifier: string) { + return /\.(?:[cm]?js|d\.[cm]?ts|json|node|css|scss|sass|less|styl)$/.test(specifier) +} + +function withRuntimeExtension(specifier: string, filepath: string) { + if (hasExplicitExtension(specifier)) { + return specifier + } + if (specifier === '.' || specifier === '..' || specifier.endsWith('/..')) { + return `${specifier}/index${declarationRuntimeExtension(filepath)}` + } + return `${specifier}${declarationRuntimeExtension(filepath)}` +} + +function toRelativePath(filepath: string, target: string) { + let value = relative(dirname(filepath), target).split(sep).join('/') + if (!value.startsWith('.')) { + value = `./${value}` + } + return value +} + +function toModulePath(filepath: string, declarationFile: string) { + return toRelativePath(filepath, declarationRuntimePath(declarationFile)) +} + +function resolveDeclarationTarget( + target: string, + declarationFiles: ReadonlySet | undefined, +) { + if (!declarationFiles) { + return undefined + } + + const candidates = [ + `${target}.d.ts`, + `${target}.d.cts`, + `${target}.d.mts`, + join(target, 'index.d.ts'), + join(target, 'index.d.cts'), + join(target, 'index.d.mts'), + ] + return candidates.find(candidate => declarationFiles.has(normalize(candidate))) +} + +function rewriteRelativeSpecifier( + specifier: string, + filepath: string, + declarationFiles: ReadonlySet | undefined, +) { + if (hasExplicitExtension(specifier)) { + return specifier + } + + const target = resolve(dirname(filepath), specifier) + const declarationFile = resolveDeclarationTarget(target, declarationFiles) + if (!declarationFile) { + return withRuntimeExtension(specifier, filepath) + } + + return toModulePath(filepath, declarationFile) +} + +function getModuleSpecifier(node: ts.Node) { + if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier) { + return ts.isStringLiteralLike(node.moduleSpecifier) ? node.moduleSpecifier : undefined + } + if (ts.isImportEqualsDeclaration(node) + && ts.isExternalModuleReference(node.moduleReference) + && node.moduleReference.expression + && ts.isStringLiteralLike(node.moduleReference.expression)) { + return node.moduleReference.expression + } + if (ts.isImportTypeNode(node) + && ts.isLiteralTypeNode(node.argument) + && ts.isStringLiteralLike(node.argument.literal)) { + return node.argument.literal + } + return undefined +} + +export function rewriteDeclarationModuleSpecifiers( + content: string, + filepath: string, + distDir: string, + declarationFiles?: ReadonlySet, +) { + const sourceFile = ts.createSourceFile(filepath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS) + const replacements: ModuleSpecifierReplacement[] = [] + + function visit(node: ts.Node) { + const literal = getModuleSpecifier(node) + if (literal) { + const current = literal.text + const next = current.startsWith('@/') + ? rewriteRelativeSpecifier( + toRelativePath(filepath, join(distDir, current.slice(2))), + filepath, + declarationFiles, + ) + : current.startsWith('.') + ? rewriteRelativeSpecifier(current, filepath, declarationFiles) + : current + if (next !== current) { + replacements.push({ + start: literal.getStart(sourceFile) + 1, + end: literal.getEnd() - 1, + value: next, + }) + } + } + ts.forEachChild(node, visit) + } + + visit(sourceFile) + return replacements + .sort((a, b) => b.start - a.start) + .reduce((result, replacement) => { + return `${result.slice(0, replacement.start)}${replacement.value}${result.slice(replacement.end)}` + }, content) +} diff --git a/tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts b/tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts index d33c4e2141..6577278060 100644 --- a/tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts +++ b/tools/weapp-tailwindcss-scripts/src/rewrite-dts-aliases.ts @@ -1,9 +1,10 @@ import { readdir, readFile, writeFile } from 'node:fs/promises' -import { dirname, join, relative, sep } from 'node:path' +import { join, resolve } from 'node:path' import process from 'node:process' +import { rewriteDeclarationModuleSpecifiers } from './dts-module-specifiers' import { corePackageRoot } from './paths' -const root = corePackageRoot +const root = process.argv[2] ? resolve(process.cwd(), process.argv[2]) : corePackageRoot const distDir = join(root, 'dist') async function* walk(dir) { @@ -19,21 +20,16 @@ async function* walk(dir) { } } -function toModulePath(filepath, aliasTarget) { - const target = join(distDir, aliasTarget) - let value = relative(dirname(filepath), target).split(sep).join('/') - if (!value.startsWith('.')) { - value = `./${value}` - } - return value -} - async function main() { + const declarationFiles = [] for await (const filepath of walk(distDir)) { + declarationFiles.push(filepath) + } + const declarationFileSet = new Set(declarationFiles) + + for (const filepath of declarationFiles) { const content = await readFile(filepath, 'utf8') - const next = content.replace(/from\s+(['"])@\/([^'"]+)\1/g, (_match, quote, aliasTarget) => { - return `from ${quote}${toModulePath(filepath, aliasTarget)}${quote}` - }) + const next = rewriteDeclarationModuleSpecifiers(content, filepath, distDir, declarationFileSet) if (next !== content) { await writeFile(filepath, next, 'utf8') } From 06887a82caee30834a462eeec4cd4e1950a06b1f Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 15:54:05 +0800 Subject: [PATCH 02/14] fix(e2e): stabilize web hot-update probes --- .../test/watch-hmr-regression.unit.test.ts | 3 +++ .../cases/demo/extended.ts | 1 + .../src/watch-hmr-regression/types.ts | 1 + .../src/watch-hmr-regression/web.ts | 24 +++++++++++++++---- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts index d612aafcdd..7c8d28a08e 100644 --- a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts +++ b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts @@ -2186,6 +2186,8 @@ describe('watch-hmr regression cases', () => { expect(isWebCompileReadyLogLine('compiled with some warnings')).toBe(true) expect(isWebCompileReadyLogLine('webpack 5.107.2 compiled with 1 warning in 369825 ms')).toBe(true) expect(isWebCompileDoneLogLine(' ➜ Local: http://localhost:10086/')).toBe(false) + expect(isWebCompileDoneLogLine('1:32:43 PM [vite] hmr update /src/main.css')).toBe(true) + expect(isWebCompileDoneLogLine('[weapp-tailwindcss:hmr] {"bundler":"vite","phase":"generateCss.serve","durationMs":40}')).toBe(true) expect(isWebCompileDoneLogLine('webpack 5.107.2 compiled with 1 warning in 369825 ms')).toBe(true) }) @@ -3211,6 +3213,7 @@ describe('watch-hmr regression cases', () => { expect(uniAppCase?.webHmr?.sourceDomReplacementSequence?.[0]?.beforeSelector).toBe('.text-\\[\\#00f285\\]') expect(uniAppCase?.webHmr?.sourceDomReplacementSequence?.[0]?.expectedStyle?.color).toBe('rgb(18, 52, 86)') + expect(uniAppCase?.webHmr?.touchCssEntryOnSourceMutation).toBe(false) }) it('filters platform-specific unstable watch cases from grouped runs', () => { diff --git a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/cases/demo/extended.ts b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/cases/demo/extended.ts index 99a59ac56b..bd72c84e64 100644 --- a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/cases/demo/extended.ts +++ b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/cases/demo/extended.ts @@ -408,6 +408,7 @@ export function buildDemoExtendedCases(baseCwd: string): WatchCase[] { sourceFile: path.resolve(baseCwd, 'demo/uni-app-vite-tailwindcss-v4/src/pages/index/index.vue'), cssEntryFile: path.resolve(baseCwd, 'demo/uni-app-vite-tailwindcss-v4/src/main.css'), injectMarkerElement: true, + touchCssEntryOnSourceMutation: false, readySelector: 'uni-page[data-page="pages/index/index"]', initialMutationDelayMs: 1500, mutate(source, payload) { diff --git a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types.ts b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types.ts index afdd5ec84a..1759081f48 100644 --- a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types.ts +++ b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types.ts @@ -308,6 +308,7 @@ export interface WebHmrConfig { waitForInitialCompileSettled?: boolean initialCompileSettleTimeoutMs?: number reloadAfterCssMutation?: boolean + touchCssEntryOnSourceMutation?: boolean compileSettleTimeoutMs?: number mutate: (source: string, payload: ClassMutationPayload) => string env?: Record diff --git a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/web.ts b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/web.ts index 3fd7823aa1..b4c97090ac 100644 --- a/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/web.ts +++ b/tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/web.ts @@ -36,9 +36,11 @@ export function isWebCompileReadyLogLine(line: string) { } export function isWebCompileDoneLogLine(line: string) { - return /ready in \d+|compiled successfully|compiled with (?:(?:some|\d+) )?warnings?|webpack\s+[\d.]+\s+compiled|webpack compiled|构建完成|编译成功/u.test(line) + return /ready in \d+|\[vite\]\s+hmr update|\[weapp-tailwindcss:hmr\].*"phase":"generateCss\.serve"|compiled successfully|compiled with (?:(?:some|\d+) )?warnings?|webpack\s+[\d.]+\s+compiled|webpack compiled|构建完成|编译成功/u.test(line) } +type WaitForCompileSettled = (phaseStartedAt: number, phase: string) => Promise + function collectPluginProcessMetrics(samples: PluginProcessSample[], startedAt: number) { const phaseSamples = samples.filter(sample => sample.at >= startedAt) const totalSamples = phaseSamples.filter(sample => sample.metric === 'total' || sample.phase === 'total') @@ -386,6 +388,7 @@ async function runSourceClassReplacementSequence( page: Page, config: WebHmrConfig, sourceOriginal: string, + waitForCompileSettled: WaitForCompileSettled, ) { const sequence = config.sourceClassReplacementSequence ?? [] if (sequence.length === 0) { @@ -440,6 +443,8 @@ async function runSourceClassReplacementSequence( throw new Error(`${message}${lastError ? `\n${lastError}` : ''}`) }) + await waitForCompileSettled(hotUpdateStartedAt, `source replacement ${item.label}`) + results.push({ label: item.label, from: item.from, @@ -460,6 +465,7 @@ async function runSourceDomReplacementSequence( config: WebHmrConfig, sourceOriginal: string, cssEntryOriginal?: string | undefined, + waitForCompileSettled: WaitForCompileSettled, ) { const sequence = config.sourceDomReplacementSequence ?? [] if (sequence.length === 0) { @@ -485,7 +491,7 @@ async function runSourceDomReplacementSequence( message: `[${watchCase.label}] web source DOM replacement base node was not ready: ${item.label}`, }, hotUpdateStartedAt) await writeFilePreserveEol(config.sourceFile, mutation.next, sourceOriginal) - if (config.cssEntryFile && cssEntryOriginal != null) { + if (config.touchCssEntryOnSourceMutation !== false && config.cssEntryFile && cssEntryOriginal != null) { // Taro H5 的 TSX HMR 只更新页面模块;触碰 CSS 入口以复用框架真实的 app.css 热更新链路。 await writeFilePreserveEol( config.cssEntryFile, @@ -535,6 +541,8 @@ async function runSourceDomReplacementSequence( throw new Error(`${message}${lastError ? `\n${lastError}` : ''}`) }) + await waitForCompileSettled(hotUpdateStartedAt, `source DOM replacement ${item.label}`) + results.push({ label: item.label, ...(item.selector ? { selector: item.selector } : {}), @@ -575,6 +583,7 @@ async function runWebIconifyHmr( page: Page, config: WebHmrConfig, sourceOriginal: string, + waitForCompileSettled: WaitForCompileSettled, ) { const iconifyConfig = config.iconifyHmr if (!iconifyConfig) { @@ -641,6 +650,7 @@ async function runWebIconifyHmr( }, injectStartedAt, ) + await waitForCompileSettled(injectStartedAt, 'iconify inject') const hotUpdateStartedAt = Date.now() process.stdout.write( @@ -664,6 +674,7 @@ async function runWebIconifyHmr( }, hotUpdateStartedAt, ) + await waitForCompileSettled(hotUpdateStartedAt, 'iconify content') return { marker, @@ -1009,7 +1020,7 @@ export async function runWebHmr( const initialReadyMs = Date.now() - startedAt const hotUpdateStartedAt = Date.now() await writeFilePreserveEol(config.sourceFile, mutatedSource, sourceOriginal) - if (config.cssEntryFile && cssEntryOriginal != null) { + if (config.touchCssEntryOnSourceMutation !== false && config.cssEntryFile && cssEntryOriginal != null) { await writeFilePreserveEol( config.cssEntryFile, createCssEntryContent(cssEntryOriginal, marker, mutation.classLiteral), @@ -1054,6 +1065,7 @@ export async function runWebHmr( const message = error instanceof Error ? error.message : String(error) throw new Error(`${message}${lastStyleError ? `\n${lastStyleError}` : ''}`) } + await waitForCompileSettled(hotUpdateStartedAt, 'hot-update acceptance') const rollbackStartedAt = Date.now() const rollbackExpectedStyle = resolveRollbackExpectedStyle(config) @@ -1064,7 +1076,7 @@ export async function runWebHmr( : sourceOriginal, sourceOriginal, ) - if (config.cssEntryFile && cssEntryOriginal != null) { + if (config.touchCssEntryOnSourceMutation !== false && config.cssEntryFile && cssEntryOriginal != null) { await writeFilePreserveEol( config.cssEntryFile, config.injectMarkerElement @@ -1106,6 +1118,7 @@ export async function runWebHmr( const message = error instanceof Error ? error.message : String(error) throw new Error(`${message}${lastStyleError ? `\n${lastStyleError}` : ''}`) }) + await waitForCompileSettled(rollbackStartedAt, 'rollback acceptance') if (config.injectMarkerElement) { await page.locator(`[data-tw-watch-web="${marker}"]`).evaluate((element) => { element.remove() @@ -1119,6 +1132,7 @@ export async function runWebHmr( page, config, sourceOriginal, + waitForCompileSettled, ) const sourceDomReplacementSequence = await runSourceDomReplacementSequence( watchCase, @@ -1127,6 +1141,7 @@ export async function runWebHmr( config, sourceOriginal, cssEntryOriginal, + waitForCompileSettled, ) const iconifyHmr = await runWebIconifyHmr( watchCase, @@ -1134,6 +1149,7 @@ export async function runWebHmr( page, config, sourceOriginal, + waitForCompileSettled, ) process.stdout.write( From b71dc8a393f576a09ae8cec0a1151f92a355c4b7 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 16:20:06 +0800 Subject: [PATCH 03/14] fix(build): stabilize ESM package demo builds --- .../ensure-weapp-tailwindcss-built.test.ts | 81 +++++++ .../src/bundlers/rspack/index.ts | 2 +- .../test/bundlers/rspack.unit.test.ts | 27 +++ scripts/ensure-weapp-tailwindcss-built.mjs | 198 ++++++++---------- 4 files changed, 197 insertions(+), 111 deletions(-) create mode 100644 demo/__tests__/ensure-weapp-tailwindcss-built.test.ts diff --git a/demo/__tests__/ensure-weapp-tailwindcss-built.test.ts b/demo/__tests__/ensure-weapp-tailwindcss-built.test.ts new file mode 100644 index 0000000000..e8ade2a79c --- /dev/null +++ b/demo/__tests__/ensure-weapp-tailwindcss-built.test.ts @@ -0,0 +1,81 @@ +import { mkdtempSync, mkdirSync, rmSync, unlinkSync, utimesSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import path from 'node:path' +import { afterEach, describe, expect, it } from 'vitest' +import { + buildTargets, + collectPackageEntryStamps, + resolveTargetStamps, + shouldBuild, +} from '../../scripts/ensure-weapp-tailwindcss-built.mjs' + +const temporaryRoots: string[] = [] + +function createPackageFixture(moduleEntry = './dist/index.js') { + const packageRoot = mkdtempSync(path.join(tmpdir(), 'weapp-tailwindcss-ensure-')) + temporaryRoots.push(packageRoot) + mkdirSync(path.join(packageRoot, 'src')) + mkdirSync(path.join(packageRoot, 'dist')) + writeFileSync(path.join(packageRoot, 'package.json'), JSON.stringify({ + exports: { + '.': { + types: './dist/index.d.ts', + import: moduleEntry, + require: './dist/index.cjs', + }, + }, + main: './dist/index.cjs', + module: moduleEntry, + types: './dist/index.d.ts', + })) + writeFileSync(path.join(packageRoot, 'src/index.ts'), 'export const value = 1\n') + for (const file of ['dist/index.cjs', moduleEntry.slice(2), 'dist/index.d.ts']) { + writeFileSync(path.join(packageRoot, file), '') + } + return packageRoot +} + +afterEach(() => { + for (const root of temporaryRoots.splice(0)) { + rmSync(root, { recursive: true, force: true }) + } +}) + +describe('ensure-weapp-tailwindcss-built', () => { + it('从 package exports 推导 ESM 与 CJS 产物扩展名', () => { + const postcssCalc = buildTargets.find(target => target.filter === '@weapp-tailwindcss/postcss-calc')! + const reset = buildTargets.find(target => target.filter === '@weapp-tailwindcss/reset')! + + expect(resolveTargetStamps(postcssCalc)).toEqual(expect.arrayContaining([ + 'dist/index.mjs', + 'dist/index.cjs', + 'dist/index.d.ts', + ])) + expect(resolveTargetStamps(reset)).toEqual(expect.arrayContaining([ + 'dist/index.js', + 'dist/index.cjs', + 'dist/index.d.ts', + ])) + }) + + it('只在公共入口缺失或源码更新后触发重建', () => { + const packageRoot = createPackageFixture('./dist/index.mjs') + const sourceFile = path.join(packageRoot, 'src/index.ts') + const outputFile = path.join(packageRoot, 'dist/index.mjs') + const now = Date.now() / 1000 + + utimesSync(sourceFile, now - 10, now - 10) + for (const stamp of collectPackageEntryStamps(packageRoot)) { + utimesSync(path.join(packageRoot, stamp), now, now) + } + expect(shouldBuild({ packageRoot })).toBe(false) + + unlinkSync(outputFile) + expect(shouldBuild({ packageRoot })).toBe(true) + + writeFileSync(outputFile, '') + utimesSync(outputFile, now, now) + utimesSync(sourceFile, now + 10, now + 10) + expect(shouldBuild({ packageRoot })).toBe(true) + }) +}) diff --git a/packages/weapp-tailwindcss/src/bundlers/rspack/index.ts b/packages/weapp-tailwindcss/src/bundlers/rspack/index.ts index dabd765823..6cd19fab45 100644 --- a/packages/weapp-tailwindcss/src/bundlers/rspack/index.ts +++ b/packages/weapp-tailwindcss/src/bundlers/rspack/index.ts @@ -75,7 +75,7 @@ function includesLoaderName(item: RspackUseItem | undefined, name: string) { function createCssImportRewriteLoaderEntry(options: PatchRspackCssImportRewriteLoaderOptions): RspackUseItem { return { - loader: options.loader ?? path.resolve(__dirname, `./${CSS_IMPORT_REWRITE_LOADER_NAME}.js`), + loader: options.loader ?? path.resolve(__dirname, `./${CSS_IMPORT_REWRITE_LOADER_NAME}.cjs`), ...(options.options === undefined ? {} : { options: options.options }), } } diff --git a/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts index 97d46d1bd6..0f78383ffb 100644 --- a/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/rspack.unit.test.ts @@ -6,6 +6,33 @@ function getUseLoaders(config: any) { } describe('bundlers/rspack patchRspackConfig', () => { + it('uses the physical CommonJS loader by default', () => { + const config = { + module: { + rules: [ + { + oneOf: [ + { + use: [ + { loader: 'css-loader' }, + { loader: 'builtin:lightningcss-loader' }, + ], + }, + ], + }, + ], + }, + } + + patchRspackConfig(config) + + expect(getUseLoaders(config)).toEqual([ + 'css-loader', + 'builtin:lightningcss-loader', + expect.stringMatching(/weapp-tw-css-import-rewrite-loader\.cjs$/), + ]) + }) + it('injects css rewrite loader after lightning css loader without removing it', () => { const config = { module: { diff --git a/scripts/ensure-weapp-tailwindcss-built.mjs b/scripts/ensure-weapp-tailwindcss-built.mjs index 6946ed9a0f..1048f7d007 100644 --- a/scripts/ensure-weapp-tailwindcss-built.mjs +++ b/scripts/ensure-weapp-tailwindcss-built.mjs @@ -13,157 +13,78 @@ const runtimeBuildTargets = [ filter: '@weapp-tailwindcss/runtime', label: '@weapp-tailwindcss/runtime', packageRoot: path.join(repoRoot, 'packages-runtime/runtime'), - stamps: [ - 'dist/index.cjs', - 'dist/index.mjs', - 'dist/index.d.mts', - ], }, { name: '@weapp-tailwindcss/merge', filter: '@weapp-tailwindcss/merge', label: '@weapp-tailwindcss/merge', packageRoot: path.join(repoRoot, 'packages-runtime/merge'), - stamps: [ - 'dist/index.cjs', - 'dist/index.mjs', - 'dist/index.d.mts', - ], }, { name: '@weapp-tailwindcss/cva', filter: '@weapp-tailwindcss/cva', label: '@weapp-tailwindcss/cva', packageRoot: path.join(repoRoot, 'packages-runtime/cva'), - stamps: [ - 'dist/index.cjs', - 'dist/index.mjs', - 'dist/index.d.mts', - ], }, { name: '@weapp-tailwindcss/variants', filter: '@weapp-tailwindcss/variants', label: '@weapp-tailwindcss/variants', packageRoot: path.join(repoRoot, 'packages-runtime/variants'), - stamps: [ - 'dist/index.cjs', - 'dist/index.mjs', - 'dist/index.d.mts', - ], }, { name: '@weapp-tailwindcss/typography', filter: '@weapp-tailwindcss/typography', label: '@weapp-tailwindcss/typography', packageRoot: path.join(repoRoot, 'packages-runtime/typography'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/transform.js', - 'dist/transform.cjs', - 'dist/index.d.ts', - ], }, ] -const buildTargets = [ +export const buildTargets = [ { filter: '@weapp-tailwindcss/shared', label: '@weapp-tailwindcss/shared', packageRoot: path.join(repoRoot, 'packages/shared'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/node.js', - 'dist/node.cjs', - ], }, { filter: '@weapp-tailwindcss/logger', label: '@weapp-tailwindcss/logger', packageRoot: path.join(repoRoot, 'packages/logger'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/index.d.ts', - ], }, { filter: '@weapp-tailwindcss/postcss-calc', label: '@weapp-tailwindcss/postcss-calc', packageRoot: path.join(repoRoot, 'packages/postcss-calc'), - stamps: [ - 'dist/index.cjs', - 'dist/index.js', - 'dist/index.d.ts', - ], }, { filter: 'tailwindcss-config', label: 'tailwindcss-config', packageRoot: path.join(repoRoot, 'packages/tailwindcss-config'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/index.d.ts', - ], }, { filter: '@weapp-tailwindcss/reset', label: '@weapp-tailwindcss/reset', packageRoot: path.join(repoRoot, 'packages/reset'), - stamps: [ - 'dist/index.cjs', - 'dist/index.mjs', - 'dist/index.d.ts', - ], }, { filter: '@weapp-tailwindcss/postcss', label: '@weapp-tailwindcss/postcss', packageRoot: path.join(repoRoot, 'packages/postcss'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/index.d.ts', - ], }, { filter: '@weapp-tailwindcss/debug-uni-app-x', label: '@weapp-tailwindcss/debug-uni-app-x', packageRoot: path.join(repoRoot, 'packages/debug-uni-app-x'), - stamps: [ - 'dist/index.cjs', - 'dist/index.js', - 'dist/index.d.ts', - ], }, { filter: 'weapp-style-injector', label: 'weapp-style-injector', packageRoot: path.join(repoRoot, 'packages/weapp-style-injector'), - stamps: [ - 'dist/index.js', - 'dist/index.cjs', - 'dist/vite.js', - 'dist/vite.cjs', - 'dist/webpack.js', - 'dist/webpack.cjs', - ], }, { filter: 'weapp-tailwindcss', label: '核心包', packageRoot: path.join(repoRoot, 'packages/weapp-tailwindcss'), - stamps: [ - 'dist/vite.js', - 'dist/vite.cjs', - 'dist/webpack.js', - 'dist/webpack.cjs', - 'dist/gulp.js', - 'dist/gulp.cjs', - 'dist/index.js', - 'dist/index.cjs', + extraStamps: [ 'dist/cli.cjs', 'dist/weapp-tw-runtime-classset-loader.cjs', ], @@ -179,6 +100,56 @@ function readPackageJson(file) { } } +function collectDistEntries(value, entries) { + if (typeof value === 'string') { + const normalized = value.startsWith('./') ? value.slice(2) : value + if (normalized.startsWith('dist/') && !normalized.includes('*')) { + entries.add(normalized) + } + return + } + + if (Array.isArray(value)) { + for (const entry of value) { + collectDistEntries(entry, entries) + } + return + } + + if (value && typeof value === 'object') { + for (const entry of Object.values(value)) { + collectDistEntries(entry, entries) + } + } +} + +export function collectPackageEntryStamps(packageRoot) { + const packageJson = readPackageJson(path.join(packageRoot, 'package.json')) + if (!packageJson) { + return [] + } + + const entries = new Set() + for (const value of [ + packageJson.exports, + packageJson.main, + packageJson.module, + packageJson.types, + packageJson.typings, + packageJson.bin, + ]) { + collectDistEntries(value, entries) + } + return [...entries].sort() +} + +export function resolveTargetStamps(target) { + return [...new Set([ + ...collectPackageEntryStamps(target.packageRoot), + ...(target.extraStamps ?? []), + ])] +} + function collectWorkspaceRuntimeDependencyNames() { const packageJson = readPackageJson(path.join(process.cwd(), 'package.json')) const dependencies = { @@ -221,12 +192,17 @@ function collectLatestMtime(target, ignoredDirectories = new Set()) { return latest } -function shouldBuild(target) { +export function shouldBuild(target) { const srcRoot = path.join(target.packageRoot, 'src') const distRoot = path.join(target.packageRoot, 'dist') - const stampFiles = target.stamps.map(stamp => path.join(target.packageRoot, stamp)) + const stampFiles = resolveTargetStamps(target) + .map(stamp => path.join(target.packageRoot, stamp)) - if (!existsSync(distRoot) || stampFiles.some(file => !existsSync(file))) { + if ( + !existsSync(distRoot) + || stampFiles.length === 0 + || stampFiles.some(file => !existsSync(file)) + ) { return true } const latestSource = collectLatestMtime(srcRoot) @@ -269,35 +245,37 @@ function expandRuntimeBuildTargets() { return runtimeBuildTargets.filter(target => selectedNames.has(target.name)) } -const staleTargets = [ - ...buildTargets, - ...expandRuntimeBuildTargets(), -].filter(shouldBuild) +export function main() { + const staleTargets = [ + ...buildTargets, + ...expandRuntimeBuildTargets(), + ].filter(shouldBuild) -if (staleTargets.length === 0) { - process.exit(0) -} + for (const target of staleTargets) { + console.log(`[weapp-tailwindcss] ${target.label} dist 已过期,正在构建供 demo 使用...`) + const command = createPnpmCommand(['--filter', target.filter, 'build']) + const result = spawnSync( + command.command, + command.args, + { + cwd: repoRoot, + stdio: 'inherit', + env: process.env, + shell: command.shell, + }, + ) -for (const target of staleTargets) { - console.log(`[weapp-tailwindcss] ${target.label} dist 已过期,正在构建供 demo 使用...`) - const command = createPnpmCommand(['--filter', target.filter, 'build']) - const result = spawnSync( - command.command, - command.args, - { - cwd: repoRoot, - stdio: 'inherit', - env: process.env, - shell: command.shell, - }, - ) + if (result.error) { + console.error(result.error) + process.exit(1) + } - if (result.error) { - console.error(result.error) - process.exit(1) + if (result.status !== 0) { + process.exit(result.status ?? 1) + } } +} - if (result.status !== 0) { - process.exit(result.status ?? 1) - } +if (path.resolve(process.argv[1] ?? '') === fileURLToPath(import.meta.url)) { + main() } From 279deba1396269d299a13951df9d8aea33c10be1 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 16:44:52 +0800 Subject: [PATCH 04/14] test(typography): refresh Tailwind 4.3 snapshots --- .../test/__snapshots__/index.test.ts.snap | 580 +++++++----------- .../test/__snapshots__/styles.test.ts.snap | 56 +- 2 files changed, 249 insertions(+), 387 deletions(-) diff --git a/packages-runtime/typography/test/__snapshots__/index.test.ts.snap b/packages-runtime/typography/test/__snapshots__/index.test.ts.snap index a76645a4c4..59a47d1b12 100644 --- a/packages-runtime/typography/test/__snapshots__/index.test.ts.snap +++ b/packages-runtime/typography/test/__snapshots__/index.test.ts.snap @@ -65,17 +65,11 @@ exports[`does not modify selectors with differing pseudo elements 1`] = ` margin: 0; padding: 0; } -.prose { - .ol .li::before, .ul .li::after { - color: red; - } +.prose .ol .li::before, .prose .ul .li::after { + color: red; } -.dark\\:prose { - &:is(.dark *) { - .ol .li::before, .ul .li::after { - color: red; - } - } +.dark\\:prose:is(.dark *) .ol .li::before, .dark\\:prose:is(.dark *) .ul .li::after { + color: red; }" `; @@ -118,155 +112,105 @@ exports[`element variants 1`] = ` font-weight: 700; } } -.prose-headings\\:underline { - & .h1 { - text-decoration-line: underline; - } - & .h2 { - text-decoration-line: underline; - } - & .h3 { - text-decoration-line: underline; - } - & .h4 { - text-decoration-line: underline; - } - & .h5 { - text-decoration-line: underline; - } - & .h6 { - text-decoration-line: underline; - } - & .th { - text-decoration-line: underline; - } +.prose-headings\\:underline .h1 { + text-decoration-line: underline; } -.prose-h1\\:text-3xl { - & .h1 { - font-size: var(--text-3xl); - line-height: var(--tw-leading, var(--text-3xl--line-height)); - } +.prose-headings\\:underline .h2 { + text-decoration-line: underline; } -.prose-h2\\:text-2xl { - & .h2 { - font-size: var(--text-2xl); - line-height: var(--tw-leading, var(--text-2xl--line-height)); - } +.prose-headings\\:underline .h3 { + text-decoration-line: underline; } -.prose-h3\\:text-xl { - & .h3 { - font-size: var(--text-xl); - line-height: var(--tw-leading, var(--text-xl--line-height)); - } +.prose-headings\\:underline .h4 { + text-decoration-line: underline; } -.prose-h4\\:text-lg { - & .h4 { - font-size: var(--text-lg); - line-height: var(--tw-leading, var(--text-lg--line-height)); - } +.prose-headings\\:underline .h5 { + text-decoration-line: underline; } -.prose-p\\:text-gray-700 { - & .p { - color: var(--color-gray-700); - } +.prose-headings\\:underline .h6 { + text-decoration-line: underline; } -.prose-a\\:font-bold { - & .a { - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - } +.prose-headings\\:underline .th { + text-decoration-line: underline; } -.prose-blockquote\\:italic { - & .blockquote { - font-style: italic; - } +.prose-h1\\:text-3xl .h1 { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); } -.prose-figure\\:mx-auto { - & .figure { - margin-inline: auto; - } +.prose-h2\\:text-2xl .h2 { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); } -.prose-figcaption\\:opacity-75 { - & .figcaption { - opacity: 75%; - } +.prose-h3\\:text-xl .h3 { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); } -.prose-strong\\:font-medium { - & .strong { - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - } +.prose-h4\\:text-lg .h4 { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); } -.prose-em\\:italic { - & .em { - font-style: italic; - } +.prose-p\\:text-gray-700 .p { + color: var(--color-gray-700); } -.prose-code\\:font-mono { - & .code { - font-family: var(--font-mono); - } +.prose-a\\:font-bold .a { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); } -.prose-pre\\:font-mono { - & .pre { - font-family: var(--font-mono); - } +.prose-blockquote\\:italic .blockquote { + font-style: italic; } -.prose-ol\\:pl-6 { - & .ol { - padding-left: calc(var(--spacing) * 6); - } +.prose-figure\\:mx-auto .figure { + margin-inline: auto; } -.prose-ul\\:pl-8 { - & .ul { - padding-left: calc(var(--spacing) * 8); - } +.prose-figcaption\\:opacity-75 .figcaption { + opacity: 75%; } -.prose-li\\:my-4 { - & .li { - margin-block: calc(var(--spacing) * 4); - } +.prose-strong\\:font-medium .strong { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); } -.prose-table\\:my-8 { - & .table { - margin-block: calc(var(--spacing) * 8); - } +.prose-em\\:italic .em { + font-style: italic; } -.prose-thead\\:border-red-300 { - & .thead { - border-color: var(--color-red-300); - } +.prose-code\\:font-mono .code { + font-family: var(--font-mono); } -.prose-tr\\:border-red-200 { - & .tr { - border-color: var(--color-red-200); - } +.prose-pre\\:font-mono .pre { + font-family: var(--font-mono); } -.prose-th\\:text-left { - & .th { - text-align: left; - } +.prose-ol\\:pl-6 .ol { + padding-left: calc(var(--spacing) * 6); } -.prose-img\\:rounded-lg { - & .img { - border-radius: var(--radius-lg); - } +.prose-ul\\:pl-8 .ul { + padding-left: calc(var(--spacing) * 8); } -.prose-video\\:my-12 { - & .video { - margin-block: calc(var(--spacing) * 12); - } +.prose-li\\:my-4 .li { + margin-block: calc(var(--spacing) * 4); } -.prose-hr\\:border-t-2 { - & .hr { - border-top-style: var(--tw-border-style); - border-top-width: 2px; - } +.prose-table\\:my-8 .table { + margin-block: calc(var(--spacing) * 8); } -.prose-lead\\:italic { - & [class~="lead"] { - font-style: italic; - } +.prose-thead\\:border-red-300 .thead { + border-color: var(--color-red-300); +} +.prose-tr\\:border-red-200 .tr { + border-color: var(--color-red-200); +} +.prose-th\\:text-left .th { + text-align: left; +} +.prose-img\\:rounded-lg .img { + border-radius: var(--radius-lg); +} +.prose-video\\:my-12 .video { + margin-block: calc(var(--spacing) * 12); +} +.prose-hr\\:border-t-2 .hr { + border-top-style: var(--tw-border-style); + border-top-width: 2px; +} +.prose-lead\\:italic [class~="lead"] { + font-style: italic; } @property --tw-font-weight { syntax: "*"; @@ -326,155 +270,105 @@ exports[`element variants with custom class name 1`] = ` font-weight: 700; } } -.markdown-headings\\:underline { - & .h1 { - text-decoration-line: underline; - } - & .h2 { - text-decoration-line: underline; - } - & .h3 { - text-decoration-line: underline; - } - & .h4 { - text-decoration-line: underline; - } - & .h5 { - text-decoration-line: underline; - } - & .h6 { - text-decoration-line: underline; - } - & .th { - text-decoration-line: underline; - } +.markdown-headings\\:underline .h1 { + text-decoration-line: underline; } -.markdown-h1\\:text-3xl { - & .h1 { - font-size: var(--text-3xl); - line-height: var(--tw-leading, var(--text-3xl--line-height)); - } +.markdown-headings\\:underline .h2 { + text-decoration-line: underline; } -.markdown-h2\\:text-2xl { - & .h2 { - font-size: var(--text-2xl); - line-height: var(--tw-leading, var(--text-2xl--line-height)); - } +.markdown-headings\\:underline .h3 { + text-decoration-line: underline; } -.markdown-h3\\:text-xl { - & .h3 { - font-size: var(--text-xl); - line-height: var(--tw-leading, var(--text-xl--line-height)); - } +.markdown-headings\\:underline .h4 { + text-decoration-line: underline; } -.markdown-h4\\:text-lg { - & .h4 { - font-size: var(--text-lg); - line-height: var(--tw-leading, var(--text-lg--line-height)); - } +.markdown-headings\\:underline .h5 { + text-decoration-line: underline; } -.markdown-p\\:text-gray-700 { - & .p { - color: var(--color-gray-700); - } +.markdown-headings\\:underline .h6 { + text-decoration-line: underline; } -.markdown-a\\:font-bold { - & .a { - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - } +.markdown-headings\\:underline .th { + text-decoration-line: underline; } -.markdown-blockquote\\:italic { - & .blockquote { - font-style: italic; - } +.markdown-h1\\:text-3xl .h1 { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); } -.markdown-figure\\:mx-auto { - & .figure { - margin-inline: auto; - } +.markdown-h2\\:text-2xl .h2 { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); } -.markdown-figcaption\\:opacity-75 { - & .figcaption { - opacity: 75%; - } +.markdown-h3\\:text-xl .h3 { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); } -.markdown-strong\\:font-medium { - & .strong { - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - } +.markdown-h4\\:text-lg .h4 { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); } -.markdown-em\\:italic { - & .em { - font-style: italic; - } +.markdown-p\\:text-gray-700 .p { + color: var(--color-gray-700); } -.markdown-code\\:font-mono { - & .code { - font-family: var(--font-mono); - } +.markdown-a\\:font-bold .a { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); } -.markdown-pre\\:font-mono { - & .pre { - font-family: var(--font-mono); - } +.markdown-blockquote\\:italic .blockquote { + font-style: italic; } -.markdown-ol\\:pl-6 { - & .ol { - padding-left: calc(var(--spacing) * 6); - } +.markdown-figure\\:mx-auto .figure { + margin-inline: auto; } -.markdown-ul\\:pl-8 { - & .ul { - padding-left: calc(var(--spacing) * 8); - } +.markdown-figcaption\\:opacity-75 .figcaption { + opacity: 75%; } -.markdown-li\\:my-4 { - & .li { - margin-block: calc(var(--spacing) * 4); - } +.markdown-strong\\:font-medium .strong { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); } -.markdown-table\\:my-8 { - & .table { - margin-block: calc(var(--spacing) * 8); - } +.markdown-em\\:italic .em { + font-style: italic; } -.markdown-thead\\:border-red-300 { - & .thead { - border-color: var(--color-red-300); - } +.markdown-code\\:font-mono .code { + font-family: var(--font-mono); } -.markdown-tr\\:border-red-200 { - & .tr { - border-color: var(--color-red-200); - } +.markdown-pre\\:font-mono .pre { + font-family: var(--font-mono); } -.markdown-th\\:text-left { - & .th { - text-align: left; - } +.markdown-ol\\:pl-6 .ol { + padding-left: calc(var(--spacing) * 6); } -.markdown-img\\:rounded-lg { - & .img { - border-radius: var(--radius-lg); - } +.markdown-ul\\:pl-8 .ul { + padding-left: calc(var(--spacing) * 8); } -.markdown-video\\:my-12 { - & .video { - margin-block: calc(var(--spacing) * 12); - } +.markdown-li\\:my-4 .li { + margin-block: calc(var(--spacing) * 4); } -.markdown-hr\\:border-t-2 { - & .hr { - border-top-style: var(--tw-border-style); - border-top-width: 2px; - } +.markdown-table\\:my-8 .table { + margin-block: calc(var(--spacing) * 8); } -.markdown-lead\\:italic { - & [class~="lead"] { - font-style: italic; - } +.markdown-thead\\:border-red-300 .thead { + border-color: var(--color-red-300); +} +.markdown-tr\\:border-red-200 .tr { + border-color: var(--color-red-200); +} +.markdown-th\\:text-left .th { + text-align: left; +} +.markdown-img\\:rounded-lg .img { + border-radius: var(--radius-lg); +} +.markdown-video\\:my-12 .video { + margin-block: calc(var(--spacing) * 12); +} +.markdown-hr\\:border-t-2 .hr { + border-top-style: var(--tw-border-style); + border-top-width: 2px; +} +.markdown-lead\\:italic [class~="lead"] { + font-style: italic; } @property --tw-font-weight { syntax: "*"; @@ -502,17 +396,11 @@ exports[`ignores common non-trailing pseudo-elements in selectors 1`] = ` margin: 0; padding: 0; } -.prose { - .ol .li::before::scroll-thumb, .ul .li::before::scroll-track { - color: red; - } +.prose .ol .li::before::scroll-thumb, .prose .ul .li::before::scroll-track { + color: red; } -.dark\\:prose { - &:is(.dark *) { - .ol .li::before::scroll-thumb, .ul .li::before::scroll-track { - color: red; - } - } +.dark\\:prose:is(.dark *) .ol .li::before::scroll-thumb, .dark\\:prose:is(.dark *) .ul .li::before::scroll-track { + color: red; }" `; @@ -963,33 +851,29 @@ exports[`legacy target 1`] = ` content: "`"; } } -.prose-headings\\:text-ellipsis { - & .h1 { - text-overflow: ellipsis; - } - & .h2 { - text-overflow: ellipsis; - } - & .h3 { - text-overflow: ellipsis; - } - & .h4 { - text-overflow: ellipsis; - } - & .h5 { - text-overflow: ellipsis; - } - & .h6 { - text-overflow: ellipsis; - } - & .th { - text-overflow: ellipsis; - } +.prose-headings\\:text-ellipsis .h1 { + text-overflow: ellipsis; } -.prose-h1\\:text-center { - & .h1 { - text-align: center; - } +.prose-headings\\:text-ellipsis .h2 { + text-overflow: ellipsis; +} +.prose-headings\\:text-ellipsis .h3 { + text-overflow: ellipsis; +} +.prose-headings\\:text-ellipsis .h4 { + text-overflow: ellipsis; +} +.prose-headings\\:text-ellipsis .h5 { + text-overflow: ellipsis; +} +.prose-headings\\:text-ellipsis .h6 { + text-overflow: ellipsis; +} +.prose-headings\\:text-ellipsis .th { + text-overflow: ellipsis; +} +.prose-h1\\:text-center .h1 { + text-align: center; }" `; @@ -1000,17 +884,11 @@ exports[`lifts all common, trailing pseudo elements when the same across all sel margin: 0; padding: 0; } -.prose { - .ol .li::marker::before, .ul .li::marker::before { - color: red; - } +.prose .ol .li::marker::before, .prose .ul .li::marker::before { + color: red; } -.dark\\:prose { - &:is(.dark *) { - .ol .li::marker::before, .ul .li::marker::before { - color: red; - } - } +.dark\\:prose:is(.dark *) .ol .li::marker::before, .dark\\:prose:is(.dark *) .ul .li::marker::before { + color: red; }" `; @@ -1021,17 +899,11 @@ exports[`lifts only the common, trailing pseudo elements from selectors 1`] = ` margin: 0; padding: 0; } -.prose { - .ol .li::scroll-thumb::before, .ul .li::scroll-track::before { - color: red; - } +.prose .ol .li::scroll-thumb::before, .prose .ul .li::scroll-track::before { + color: red; } -.dark\\:prose { - &:is(.dark *) { - .ol .li::scroll-thumb::before, .ul .li::scroll-track::before { - color: red; - } - } +.dark\\:prose:is(.dark *) .ol .li::scroll-thumb::before, .dark\\:prose:is(.dark *) .ul .li::scroll-track::before { + color: red; }" `; @@ -2733,17 +2605,13 @@ exports[`should be possible to specify custom h5 and h6 styles 1`] = ` margin-bottom: 2em; } } -.prose-h5\\:text-sm { - & .h5 { - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - } +.prose-h5\\:text-sm .h5 { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); } -.prose-h6\\:text-xl { - & .h6 { - font-size: var(--text-xl); - line-height: var(--tw-leading, var(--text-xl--line-height)); - } +.prose-h6\\:text-xl .h6 { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); }" `; @@ -3161,12 +3029,8 @@ exports[`should not break with multiple selectors with pseudo elements using var margin: 0; padding: 0; } -.dark\\:prose { - &:is(.dark *) { - .ol .li::before, .ul .li::before { - color: red; - } - } +.dark\\:prose:is(.dark *) .ol .li::before, .dark\\:prose:is(.dark *) .ul .li::before { + color: red; }" `; @@ -3226,39 +3090,37 @@ exports[`variants 1`] = ` margin: 0; padding: 0; } -.hover\\:prose-lg { - &:hover { - @media (hover: hover) { - color: green; - .p { - color: tomato; - } - > .ul > .li { - color: blue; - } - } +@media (hover: hover) { + .hover\\:prose-lg:hover { + color: green; + } + .hover\\:prose-lg:hover .p { + color: tomato; + } + .hover\\:prose-lg:hover > .ul > .li { + color: blue; } } -.sm\\:prose { - @media (width >= 40rem) { +@media (width >= 40rem) { + .sm\\:prose { color: red; - .p { - color: lime; - } - > .ul > .li { - color: purple; - } + } + .sm\\:prose .p { + color: lime; + } + .sm\\:prose > .ul > .li { + color: purple; } } -.lg\\:prose-lg { - @media (width >= 64rem) { +@media (width >= 64rem) { + .lg\\:prose-lg { color: green; - .p { - color: tomato; - } - > .ul > .li { - color: blue; - } + } + .lg\\:prose-lg .p { + color: tomato; + } + .lg\\:prose-lg > .ul > .li { + color: blue; } }" `; diff --git a/packages-runtime/typography/test/__snapshots__/styles.test.ts.snap b/packages-runtime/typography/test/__snapshots__/styles.test.ts.snap index b2e3eedc8f..8df40fca93 100644 --- a/packages-runtime/typography/test/__snapshots__/styles.test.ts.snap +++ b/packages-runtime/typography/test/__snapshots__/styles.test.ts.snap @@ -1149,42 +1149,42 @@ exports[`styles > snap 1`] = ` }, "neutral": { "css": { - "--tw-prose-body": "oklch(37.1% 0 0)", - "--tw-prose-bold": "oklch(20.5% 0 0)", - "--tw-prose-bullets": "oklch(87% 0 0)", - "--tw-prose-captions": "oklch(55.6% 0 0)", - "--tw-prose-code": "oklch(20.5% 0 0)", - "--tw-prose-counters": "oklch(55.6% 0 0)", - "--tw-prose-headings": "oklch(20.5% 0 0)", - "--tw-prose-hr": "oklch(92.2% 0 0)", - "--tw-prose-invert-body": "oklch(87% 0 0)", + "--tw-prose-body": "oklch(37.1% 0 none)", + "--tw-prose-bold": "oklch(20.5% 0 none)", + "--tw-prose-bullets": "oklch(87% 0 none)", + "--tw-prose-captions": "oklch(55.6% 0 none)", + "--tw-prose-code": "oklch(20.5% 0 none)", + "--tw-prose-counters": "oklch(55.6% 0 none)", + "--tw-prose-headings": "oklch(20.5% 0 none)", + "--tw-prose-hr": "oklch(92.2% 0 none)", + "--tw-prose-invert-body": "oklch(87% 0 none)", "--tw-prose-invert-bold": "#fff", - "--tw-prose-invert-bullets": "oklch(43.9% 0 0)", - "--tw-prose-invert-captions": "oklch(70.8% 0 0)", + "--tw-prose-invert-bullets": "oklch(43.9% 0 none)", + "--tw-prose-invert-captions": "oklch(70.8% 0 none)", "--tw-prose-invert-code": "#fff", - "--tw-prose-invert-counters": "oklch(70.8% 0 0)", + "--tw-prose-invert-counters": "oklch(70.8% 0 none)", "--tw-prose-invert-headings": "#fff", - "--tw-prose-invert-hr": "oklch(37.1% 0 0)", + "--tw-prose-invert-hr": "oklch(37.1% 0 none)", "--tw-prose-invert-kbd": "#fff", "--tw-prose-invert-kbd-shadows": "255 255 255", - "--tw-prose-invert-lead": "oklch(70.8% 0 0)", + "--tw-prose-invert-lead": "oklch(70.8% 0 none)", "--tw-prose-invert-links": "#fff", "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-pre-code": "oklch(87% 0 0)", - "--tw-prose-invert-quote-borders": "oklch(37.1% 0 0)", - "--tw-prose-invert-quotes": "oklch(97% 0 0)", - "--tw-prose-invert-td-borders": "oklch(37.1% 0 0)", - "--tw-prose-invert-th-borders": "oklch(43.9% 0 0)", - "--tw-prose-kbd": "oklch(20.5% 0 0)", + "--tw-prose-invert-pre-code": "oklch(87% 0 none)", + "--tw-prose-invert-quote-borders": "oklch(37.1% 0 none)", + "--tw-prose-invert-quotes": "oklch(97% 0 none)", + "--tw-prose-invert-td-borders": "oklch(37.1% 0 none)", + "--tw-prose-invert-th-borders": "oklch(43.9% 0 none)", + "--tw-prose-kbd": "oklch(20.5% 0 none)", "--tw-prose-kbd-shadows": "NaN NaN NaN", - "--tw-prose-lead": "oklch(43.9% 0 0)", - "--tw-prose-links": "oklch(20.5% 0 0)", - "--tw-prose-pre-bg": "oklch(26.9% 0 0)", - "--tw-prose-pre-code": "oklch(92.2% 0 0)", - "--tw-prose-quote-borders": "oklch(92.2% 0 0)", - "--tw-prose-quotes": "oklch(20.5% 0 0)", - "--tw-prose-td-borders": "oklch(92.2% 0 0)", - "--tw-prose-th-borders": "oklch(87% 0 0)", + "--tw-prose-lead": "oklch(43.9% 0 none)", + "--tw-prose-links": "oklch(20.5% 0 none)", + "--tw-prose-pre-bg": "oklch(26.9% 0 none)", + "--tw-prose-pre-code": "oklch(92.2% 0 none)", + "--tw-prose-quote-borders": "oklch(92.2% 0 none)", + "--tw-prose-quotes": "oklch(20.5% 0 none)", + "--tw-prose-td-borders": "oklch(92.2% 0 none)", + "--tw-prose-th-borders": "oklch(87% 0 none)", }, }, "orange": { From 9f7770959a8ce6d87e9058b8911c5517a120aead Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 17:56:36 +0800 Subject: [PATCH 05/14] fix(build): reduce Babel 8 CJS overhead --- .changeset/babel-eight-module-packages.md | 2 +- .../version-compare/scripts/ci-report.mjs | 14 ++-- .../compiler/runtime-affecting-signature.ts | 81 ++++++++++++++----- .../test/build/tsdown-config.test.ts | 12 ++- ...e-runtime-affecting-signature.unit.test.ts | 24 ++++-- .../test/ci/benchmark-report.test.ts | 46 +++++++++++ packages/weapp-tailwindcss/tsdown.shared.mts | 21 ++--- 7 files changed, 150 insertions(+), 50 deletions(-) diff --git a/.changeset/babel-eight-module-packages.md b/.changeset/babel-eight-module-packages.md index 66a0a0564a..e4eb1df306 100644 --- a/.changeset/babel-eight-module-packages.md +++ b/.changeset/babel-eight-module-packages.md @@ -12,4 +12,4 @@ "weapp-style-injector": patch --- -升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。 +升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。 diff --git a/benchmark/version-compare/scripts/ci-report.mjs b/benchmark/version-compare/scripts/ci-report.mjs index f0b3c0fa46..d3cc089bde 100644 --- a/benchmark/version-compare/scripts/ci-report.mjs +++ b/benchmark/version-compare/scripts/ci-report.mjs @@ -181,16 +181,17 @@ export function buildSummary(raw, baselineLabel, currentLabel) { export function evaluatePerformanceGuard(summary, options = {}) { const regressionPercent = toNumber(options.regressionPercent) ?? 5 + const minimumTimingRegressionMs = toNumber(options.minimumTimingRegressionMs) ?? 10 const violations = summary.currentOnlyErrors.map(item => ({ key: item.key, metric: 'error', message: String(item.error).split('\n')[0], })) const metrics = [ - { metric: 'buildMedian', baseline: 'baselineBuild', current: 'currentBuild', delta: 'buildDeltaPct' }, - { metric: 'hmrP95', baseline: 'baselineHmr', current: 'currentHmr', delta: 'hmrDeltaPct', watchOnly: true }, - { metric: 'buildPluginMedian', baseline: 'baselineBuildPlugin', current: 'currentBuildPlugin', delta: 'buildPluginDeltaPct' }, - { metric: 'hmrPluginP95', baseline: 'baselineHmrPlugin', current: 'currentHmrPlugin', delta: 'hmrPluginDeltaPct', watchOnly: true }, + { metric: 'buildMedian', baseline: 'baselineBuild', current: 'currentBuild', delta: 'buildDeltaPct', timing: true }, + { metric: 'hmrP95', baseline: 'baselineHmr', current: 'currentHmr', delta: 'hmrDeltaPct', timing: true, watchOnly: true }, + { metric: 'buildPluginMedian', baseline: 'baselineBuildPlugin', current: 'currentBuildPlugin', delta: 'buildPluginDeltaPct', timing: true }, + { metric: 'hmrPluginP95', baseline: 'baselineHmrPlugin', current: 'currentHmrPlugin', delta: 'hmrPluginDeltaPct', timing: true, watchOnly: true }, { metric: 'buildPeakRssMb', baseline: 'baselineBuildPeakRssMb', current: 'currentBuildPeakRssMb', delta: 'buildPeakRssDeltaPct' }, { metric: 'buildSteadyRssMb', baseline: 'baselineBuildSteadyRssMb', current: 'currentBuildSteadyRssMb', delta: 'buildSteadyRssDeltaPct' }, { metric: 'hmrPeakRssMb', baseline: 'baselineHmrPeakRssMb', current: 'currentHmrPeakRssMb', delta: 'hmrPeakRssDeltaPct', watchOnly: true }, @@ -269,7 +270,8 @@ export function evaluatePerformanceGuard(summary, options = {}) { continue } const absoluteDelta = current - baseline - if (deltaPercent > regressionPercent) { + const minimumAbsoluteDelta = config.timing ? minimumTimingRegressionMs : 0 + if (deltaPercent > regressionPercent && absoluteDelta >= minimumAbsoluteDelta) { violations.push({ key: compare.key, metric: config.metric, @@ -286,6 +288,7 @@ export function evaluatePerformanceGuard(summary, options = {}) { return { passed: violations.length === 0, thresholds: { + minimumTimingRegressionMs, regressionPercent, }, violations, @@ -324,6 +327,7 @@ export function toMarkdown(summary, baselineSpec) { '', `- 结果:${guard.passed ? '通过' : '失败'}`, `- 统一退化阈值:${guard.thresholds.regressionPercent}%`, + `- 时间回归绝对下限:${fmtMs(guard.thresholds.minimumTimingRegressionMs)}ms`, `- 违规项:${guard.violations.length}`, ...guard.violations.map(item => `- ${item.key} / ${item.metric}: ${item.message ?? `${fmtMs(item.baseline)} -> ${fmtMs(item.current)} (${fmtPct(item.deltaPercent)})`}`), ].join('\n') diff --git a/packages/weapp-tailwindcss/src/compiler/runtime-affecting-signature.ts b/packages/weapp-tailwindcss/src/compiler/runtime-affecting-signature.ts index a381a12395..7d005e945d 100644 --- a/packages/weapp-tailwindcss/src/compiler/runtime-affecting-signature.ts +++ b/packages/weapp-tailwindcss/src/compiler/runtime-affecting-signature.ts @@ -1,9 +1,6 @@ -import type { NodePath } from '@babel/traverse' -import type { JSXText, StringLiteral, TemplateElement } from '@babel/types' import type { RuntimeEntryType } from './runtime-snapshot' import { Parser } from 'htmlparser2' -import { traverse } from '@/babel' -import { babelParse } from '@/js/babel' +import { babelParse } from '@/js/babel/parse' const CSS_BLOCK_COMMENT_RE = /\/\*[\s\S]*?\*\//g const CSS_AROUND_PUNCTUATION_RE = /\s*([{}:;,>+~()])\s*/g @@ -11,6 +8,25 @@ const CSS_TRAILING_DECLARATION_SEMICOLON_RE = /;\}/g const CSS_WHITESPACE_RE = /\s+/g const JS_RUNTIME_AFFECTING_TEXT_HINT_RE = /["'`/]/ const JS_INCOMPLETE_TRAILING_OPERATOR_RE = /(?:=>|[=+\-*%&|^!~?:,.({[\]])\s*$/ +const JS_AST_IGNORED_KEYS = new Set([ + 'comments', + 'errors', + 'extra', + 'innerComments', + 'leadingComments', + 'loc', + 'tokens', + 'trailingComments', +]) + +interface AstNode { + type: string + [key: string]: unknown +} + +function isAstNode(value: unknown): value is AstNode { + return Boolean(value && typeof value === 'object' && typeof (value as { type?: unknown }).type === 'string') +} function createHtmlRuntimeAffectingSignature(source: string) { try { @@ -56,30 +72,57 @@ function createJsRuntimeAffectingSignature(source: string) { try { const ast = babelParse(source, { - cache: false, - cacheKey: 'compiler-runtime-affecting:unambiguous', + cache: true, + cacheKey: 'st:unambiguous', plugins: ['jsx', 'typescript'], sourceType: 'unambiguous', }) const parts: string[] = [] - traverse(ast, { - noScope: true, - StringLiteral(path: NodePath) { - parts.push(`s:${path.node.value}`) - }, - TemplateElement(path: NodePath) { - parts.push(`t:${path.node.value.raw}`) - }, - JSXText(path: NodePath) { - const value = path.node.value.trim() + const stack: AstNode[] = [ast as unknown as AstNode] + while (stack.length > 0) { + const node = stack.pop()! + if (node.type === 'StringLiteral' && typeof node.value === 'string') { + parts.push(`s:${node.value}`) + } + else if ( + node.type === 'TemplateElement' + && node.value + && typeof node.value === 'object' + && 'raw' in node.value + && typeof node.value.raw === 'string' + ) { + parts.push(`t:${node.value.raw}`) + } + else if (node.type === 'JSXText' && typeof node.value === 'string') { + const value = node.value.trim() if (value.length > 0) { parts.push(`x:${value}`) } - }, - } as any) + } + + const children: AstNode[] = [] + for (const [key, value] of Object.entries(node)) { + if (JS_AST_IGNORED_KEYS.has(key)) { + continue + } + if (Array.isArray(value)) { + for (const item of value) { + if (isAstNode(item)) { + children.push(item) + } + } + } + else if (isAstNode(value)) { + children.push(value) + } + } + for (let index = children.length - 1; index >= 0; index--) { + stack.push(children[index]!) + } + } - const comments = (ast as any).comments + const comments = (ast as unknown as { comments?: Array<{ value?: unknown }> }).comments if (Array.isArray(comments)) { for (const comment of comments) { if (typeof comment?.value === 'string' && comment.value.length > 0) { diff --git a/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts b/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts index 2d78ffd5e4..754341e7cc 100644 --- a/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts +++ b/packages/weapp-tailwindcss/test/build/tsdown-config.test.ts @@ -6,7 +6,9 @@ import { createTsdownConfigs, externalizeEsmRuntimeDeps, moduleOutExtensions, + runtimeCjsEntries, runtimeEntries, + webpackLoaderEntries, } from '../../tsdown.shared.mts' describe('tsdown build layout', () => { @@ -18,11 +20,13 @@ describe('tsdown build layout', () => { const cliCjsConfig = configs[3] expect(runtimeEsmConfig.entry).toEqual(runtimeEntries) - expect(runtimeCjsConfig.entry).toEqual(runtimeEntries) + expect(runtimeCjsConfig.entry).toEqual(runtimeCjsEntries) expect(runtimeEsmConfig.entry).not.toHaveProperty('cli') + expect(runtimeEsmConfig.entry).not.toHaveProperty('weapp-tw-css-import-rewrite-loader') expect(runtimeEsmConfig.entry).toHaveProperty('framework') expect(runtimeEsmConfig.entry).toHaveProperty('generator') expect(runtimeEsmConfig.entry).toHaveProperty('postcss') + expect(runtimeCjsConfig.entry).toMatchObject(webpackLoaderEntries) expect(cliEsmConfig.entry).toEqual(cliEntries) expect(cliCjsConfig.entry).toEqual(cliEntries) @@ -44,14 +48,14 @@ describe('tsdown build layout', () => { it('uses module-safe extensions and keeps webpack loaders as physical cjs files', () => { const configs = createTsdownConfigs() - const loaderConfig = configs[5] + const runtimeCjsConfig = configs[1] expect(configs[0].format).toEqual(['esm']) expect(configs[1].format).toEqual(['cjs']) expect(configs[2].format).toEqual(['esm']) expect(configs[3].format).toEqual(['cjs']) - expect(loaderConfig.format).toEqual(['cjs']) - expect(loaderConfig.deps?.alwaysBundle).toBe(bundleCjsRuntimeDeps) + expect(runtimeCjsConfig.entry).toMatchObject(webpackLoaderEntries) + expect(runtimeCjsConfig.deps?.alwaysBundle).toBe(bundleCjsRuntimeDeps) expect(moduleOutExtensions({ format: 'es' }).js).toBe('.js') expect(moduleOutExtensions({ format: 'cjs' }).js).toBe('.cjs') }) diff --git a/packages/weapp-tailwindcss/test/bundlers/vite-runtime-affecting-signature.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/vite-runtime-affecting-signature.unit.test.ts index e5592dedd3..51516ecf83 100644 --- a/packages/weapp-tailwindcss/test/bundlers/vite-runtime-affecting-signature.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/vite-runtime-affecting-signature.unit.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { createRuntimeAffectingSourceSignature } from '@/bundlers/vite/runtime-affecting-signature' -import { parseCache } from '@/js/babel' +import { babelParse, parseCache } from '@/js/babel/parse' describe('bundlers/vite runtime-affecting signature', () => { it('keeps html comment content in runtime-affecting signature', () => { @@ -33,13 +33,23 @@ describe('bundlers/vite runtime-affecting signature', () => { expect(second).toContain('c: text-[#654321] ') }) - it('does not retain runtime js signature parses in the global parser cache', () => { + it('seeds the parser cache for the downstream JS transform', () => { parseCache.clear() - - createRuntimeAffectingSourceSignature('const cls = "card"', 'js') - createRuntimeAffectingSourceSignature('const cls = "card next"', 'js') - - expect(parseCache.size).toBe(0) + const source = 'const cls = "card"' + + createRuntimeAffectingSourceSignature(source, 'js') + const cached = babelParse(source, { + cache: true, + cacheKey: 'st:unambiguous', + sourceType: 'unambiguous', + }) + + expect(parseCache.size).toBe(1) + expect(babelParse(source, { + cache: true, + cacheKey: 'st:unambiguous', + sourceType: 'unambiguous', + })).toBe(cached) }) it('skips js parser work when source has no runtime-affecting text hint', () => { diff --git a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts index 5a9139082f..4f467a259a 100644 --- a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts +++ b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts @@ -176,9 +176,55 @@ describe('benchmark ci report', () => { 'hmrPeakRssMb', ]) expect(result.thresholds.regressionPercent).toBe(5) + expect(result.thresholds.minimumTimingRegressionMs).toBe(10) expect(result.passed).toBe(false) }) + it('ignores sub-10ms timing drift while retaining the percentage guard for larger regressions', async () => { + const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') + const baselineLabel = 'base:main' + const currentLabel = 'current:feature' + const summary = buildSummary({ + generatedAt: '2026-07-20T00:00:00.000Z', + options: { buildRuns: 1, hmrRuns: 1, timeoutMs: 180000 }, + rows: [ + { + version: baselineLabel, + key: 'micro-noise', + hmrMode: 'watch', + summary: { hmrPlugin: { p95: 50 } }, + }, + { + version: currentLabel, + key: 'micro-noise', + hmrMode: 'watch', + summary: { hmrPlugin: { p95: 56 } }, + }, + { + version: baselineLabel, + key: 'real-regression', + hmrMode: 'watch', + summary: { hmrPlugin: { p95: 100 } }, + }, + { + version: currentLabel, + key: 'real-regression', + hmrMode: 'watch', + summary: { hmrPlugin: { p95: 111 } }, + }, + ], + }, baselineLabel, currentLabel) + + const result = evaluatePerformanceGuard(summary) + + expect(result.violations).not.toContainEqual(expect.objectContaining({ key: 'micro-noise' })) + expect(result.violations).toContainEqual(expect.objectContaining({ + key: 'real-regression', + metric: 'hmrPluginP95', + absoluteDelta: 11, + })) + }) + it('uses the full build plugin median so one steady-sample outlier cannot dominate the guard', async () => { const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') const baselineLabel = 'base:main' diff --git a/packages/weapp-tailwindcss/tsdown.shared.mts b/packages/weapp-tailwindcss/tsdown.shared.mts index afa742f94a..09a5132452 100644 --- a/packages/weapp-tailwindcss/tsdown.shared.mts +++ b/packages/weapp-tailwindcss/tsdown.shared.mts @@ -37,6 +37,11 @@ export const webpackLoaderEntries = { 'weapp-tw-css-import-rewrite-loader': 'src/bundlers/webpack/loaders/weapp-tw-css-import-rewrite-loader.ts', } as const +export const runtimeCjsEntries = { + ...runtimeEntries, + ...webpackLoaderEntries, +} as const + function externalizeCommonRuntimeDeps(id: string) { return id === 'webpack' || id === 'tailwindcss/plugin' @@ -95,7 +100,8 @@ export function createTsdownConfigs(options: WatchAwareOptions = {}) { outExtensions: moduleOutExtensions, }, { - entry: runtimeEntries, + // loaders 与 runtime 共用构建图,避免 Babel 8 等 ESM-only 依赖被重复内联。 + entry: runtimeCjsEntries, dts: false, clean: false, shims: true, @@ -146,18 +152,5 @@ export function createTsdownConfigs(options: WatchAwareOptions = {}) { target: ['es2020'], outExtensions: moduleOutExtensions, }, - { - entry: webpackLoaderEntries, - dts: false, - clean: false, - shims: true, - format: ['cjs'], - deps: { - alwaysBundle: bundleCjsRuntimeDeps, - neverBundle: externalizeCommonRuntimeDeps, - onlyBundle: false, - }, - outExtensions: moduleOutExtensions, - }, ] } From 6c81bbcd4f9d891b1cc1abebfa25e791b73e0ae6 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 18:22:15 +0800 Subject: [PATCH 06/14] fix(ci): stabilize micro benchmark statistics --- .../version-compare/scripts/ci-report.mjs | 26 +++++--- benchmark/version-compare/scripts/run-ci.mjs | 3 + .../test/ci/benchmark-report.test.ts | 59 +++++++++++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/benchmark/version-compare/scripts/ci-report.mjs b/benchmark/version-compare/scripts/ci-report.mjs index d3cc089bde..8741e6f164 100644 --- a/benchmark/version-compare/scripts/ci-report.mjs +++ b/benchmark/version-compare/scripts/ci-report.mjs @@ -33,6 +33,10 @@ function sampleCount(row, field) { return Array.isArray(row?.[field]) ? row[field].length : undefined } +function hmrPluginStatistic(row) { + return row?.hmrPluginStatistic === 'median' ? 'median' : 'p95' +} + function average(values) { const validValues = values.filter(value => typeof value === 'number' && Number.isFinite(value)) return validValues.length ? validValues.reduce((sum, value) => sum + value, 0) / validValues.length : undefined @@ -57,8 +61,10 @@ export function buildSummary(raw, baselineLabel, currentLabel) { const currentHmr = summaryMetric(current, 'hmr', 'p95') const baselineBuildPlugin = summaryMetric(baseline, 'buildPlugin') const currentBuildPlugin = summaryMetric(current, 'buildPlugin') - const baselineHmrPlugin = summaryMetric(baseline, 'hmrPlugin', 'p95') - const currentHmrPlugin = summaryMetric(current, 'hmrPlugin', 'p95') + const baselineHmrPluginStatistic = hmrPluginStatistic(baseline) + const currentHmrPluginStatistic = hmrPluginStatistic(current) + const baselineHmrPlugin = summaryMetric(baseline, 'hmrPlugin', baselineHmrPluginStatistic) + const currentHmrPlugin = summaryMetric(current, 'hmrPlugin', currentHmrPluginStatistic) const baselineBuildPeakRssMb = memoryMetric(baseline, 'buildPeakRssMb') const currentBuildPeakRssMb = memoryMetric(current, 'buildPeakRssMb') const baselineBuildSteadyRssMb = memoryMetric(baseline, 'buildSteadyRssMb') @@ -85,6 +91,9 @@ export function buildSummary(raw, baselineLabel, currentLabel) { buildPluginDeltaPct: pct(baselineBuildPlugin, currentBuildPlugin), baselineHmrPlugin, currentHmrPlugin, + hmrPluginStatistic: baselineHmrPluginStatistic === currentHmrPluginStatistic + ? currentHmrPluginStatistic + : `${baselineHmrPluginStatistic}->${currentHmrPluginStatistic}`, hmrPluginDeltaPct: pct(baselineHmrPlugin, currentHmrPlugin), baselineBuildPeakRssMb, currentBuildPeakRssMb, @@ -272,9 +281,12 @@ export function evaluatePerformanceGuard(summary, options = {}) { const absoluteDelta = current - baseline const minimumAbsoluteDelta = config.timing ? minimumTimingRegressionMs : 0 if (deltaPercent > regressionPercent && absoluteDelta >= minimumAbsoluteDelta) { + const metric = config.metric === 'hmrPluginP95' && compare.hmrPluginStatistic === 'median' + ? 'hmrPluginMedian' + : config.metric violations.push({ key: compare.key, - metric: config.metric, + metric, baseline, current, deltaPercent, @@ -314,7 +326,7 @@ export function toMarkdown(summary, baselineSpec) { const errors = summary.errors.length ? summary.errors.map(item => `- ${item.version} / ${item.key}: ${String(item.error).split('\n')[0]}`).join('\n') : '- 无' - const pluginRows = summary.compares.map(item => `| ${item.key} | ${fmtMs(item.baselineBuildPlugin)} | ${fmtMs(item.currentBuildPlugin)} | ${fmtPct(item.buildPluginDeltaPct)} | ${fmtMs(item.baselineHmrPlugin)} | ${fmtMs(item.currentHmrPlugin)} | ${fmtPct(item.hmrPluginDeltaPct)} |`).join('\n') + const pluginRows = summary.compares.map(item => `| ${item.key} | ${fmtMs(item.baselineBuildPlugin)} | ${fmtMs(item.currentBuildPlugin)} | ${fmtPct(item.buildPluginDeltaPct)} | ${item.hmrPluginStatistic} | ${fmtMs(item.baselineHmrPlugin)} | ${fmtMs(item.currentHmrPlugin)} | ${fmtPct(item.hmrPluginDeltaPct)} |`).join('\n') const memoryRows = summary.compares.map(item => `| ${item.key} | ${fmtMs(item.baselineBuildPeakRssMb)} | ${fmtMs(item.currentBuildPeakRssMb)} | ${fmtPct(item.buildPeakRssDeltaPct)} | ${fmtMs(item.baselineBuildSteadyRssMb)} | ${fmtMs(item.currentBuildSteadyRssMb)} | ${fmtPct(item.buildSteadyRssDeltaPct)} | ${fmtMs(item.baselineHmrPeakRssMb)} | ${fmtMs(item.currentHmrPeakRssMb)} | ${fmtPct(item.hmrPeakRssDeltaPct)} | ${fmtMs(item.baselineHmrSteadyRssMb)} | ${fmtMs(item.currentHmrSteadyRssMb)} | ${fmtPct(item.hmrSteadyRssDeltaPct)} |`).join('\n') const baselineDisplay = summary.baseline.startsWith('base:') ? baselineSpec @@ -348,7 +360,7 @@ export function toMarkdown(summary, baselineSpec) { - 冷构建中位数平均变化:${fmtPct(summary.averages.buildDeltaPct)}(${summary.averages.buildCompareCount} 项) - 真实 watch HMR P95 平均变化:${fmtPct(summary.averages.hmrDeltaPct)}(${summary.averages.watchHmrCompareCount} 项;fallback-build/unsupported 不参与) - 插件 Build 中位数平均变化:${fmtPct(summary.averages.buildPluginDeltaPct)}(${summary.averages.buildPluginCompareCount} 项) -- 插件 HMR P95 平均变化:${fmtPct(summary.averages.hmrPluginDeltaPct)}(${summary.averages.watchHmrPluginCompareCount} 项) +- 插件 HMR 门禁统计平均变化:${fmtPct(summary.averages.hmrPluginDeltaPct)}(${summary.averages.watchHmrPluginCompareCount} 项) - 失败项:${summary.errors.length} - 当前版本独有失败项:${summary.currentOnlyErrors.length} - 基线/当前共同失败项:${summary.sharedErrors.length} @@ -361,8 +373,8 @@ ${rows} ## 插件处理阶段 -| 项目 | Baseline Build Plugin median(ms) | Current Build Plugin median(ms) | Build Plugin 变化 | Baseline HMR Plugin P95(ms) | Current HMR Plugin P95(ms) | HMR Plugin 变化 | -| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| 项目 | Baseline Build Plugin median(ms) | Current Build Plugin median(ms) | Build Plugin 变化 | HMR 统计 | Baseline HMR Plugin(ms) | Current HMR Plugin(ms) | HMR Plugin 变化 | +| --- | ---: | ---: | ---: | --- | ---: | ---: | ---: | ${pluginRows} ## 内存 diff --git a/benchmark/version-compare/scripts/run-ci.mjs b/benchmark/version-compare/scripts/run-ci.mjs index 0f16c6e588..8d4b0b8466 100644 --- a/benchmark/version-compare/scripts/run-ci.mjs +++ b/benchmark/version-compare/scripts/run-ci.mjs @@ -348,6 +348,7 @@ function createSourceCandidateBenchmarkRow(version, root, result) { buildNote: 'internal hot-update micro benchmark', hmrMode: 'watch', hmrNote: 'plugin-only source candidate hot-update micro benchmark', + hmrPluginStatistic: 'median', buildMs: [], buildPluginMs: [], hmrMs: [], @@ -371,6 +372,7 @@ function createProcessedCssCoverageBenchmarkRow(version, root, result) { buildNote: 'internal processed css coverage micro benchmark', hmrMode: 'watch', hmrNote: 'plugin-only processed css coverage micro benchmark', + hmrPluginStatistic: 'median', buildMs: [], buildPluginMs: [], hmrMs: [], @@ -393,6 +395,7 @@ function createProcessedCssInjectionBenchmarkRow(version, root, result) { buildNote: 'internal processed css injection micro benchmark', hmrMode: 'watch', hmrNote: 'plugin-only processed css injection micro benchmark', + hmrPluginStatistic: 'median', buildMs: [], buildPluginMs: [], hmrMs: [], diff --git a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts index 4f467a259a..b1ed8af9a5 100644 --- a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts +++ b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts @@ -69,6 +69,7 @@ describe('benchmark ci report', () => { expect(source).toContain('core-vite-processed-css-coverage') expect(source).toContain('runProcessedCssInjectionBenchmark') expect(source).toContain('core-vite-processed-css-injection') + expect(source.match(/hmrPluginStatistic: 'median'/g)).toHaveLength(3) expect(source).toContain("parseNumber('--poll-interval', 30)") expect(matrixSource).toContain("parseNumber('--poll-interval', 30)") @@ -225,6 +226,64 @@ describe('benchmark ci report', () => { })) }) + it('uses the median for isolated core micro benchmarks while keeping watch plugins on P95', async () => { + const { buildSummary, evaluatePerformanceGuard, toMarkdown } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') + const baselineLabel = 'base:main' + const currentLabel = 'current:feature' + const summary = buildSummary({ + generatedAt: '2026-07-20T00:00:00.000Z', + options: { buildRuns: 1, hmrRuns: 3, timeoutMs: 180000 }, + rows: [ + { + version: baselineLabel, + key: 'core-vite-processed-css-coverage', + hmrMode: 'watch', + hmrPluginStatistic: 'median', + summary: { hmrPlugin: { median: 124, p95: 156 } }, + }, + { + version: currentLabel, + key: 'core-vite-processed-css-coverage', + hmrMode: 'watch', + hmrPluginStatistic: 'median', + summary: { hmrPlugin: { median: 118, p95: 171 } }, + }, + { + version: baselineLabel, + key: 'demo-watch', + hmrMode: 'watch', + summary: { hmrPlugin: { median: 80, p95: 100 } }, + }, + { + version: currentLabel, + key: 'demo-watch', + hmrMode: 'watch', + summary: { hmrPlugin: { median: 80, p95: 111 } }, + }, + ], + }, baselineLabel, currentLabel) + + expect(summary.compares).toEqual(expect.arrayContaining([ + expect.objectContaining({ + key: 'core-vite-processed-css-coverage', + baselineHmrPlugin: 124, + currentHmrPlugin: 118, + hmrPluginStatistic: 'median', + }), + expect.objectContaining({ + key: 'demo-watch', + baselineHmrPlugin: 100, + currentHmrPlugin: 111, + hmrPluginStatistic: 'p95', + }), + ])) + expect(evaluatePerformanceGuard(summary).violations).toContainEqual(expect.objectContaining({ + key: 'demo-watch', + metric: 'hmrPluginP95', + })) + expect(toMarkdown(summary, 'main')).toContain('| core-vite-processed-css-coverage | - | - | - | median | 124.00 | 118.00 |') + }) + it('uses the full build plugin median so one steady-sample outlier cannot dominate the guard', async () => { const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') const baselineLabel = 'base:main' From 31a5274d8fbe3ab14c07537348e6160afae2517c Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Mon, 20 Jul 2026 20:08:54 +0800 Subject: [PATCH 07/14] fix(ci): stabilize Babel 8 performance guard --- .changeset/babel-eight-module-packages.md | 2 +- .../version-compare/scripts/ci-report.mjs | 122 ++++++++++- .../scripts/processed-css-coverage.mts | 4 +- .../scripts/processed-css-injection.mts | 4 +- .../version-compare/scripts/projects.mjs | 3 +- .../scripts/source-candidate-hot-update.mts | 4 +- packages/weapp-tailwindcss/src/js/precheck.ts | 2 +- .../test/ci/benchmark-report.test.ts | 206 +++++++++++++++++- .../test/js/precheck.properties.test.ts | 1 - .../test/js/precheck.test.ts | 13 +- 10 files changed, 337 insertions(+), 24 deletions(-) diff --git a/.changeset/babel-eight-module-packages.md b/.changeset/babel-eight-module-packages.md index e4eb1df306..c83da4e1e7 100644 --- a/.changeset/babel-eight-module-packages.md +++ b/.changeset/babel-eight-module-packages.md @@ -12,4 +12,4 @@ "weapp-style-injector": patch --- -升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。 +升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。Webpack 产物中的 harmony import 注释与 JSDoc import type 不再误触发模块图解析。 diff --git a/benchmark/version-compare/scripts/ci-report.mjs b/benchmark/version-compare/scripts/ci-report.mjs index 8741e6f164..14fd5bd0e6 100644 --- a/benchmark/version-compare/scripts/ci-report.mjs +++ b/benchmark/version-compare/scripts/ci-report.mjs @@ -33,6 +33,12 @@ function sampleCount(row, field) { return Array.isArray(row?.[field]) ? row[field].length : undefined } +function numericSamples(row, field) { + return Array.isArray(row?.[field]) + ? row[field].filter(value => typeof value === 'number' && Number.isFinite(value)) + : undefined +} + function hmrPluginStatistic(row) { return row?.hmrPluginStatistic === 'median' ? 'median' : 'p95' } @@ -57,10 +63,14 @@ export function buildSummary(raw, baselineLabel, currentLabel) { const baseline = byKey.get(`${baselineLabel}::${current.key}`) const baselineBuild = summaryMetric(baseline, 'build') const currentBuild = summaryMetric(current, 'build') + const baselineHmrMedian = summaryMetric(baseline, 'hmr') + const currentHmrMedian = summaryMetric(current, 'hmr') const baselineHmr = summaryMetric(baseline, 'hmr', 'p95') const currentHmr = summaryMetric(current, 'hmr', 'p95') const baselineBuildPlugin = summaryMetric(baseline, 'buildPlugin') const currentBuildPlugin = summaryMetric(current, 'buildPlugin') + const baselineHmrPluginMedian = summaryMetric(baseline, 'hmrPlugin') + const currentHmrPluginMedian = summaryMetric(current, 'hmrPlugin') const baselineHmrPluginStatistic = hmrPluginStatistic(baseline) const currentHmrPluginStatistic = hmrPluginStatistic(current) const baselineHmrPlugin = summaryMetric(baseline, 'hmrPlugin', baselineHmrPluginStatistic) @@ -86,6 +96,9 @@ export function buildSummary(raw, baselineLabel, currentLabel) { baselineHmr, currentHmr, hmrDeltaPct: pct(baselineHmr, currentHmr), + baselineHmrMedian, + currentHmrMedian, + hmrMedianDeltaPct: pct(baselineHmrMedian, currentHmrMedian), baselineBuildPlugin, currentBuildPlugin, buildPluginDeltaPct: pct(baselineBuildPlugin, currentBuildPlugin), @@ -95,6 +108,9 @@ export function buildSummary(raw, baselineLabel, currentLabel) { ? currentHmrPluginStatistic : `${baselineHmrPluginStatistic}->${currentHmrPluginStatistic}`, hmrPluginDeltaPct: pct(baselineHmrPlugin, currentHmrPlugin), + baselineHmrPluginMedian, + currentHmrPluginMedian, + hmrPluginMedianDeltaPct: pct(baselineHmrPluginMedian, currentHmrPluginMedian), baselineBuildPeakRssMb, currentBuildPeakRssMb, buildPeakRssDeltaPct: pct(baselineBuildPeakRssMb, currentBuildPeakRssMb), @@ -111,6 +127,10 @@ export function buildSummary(raw, baselineLabel, currentLabel) { currentHmrSampleCount: sampleCount(current, 'hmrMs'), baselineHmrPluginSampleCount: sampleCount(baseline, 'hmrPluginMs'), currentHmrPluginSampleCount: sampleCount(current, 'hmrPluginMs'), + baselineHmrSamples: numericSamples(baseline, 'hmrMs'), + currentHmrSamples: numericSamples(current, 'hmrMs'), + baselineHmrPluginSamples: numericSamples(baseline, 'hmrPluginMs'), + currentHmrPluginSamples: numericSamples(current, 'hmrPluginMs'), baselineMemoryStability: baseline?.memoryStability, currentMemoryStability: current.memoryStability, baselineBuildMode: baseline?.buildMode ?? 'build', @@ -191,6 +211,8 @@ export function buildSummary(raw, baselineLabel, currentLabel) { export function evaluatePerformanceGuard(summary, options = {}) { const regressionPercent = toNumber(options.regressionPercent) ?? 5 const minimumTimingRegressionMs = toNumber(options.minimumTimingRegressionMs) ?? 10 + const minimumMemoryRegressionMb = toNumber(options.minimumMemoryRegressionMb) ?? 64 + const minimumTailRegressionSamples = Math.max(1, Math.floor(toNumber(options.minimumTailRegressionSamples) ?? 2)) const violations = summary.currentOnlyErrors.map(item => ({ key: item.key, metric: 'error', @@ -198,13 +220,15 @@ export function evaluatePerformanceGuard(summary, options = {}) { })) const metrics = [ { metric: 'buildMedian', baseline: 'baselineBuild', current: 'currentBuild', delta: 'buildDeltaPct', timing: true }, - { metric: 'hmrP95', baseline: 'baselineHmr', current: 'currentHmr', delta: 'hmrDeltaPct', timing: true, watchOnly: true }, + { metric: 'hmrMedian', baseline: 'baselineHmrMedian', current: 'currentHmrMedian', delta: 'hmrMedianDeltaPct', timing: true, watchOnly: true, tailSamples: 'currentHmrSamples', medianSamples: true, pluginConfirmation: { baseline: 'baselineHmrPluginMedian', current: 'currentHmrPluginMedian', delta: 'hmrPluginMedianDeltaPct', tailSamples: 'currentHmrPluginSamples', medianSamples: true } }, + { metric: 'hmrP95', baseline: 'baselineHmr', current: 'currentHmr', delta: 'hmrDeltaPct', timing: true, watchOnly: true, tailSamples: 'currentHmrSamples', pluginConfirmation: { baseline: 'baselineHmrPlugin', current: 'currentHmrPlugin', delta: 'hmrPluginDeltaPct', tailSamples: 'currentHmrPluginSamples' } }, { metric: 'buildPluginMedian', baseline: 'baselineBuildPlugin', current: 'currentBuildPlugin', delta: 'buildPluginDeltaPct', timing: true }, - { metric: 'hmrPluginP95', baseline: 'baselineHmrPlugin', current: 'currentHmrPlugin', delta: 'hmrPluginDeltaPct', timing: true, watchOnly: true }, - { metric: 'buildPeakRssMb', baseline: 'baselineBuildPeakRssMb', current: 'currentBuildPeakRssMb', delta: 'buildPeakRssDeltaPct' }, - { metric: 'buildSteadyRssMb', baseline: 'baselineBuildSteadyRssMb', current: 'currentBuildSteadyRssMb', delta: 'buildSteadyRssDeltaPct' }, - { metric: 'hmrPeakRssMb', baseline: 'baselineHmrPeakRssMb', current: 'currentHmrPeakRssMb', delta: 'hmrPeakRssDeltaPct', watchOnly: true }, - { metric: 'hmrSteadyRssMb', baseline: 'baselineHmrSteadyRssMb', current: 'currentHmrSteadyRssMb', delta: 'hmrSteadyRssDeltaPct', watchOnly: true }, + { metric: 'hmrPluginMedian', baseline: 'baselineHmrPluginMedian', current: 'currentHmrPluginMedian', delta: 'hmrPluginMedianDeltaPct', timing: true, watchOnly: true, tailSamples: 'currentHmrPluginSamples', medianSamples: true }, + { metric: 'hmrPluginP95', baseline: 'baselineHmrPlugin', current: 'currentHmrPlugin', delta: 'hmrPluginDeltaPct', timing: true, watchOnly: true, tailSamples: 'currentHmrPluginSamples', p95PluginOnly: true }, + { metric: 'buildPeakRssMb', baseline: 'baselineBuildPeakRssMb', current: 'currentBuildPeakRssMb', delta: 'buildPeakRssDeltaPct', memory: true }, + { metric: 'buildSteadyRssMb', baseline: 'baselineBuildSteadyRssMb', current: 'currentBuildSteadyRssMb', delta: 'buildSteadyRssDeltaPct', memory: true }, + { metric: 'hmrPeakRssMb', baseline: 'baselineHmrPeakRssMb', current: 'currentHmrPeakRssMb', delta: 'hmrPeakRssDeltaPct', memory: true, watchOnly: true, steadyConfirmation: true }, + { metric: 'hmrSteadyRssMb', baseline: 'baselineHmrSteadyRssMb', current: 'currentHmrSteadyRssMb', delta: 'hmrSteadyRssDeltaPct', memory: true, watchOnly: true }, ] for (const compare of summary.compares) { @@ -272,6 +296,12 @@ export function evaluatePerformanceGuard(summary, options = {}) { if (config.metric === 'hmrP95' && compare.hmrEndToEndGuard === false) { continue } + if (config.metric === 'hmrMedian' && compare.hmrEndToEndGuard === false) { + continue + } + if (config.p95PluginOnly && compare.hmrPluginStatistic !== 'p95') { + continue + } const baseline = toNumber(compare[config.baseline]) const current = toNumber(compare[config.current]) const deltaPercent = toNumber(compare[config.delta]) @@ -279,18 +309,82 @@ export function evaluatePerformanceGuard(summary, options = {}) { continue } const absoluteDelta = current - baseline - const minimumAbsoluteDelta = config.timing ? minimumTimingRegressionMs : 0 + const minimumAbsoluteDelta = config.timing + ? minimumTimingRegressionMs + : config.memory + ? minimumMemoryRegressionMb + : 0 if (deltaPercent > regressionPercent && absoluteDelta >= minimumAbsoluteDelta) { - const metric = config.metric === 'hmrPluginP95' && compare.hmrPluginStatistic === 'median' - ? 'hmrPluginMedian' - : config.metric + if (config.pluginConfirmation) { + const pluginBaseline = toNumber(compare[config.pluginConfirmation.baseline]) + const pluginCurrent = toNumber(compare[config.pluginConfirmation.current]) + const pluginDeltaPercent = toNumber(compare[config.pluginConfirmation.delta]) + if ( + pluginBaseline !== undefined + && pluginCurrent !== undefined + && pluginDeltaPercent !== undefined + ) { + const pluginTailSamples = config.pluginConfirmation.tailSamples + ? compare[config.pluginConfirmation.tailSamples] + : undefined + const regressedPluginTailSamples = Array.isArray(pluginTailSamples) + ? pluginTailSamples.filter((sample) => { + const sampleDelta = sample - pluginBaseline + return pct(pluginBaseline, sample) > regressionPercent && sampleDelta >= minimumTimingRegressionMs + }).length + : undefined + const requiredPluginRegressionSamples = config.pluginConfirmation.medianSamples && Array.isArray(pluginTailSamples) + ? Math.floor(pluginTailSamples.length / 2) + 1 + : minimumTailRegressionSamples + if ( + pluginDeltaPercent <= regressionPercent + || pluginCurrent - pluginBaseline < minimumTimingRegressionMs + || (regressedPluginTailSamples !== undefined && regressedPluginTailSamples < requiredPluginRegressionSamples) + ) { + continue + } + } + } + if (config.steadyConfirmation) { + const steadyBaseline = toNumber(compare.baselineHmrSteadyRssMb) + const steadyCurrent = toNumber(compare.currentHmrSteadyRssMb) + const steadyDeltaPercent = toNumber(compare.hmrSteadyRssDeltaPct) + if ( + steadyBaseline === undefined + || steadyCurrent === undefined + || steadyDeltaPercent === undefined + || steadyDeltaPercent <= regressionPercent + || steadyCurrent - steadyBaseline < minimumMemoryRegressionMb + ) { + continue + } + } + const tailSamples = config.tailSamples ? compare[config.tailSamples] : undefined + const regressedTailSamples = Array.isArray(tailSamples) + ? tailSamples.filter((sample) => { + const sampleDelta = sample - baseline + return pct(baseline, sample) > regressionPercent && sampleDelta >= minimumTimingRegressionMs + }).length + : undefined + const requiredRegressionSamples = config.medianSamples && Array.isArray(tailSamples) + ? Math.floor(tailSamples.length / 2) + 1 + : minimumTailRegressionSamples + if (regressedTailSamples !== undefined && regressedTailSamples < requiredRegressionSamples) { + continue + } violations.push({ key: compare.key, - metric, + metric: config.metric, baseline, current, deltaPercent, absoluteDelta, + ...(regressedTailSamples === undefined + ? {} + : { + regressionSamples: regressedTailSamples, + requiredRegressionSamples, + }), thresholdPercent: regressionPercent, }) } @@ -300,6 +394,8 @@ export function evaluatePerformanceGuard(summary, options = {}) { return { passed: violations.length === 0, thresholds: { + minimumMemoryRegressionMb, + minimumTailRegressionSamples, minimumTimingRegressionMs, regressionPercent, }, @@ -340,6 +436,10 @@ export function toMarkdown(summary, baselineSpec) { `- 结果:${guard.passed ? '通过' : '失败'}`, `- 统一退化阈值:${guard.thresholds.regressionPercent}%`, `- 时间回归绝对下限:${fmtMs(guard.thresholds.minimumTimingRegressionMs)}ms`, + `- 内存回归绝对下限:${fmtMs(guard.thresholds.minimumMemoryRegressionMb)}MB`, + `- P95 尾部回归最少样本:${guard.thresholds.minimumTailRegressionSamples}`, + '- 中位数回归需严格多数样本同步越界', + '- 端到端 HMR 回归需插件处理阶段同步越界确认', `- 违规项:${guard.violations.length}`, ...guard.violations.map(item => `- ${item.key} / ${item.metric}: ${item.message ?? `${fmtMs(item.baseline)} -> ${fmtMs(item.current)} (${fmtPct(item.deltaPercent)})`}`), ].join('\n') diff --git a/benchmark/version-compare/scripts/processed-css-coverage.mts b/benchmark/version-compare/scripts/processed-css-coverage.mts index 25bff26d72..8a60012f68 100644 --- a/benchmark/version-compare/scripts/processed-css-coverage.mts +++ b/benchmark/version-compare/scripts/processed-css-coverage.mts @@ -15,6 +15,8 @@ interface RemoveCssCoveredByRootStyleBundleSources { (bundle: Record, file: string, css: string): string } +const BENCHMARK_SAMPLE_COUNT = 7 + function summarize(values: number[]): BenchmarkStats { const sorted = [...values].sort((a, b) => a - b) const mean = values.reduce((sum, value) => sum + value, 0) / values.length @@ -90,7 +92,7 @@ async function main() { const { removeCssCoveredByRootStyleBundleSources } = await import(pathToFileURL(sourceFile).href) runSample(removeCssCoveredByRootStyleBundleSources) const samples: number[] = [] - for (let index = 0; index < 3; index++) { + for (let index = 0; index < BENCHMARK_SAMPLE_COUNT; index++) { samples.push(runSample(removeCssCoveredByRootStyleBundleSources)) } process.stdout.write(`${JSON.stringify({ diff --git a/benchmark/version-compare/scripts/processed-css-injection.mts b/benchmark/version-compare/scripts/processed-css-injection.mts index be37729703..7bc4c1c2f6 100644 --- a/benchmark/version-compare/scripts/processed-css-injection.mts +++ b/benchmark/version-compare/scripts/processed-css-injection.mts @@ -15,6 +15,8 @@ interface InjectViteProcessedCssIntoMainCssAssets { (bundle: Record, options: Record): number } +const BENCHMARK_SAMPLE_COUNT = 7 + function summarize(values: number[]): BenchmarkStats { const sorted = [...values].sort((a, b) => a - b) const mean = values.reduce((sum, value) => sum + value, 0) / values.length @@ -107,7 +109,7 @@ async function main() { const { injectViteProcessedCssIntoMainCssAssets } = await import(pathToFileURL(sourceFile).href) runSample(injectViteProcessedCssIntoMainCssAssets) const samples: number[] = [] - for (let index = 0; index < 3; index++) { + for (let index = 0; index < BENCHMARK_SAMPLE_COUNT; index++) { samples.push(runSample(injectViteProcessedCssIntoMainCssAssets)) } process.stdout.write(`${JSON.stringify({ diff --git a/benchmark/version-compare/scripts/projects.mjs b/benchmark/version-compare/scripts/projects.mjs index 0f08f79b93..2bdb3586da 100644 --- a/benchmark/version-compare/scripts/projects.mjs +++ b/benchmark/version-compare/scripts/projects.mjs @@ -24,8 +24,9 @@ export const benchmarkProjects = [ devScript: 'dev:e2e-watch', injectType: 'vue', hmrMode: 'watch', + hmrPluginStatistic: 'median', hmrEndToEndGuard: false, - hmrGuardNote: 'Mpx watch completion includes framework rebuild and output flush variance; processAssets timing remains guarded', + hmrGuardNote: 'Mpx watch completion includes framework rebuild and output flush variance; processAssets median remains guarded', }, { key: 'demo-taro-vite-react-tailwindcss-v4__mp-weixin', diff --git a/benchmark/version-compare/scripts/source-candidate-hot-update.mts b/benchmark/version-compare/scripts/source-candidate-hot-update.mts index e753fc6567..1ae25b0ae7 100644 --- a/benchmark/version-compare/scripts/source-candidate-hot-update.mts +++ b/benchmark/version-compare/scripts/source-candidate-hot-update.mts @@ -28,6 +28,8 @@ interface MemoryStabilityResult { steadyHeapUsedMb: number } +const BENCHMARK_SAMPLE_COUNT = 7 + function summarize(values: number[]): BenchmarkStats { const sorted = [...values].sort((a, b) => a - b) const mean = values.reduce((sum, value) => sum + value, 0) / values.length @@ -110,7 +112,7 @@ async function main() { } const { createSourceCandidateStore } = await import(pathToFileURL(sourceFile).href) const samples: number[] = [] - for (let index = 0; index < 3; index++) { + for (let index = 0; index < BENCHMARK_SAMPLE_COUNT; index++) { samples.push(await runSample(createSourceCandidateStore)) } const memoryStability = await runMemoryStability(createSourceCandidateStore) diff --git a/packages/weapp-tailwindcss/src/js/precheck.ts b/packages/weapp-tailwindcss/src/js/precheck.ts index a148eba08f..8808d4a31c 100644 --- a/packages/weapp-tailwindcss/src/js/precheck.ts +++ b/packages/weapp-tailwindcss/src/js/precheck.ts @@ -5,7 +5,7 @@ import process from 'node:process' const FAST_JS_TRANSFORM_HINT_RE = /className\b|class\s*=|classList\.|\b(?:twMerge|clsx|classnames|cn|cva)\b|\[["'`]class["'`]\]|text-\[|bg-\[|\b(?:[whpm]|px|py|mx|my|rounded|flex|grid|gap)-/ /** 用于检测源码中是否包含 import/export/require 语句的正则表达式 */ -const DEPENDENCY_HINT_RE = /\bimport\s*[("'`{*]|\brequire\s*\(|\bexport\s+\*\s+from\s+["'`]|\bexport\s*\{[^}]*\}\s*from\s+["'`]/ +const DEPENDENCY_HINT_RE = /\bimport\s*(?:["'`{]|\*\s+as\b)|\brequire\s*\(|\bexport\s+\*\s+from\s+["'`]|\bexport\s*\{[^}]*\}\s*from\s+["'`]/ /** * 判断源码是否可能声明跨模块依赖。 diff --git a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts index b1ed8af9a5..413adf7766 100644 --- a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts +++ b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts @@ -47,8 +47,9 @@ describe('benchmark ci report', () => { const mpxMpWeixin = benchmarkProjects.find(project => project.key === 'demo-mpx-tailwindcss-v4__mp-weixin') expect(mpxMpWeixin?.devScript).toBe('dev:e2e-watch') expect(mpxMpWeixin?.hmrMode).toBe('watch') + expect(mpxMpWeixin?.hmrPluginStatistic).toBe('median') expect(mpxMpWeixin?.hmrEndToEndGuard).toBe(false) - expect(mpxMpWeixin?.hmrGuardNote).toContain('processAssets timing remains guarded') + expect(mpxMpWeixin?.hmrGuardNote).toContain('processAssets median remains guarded') expect(benchmarkProjects.filter(project => project.key.includes('taro') && project.target === 'mp-weixin').every(project => project.hmrMode === 'watch')).toBe(true) const realDevServerTargets = benchmarkProjects.filter(project => (project.target === 'h5' || project.target === 'web') && !project.key.includes('hbuilderx')) expect(realDevServerTargets.every(project => project.hmrMode === 'watch')).toBe(true) @@ -72,6 +73,14 @@ describe('benchmark ci report', () => { expect(source.match(/hmrPluginStatistic: 'median'/g)).toHaveLength(3) expect(source).toContain("parseNumber('--poll-interval', 30)") expect(matrixSource).toContain("parseNumber('--poll-interval', 30)") + for (const benchmarkScript of [ + 'source-candidate-hot-update.mts', + 'processed-css-coverage.mts', + 'processed-css-injection.mts', + ]) { + const benchmarkSource = fs.readFileSync(path.resolve(__dirname, '../../../../benchmark/version-compare/scripts', benchmarkScript), 'utf8') + expect(benchmarkSource).toContain('const BENCHMARK_SAMPLE_COUNT = 7') + } const projectLoopIndex = matrixSource.indexOf('for (const projectMeta of selectedProjects)') const versionLoopIndex = matrixSource.indexOf('for (const versionMeta of versions)', projectLoopIndex) @@ -123,7 +132,7 @@ describe('benchmark ci report', () => { expect(round.lines).not.toContain('after-round') }) - it('guards cold build median, HMR P95, plugin timing and memory with one 5% limit', async () => { + it('guards cold build median, HMR timing and sustained memory regressions', async () => { const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') const baselineLabel = 'base:main' const currentLabel = 'current:feature' @@ -160,9 +169,9 @@ describe('benchmark ci report', () => { buildPlugin: { median: 211 }, hmrPlugin: { p95: 105 }, buildPeakRssMb: { median: 1050 }, - buildSteadyRssMb: { median: 841 }, - hmrPeakRssMb: { median: 1261 }, - hmrSteadyRssMb: { median: 945 }, + buildSteadyRssMb: { median: 865 }, + hmrPeakRssMb: { median: 1265 }, + hmrSteadyRssMb: { median: 965 }, }, }, ], @@ -175,12 +184,199 @@ describe('benchmark ci report', () => { 'buildPluginMedian', 'buildSteadyRssMb', 'hmrPeakRssMb', + 'hmrSteadyRssMb', ]) expect(result.thresholds.regressionPercent).toBe(5) expect(result.thresholds.minimumTimingRegressionMs).toBe(10) + expect(result.thresholds.minimumMemoryRegressionMb).toBe(64) + expect(result.thresholds.minimumTailRegressionSamples).toBe(2) expect(result.passed).toBe(false) }) + it('requires sustained median or two tail samples before failing small-sample HMR timing', async () => { + const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') + const baselineLabel = 'base:main' + const currentLabel = 'current:feature' + const summary = buildSummary({ + generatedAt: '2026-07-20T00:00:00.000Z', + options: { buildRuns: 1, hmrRuns: 6, timeoutMs: 180000 }, + rows: [ + { + version: baselineLabel, + key: 'single-tail-outlier', + hmrMode: 'watch', + hmrMs: [90, 92, 94, 96, 98, 100], + hmrPluginMs: [40, 42, 44, 46, 48, 50], + summary: { + hmr: { median: 95, p95: 100 }, + hmrPlugin: { median: 45, p95: 50 }, + }, + }, + { + version: currentLabel, + key: 'single-tail-outlier', + hmrMode: 'watch', + hmrMs: [91, 93, 95, 97, 99, 300], + hmrPluginMs: [41, 43, 45, 47, 49, 200], + summary: { + hmr: { median: 96, p95: 300 }, + hmrPlugin: { median: 46, p95: 200 }, + }, + }, + { + version: baselineLabel, + key: 'framework-only-median-regression', + hmrMode: 'watch', + hmrMs: [90, 92, 94, 96, 98, 100], + hmrPluginMs: [40, 42, 44, 46, 48, 50], + summary: { + hmr: { median: 95, p95: 100 }, + hmrPlugin: { median: 45, p95: 50 }, + }, + }, + { + version: currentLabel, + key: 'framework-only-median-regression', + hmrMode: 'watch', + hmrMs: [110, 112, 114, 116, 118, 120], + hmrPluginMs: [41, 43, 45, 47, 49, 51], + summary: { + hmr: { median: 115, p95: 120 }, + hmrPlugin: { median: 46, p95: 51 }, + }, + }, + { + version: baselineLabel, + key: 'two-tail-regressions', + hmrMode: 'watch', + hmrMs: [90, 92, 94, 96, 98, 100], + hmrPluginMs: [40, 42, 44, 46, 48, 50], + summary: { + hmr: { median: 95, p95: 100 }, + hmrPlugin: { median: 45, p95: 50 }, + }, + }, + { + version: currentLabel, + key: 'two-tail-regressions', + hmrMode: 'watch', + hmrMs: [91, 93, 95, 97, 120, 130], + hmrPluginMs: [41, 43, 45, 47, 70, 80], + summary: { + hmr: { median: 96, p95: 130 }, + hmrPlugin: { median: 46, p95: 80 }, + }, + }, + { + version: baselineLabel, + key: 'median-regression', + hmrMode: 'watch', + hmrMs: [90, 92, 94, 96, 98, 100], + hmrPluginMs: [40, 42, 44, 46, 48, 50], + summary: { + hmr: { median: 95, p95: 100 }, + hmrPlugin: { median: 45, p95: 50 }, + }, + }, + { + version: currentLabel, + key: 'median-regression', + hmrMode: 'watch', + hmrMs: [110, 112, 114, 116, 118, 120], + hmrPluginMs: [55, 57, 59, 61, 63, 65], + summary: { + hmr: { median: 115, p95: 120 }, + hmrPlugin: { median: 60, p95: 65 }, + }, + }, + { + version: baselineLabel, + key: 'even-median-half-regression', + hmrMode: 'watch', + hmrPluginStatistic: 'median', + hmrPluginMs: [40, 42, 44, 46, 48, 50], + summary: { + hmrPlugin: { median: 45, p95: 50 }, + }, + }, + { + version: currentLabel, + key: 'even-median-half-regression', + hmrMode: 'watch', + hmrPluginStatistic: 'median', + hmrPluginMs: [46, 47, 48, 63, 64, 65], + summary: { + hmrPlugin: { median: 55.5, p95: 65 }, + }, + }, + ], + }, baselineLabel, currentLabel) + + const result = evaluatePerformanceGuard(summary) + + expect(result.violations.filter(item => item.key === 'single-tail-outlier' && item.metric !== 'hmrMemorySamples')).toEqual([]) + expect(result.violations.filter(item => item.key === 'framework-only-median-regression' && item.metric !== 'hmrMemorySamples')).toEqual([]) + expect(result.violations).toContainEqual(expect.objectContaining({ + key: 'two-tail-regressions', + metric: 'hmrP95', + regressionSamples: 2, + })) + expect(result.violations).toContainEqual(expect.objectContaining({ + key: 'two-tail-regressions', + metric: 'hmrPluginP95', + regressionSamples: 2, + })) + expect(result.violations).toContainEqual(expect.objectContaining({ + key: 'median-regression', + metric: 'hmrMedian', + })) + expect(result.violations).toContainEqual(expect.objectContaining({ + key: 'median-regression', + metric: 'hmrPluginMedian', + })) + expect(result.violations.filter(item => item.key === 'even-median-half-regression')).toEqual([]) + }) + + it('keeps isolated RSS peaks and sub-64MB memory drift informational', async () => { + const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') + const baselineLabel = 'base:main' + const currentLabel = 'current:feature' + const summary = buildSummary({ + generatedAt: '2026-07-20T00:00:00.000Z', + options: { buildRuns: 3, hmrRuns: 6, timeoutMs: 180000 }, + rows: [ + { + version: baselineLabel, + key: 'rss-noise', + hmrMode: 'watch', + summary: { + build: { median: 500 }, + buildPeakRssMb: { median: 330 }, + buildSteadyRssMb: { median: 330 }, + hmr: { median: 100, p95: 110 }, + hmrPeakRssMb: { median: 2200 }, + hmrSteadyRssMb: { median: 2100 }, + }, + }, + { + version: currentLabel, + key: 'rss-noise', + hmrMode: 'watch', + summary: { + build: { median: 500 }, + buildPeakRssMb: { median: 375 }, + buildSteadyRssMb: { median: 375 }, + hmr: { median: 100, p95: 110 }, + hmrPeakRssMb: { median: 2450 }, + hmrSteadyRssMb: { median: 2140 }, + }, + }, + ], + }, baselineLabel, currentLabel) + + expect(evaluatePerformanceGuard(summary).passed).toBe(true) + }) + it('ignores sub-10ms timing drift while retaining the percentage guard for larger regressions', async () => { const { buildSummary, evaluatePerformanceGuard } = await import('../../../../benchmark/version-compare/scripts/ci-report.mjs') const baselineLabel = 'base:main' diff --git a/packages/weapp-tailwindcss/test/js/precheck.properties.test.ts b/packages/weapp-tailwindcss/test/js/precheck.properties.test.ts index 97c856bc32..cd0b53b716 100644 --- a/packages/weapp-tailwindcss/test/js/precheck.properties.test.ts +++ b/packages/weapp-tailwindcss/test/js/precheck.properties.test.ts @@ -66,7 +66,6 @@ const DEPENDENCY_TEMPLATES = [ (id: string) => `import { ${id} } from "module"`, (id: string) => `import "${id}"`, (id: string) => `import * as ${id} from "pkg"`, - (_id: string) => `import("dynamic")`, (_id: string) => `const m = require("mod")`, (_id: string) => `export * from "module"`, (_id: string) => `export { foo } from "bar"`, diff --git a/packages/weapp-tailwindcss/test/js/precheck.test.ts b/packages/weapp-tailwindcss/test/js/precheck.test.ts index 5f091d3c6e..d61344a6a2 100644 --- a/packages/weapp-tailwindcss/test/js/precheck.test.ts +++ b/packages/weapp-tailwindcss/test/js/precheck.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest' -import { shouldSkipJsTransform } from '@/js/precheck' import { shouldSkipViteJsTransform } from '@/bundlers/vite/js-precheck' +import { hasDependencyHint, shouldSkipJsTransform } from '@/js/precheck' describe('shouldSkipJsTransform', () => { describe('空字符串返回 true(可跳过)', () => { @@ -60,6 +60,17 @@ describe('shouldSkipJsTransform', () => { expect(shouldSkipJsTransform('import * as bar from "baz"')).toBe(false) }) + it('Webpack harmony import 注释不会误判为依赖', () => { + const source = '/* harmony import */ var className = getName()' + expect(hasDependencyHint(source)).toBe(false) + }) + + it('dynamic import 与 JSDoc import type 不会误判为静态模块图依赖', () => { + expect(hasDependencyHint('const lazy = import("./lazy")')).toBe(false) + expect(hasDependencyHint('/** @returns {import("@mpxjs/core").Mpx} */')).toBe(false) + expect(shouldSkipJsTransform('const lazy = import("./lazy")')).toBe(true) + }) + it('export 语句', () => { expect(shouldSkipJsTransform('export * from "module"')).toBe(false) }) From bd0adc7fdc69c8dfc995825d6fbcba1e529fd6cc Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 09:41:23 +0800 Subject: [PATCH 08/14] =?UTF-8?q?fix(build):=20=E4=BC=98=E5=8C=96=20Babel?= =?UTF-8?q?=208=20=E7=9A=84=20Webpack=20=E7=83=AD=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/babel-eight-module-packages.md | 2 +- package.json | 2 -- packages/weapp-tailwindcss/package.json | 2 ++ .../v5-assets/html-js-tasks.ts | 5 +++- .../weapp-tailwindcss/src/context/handlers.ts | 2 +- .../weapp-tailwindcss/src/js/fast-path/oxc.ts | 27 +++++++++++++++++-- .../src/types/user-defined-options/general.ts | 2 +- .../process-assets-js-cache.cases.ts | 7 ++++- .../v5-assets.hook-branches.cases.ts | 3 +++ .../test/context/handlers.test.ts | 17 ++++++++++++ .../test/js/oxc-fast-path.test.ts | 21 +++++++++++++++ pnpm-lock.yaml | 19 ++++++++----- 12 files changed, 94 insertions(+), 15 deletions(-) diff --git a/.changeset/babel-eight-module-packages.md b/.changeset/babel-eight-module-packages.md index c83da4e1e7..718b34f89b 100644 --- a/.changeset/babel-eight-module-packages.md +++ b/.changeset/babel-eight-module-packages.md @@ -12,4 +12,4 @@ "weapp-style-injector": patch --- -升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。Webpack 产物中的 harmony import 注释与 JSDoc import type 不再误触发模块图解析。 +升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,默认在完整语义约束允许时使用 OXC AST 快路径,并在不支持的输入或运行时自动回退 Babel。Webpack chunk 直接使用 compilation 产物图独立转译,原生 JS/WXS 才保留输出模块图关联,避免把 runtime bootstrap `require()` 误当作源码链接,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。Webpack 产物中的 harmony import 注释与 JSDoc import type 不再误触发模块图解析。 diff --git a/package.json b/package.json index d092c39803..b39d763ea4 100644 --- a/package.json +++ b/package.json @@ -352,8 +352,6 @@ "normalize-newline": "^5.0.0", "npm-registry-fetch": "^20.0.1", "only-allow": "^1.2.2", - "oxc-parser": "^0.140.0", - "oxc-walker": "^1.0.0", "pathe": "^2.0.3", "picocolors": "^1.1.1", "pixelmatch": "^7.2.0", diff --git a/packages/weapp-tailwindcss/package.json b/packages/weapp-tailwindcss/package.json index d895a4bc93..982e5b8e82 100644 --- a/packages/weapp-tailwindcss/package.json +++ b/packages/weapp-tailwindcss/package.json @@ -243,6 +243,8 @@ "lru-cache": "11.5.2", "magic-string": "1.0.0", "micromatch": "^4.0.8", + "oxc-parser": "^0.140.0", + "oxc-walker": "^1.0.0", "semver": "~7.8.5", "tailwindcss-config": "workspace:*", "weapp-style-injector": "workspace:*", diff --git a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts index 5be318a436..589fee9269 100644 --- a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts +++ b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts @@ -72,6 +72,9 @@ export async function enqueueWebpackHtmlAndJsTasks(context: any) { const initialSource = asset.source.source() const initialRawSource = typeof initialSource === 'string' ? initialSource : initialSource.toString() const chunkHash = assetHashByChunk.get(file) + // Webpack chunk 之间的字面量 require 是 runtime bootstrap 边,chunk 本身会在当前产物图中独立转译。 + // 仅非 chunk 的原生 JS/WXS 继续使用输出模块图处理跨文件源码引用。 + const outputModuleGraphOptions = chunkHash === undefined ? moduleGraphOptions : undefined await enqueueJsTask(async () => { await processCachedTask({ cache: compilerOptions.cache, @@ -99,7 +102,7 @@ export async function enqueueWebpackHtmlAndJsTasks(context: any) { tailwindcssMajorVersion: runtimeState.tailwindRuntime.majorVersion, generateMap: false, filename: absoluteFile, - moduleGraph: moduleGraphOptions, + moduleGraph: outputModuleGraphOptions, babelParserOptions: { sourceFilename: absoluteFile, }, diff --git a/packages/weapp-tailwindcss/src/context/handlers.ts b/packages/weapp-tailwindcss/src/context/handlers.ts index 24c3135bbc..b1963f10f2 100644 --- a/packages/weapp-tailwindcss/src/context/handlers.ts +++ b/packages/weapp-tailwindcss/src/context/handlers.ts @@ -54,7 +54,7 @@ export function createHandlersFromContext( tailwindcssMajorVersion, generateMap: true, babelParserOptions, - experimentalJsFastPath, + experimentalJsFastPath: experimentalJsFastPath ?? 'oxc', ignoreCallExpressionIdentifiers, ignoreTaggedTemplateExpressionIdentifiers, uniAppX: uniAppXEnabled, diff --git a/packages/weapp-tailwindcss/src/js/fast-path/oxc.ts b/packages/weapp-tailwindcss/src/js/fast-path/oxc.ts index 9b58218b2c..224f14fa76 100644 --- a/packages/weapp-tailwindcss/src/js/fast-path/oxc.ts +++ b/packages/weapp-tailwindcss/src/js/fast-path/oxc.ts @@ -114,7 +114,7 @@ function hasSupportedClassMatchSource(options: IJsHandlerOptions) { || Boolean(options.classNameSet && options.classNameSet.size > 0) } -export function canUseOxcJsFastPath(options: IJsHandlerOptions) { +function canAttemptOxcJsFastPath(options: IJsHandlerOptions) { if (options.experimentalJsFastPath !== true && options.experimentalJsFastPath !== 'oxc') { return false } @@ -126,6 +126,10 @@ export function canUseOxcJsFastPath(options: IJsHandlerOptions) { && hasSupportedClassMatchSource(options) && !shouldEnableArbitraryValueFallback(options) && !hasValues(options.ignoreCallExpressionIdentifiers) +} + +export function canUseOxcJsFastPath(options: IJsHandlerOptions) { + return canAttemptOxcJsFastPath(options) && !hasValues(options.ignoreTaggedTemplateExpressionIdentifiers) } @@ -235,8 +239,21 @@ function applyReplacements( return changed } +function hasTaggedTemplateExpression(program: Program, walker: OxcWalker) { + let found = false + walker.walk(program, { + enter(node) { + if (node.type === 'TaggedTemplateExpression') { + found = true + this.skip() + } + }, + }) + return found +} + export function oxcJsHandler(rawSource: string, options: IJsHandlerOptions): JsHandlerResult | undefined { - if (!canUseOxcJsFastPath(options)) { + if (!canAttemptOxcJsFastPath(options)) { return undefined } if (hasUnsupportedSourceMarker(rawSource)) { @@ -263,6 +280,12 @@ export function oxcJsHandler(rawSource: string, options: IJsHandlerOptions): JsH if (!result.program || (Array.isArray(result.errors) && result.errors.length > 0)) { return undefined } + if ( + hasValues(options.ignoreTaggedTemplateExpressionIdentifiers) + && hasTaggedTemplateExpression(result.program, walker) + ) { + return undefined + } const stringLiteralOptions = options.needEscaped === true ? options diff --git a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts index 245f00bd40..a2581efc07 100644 --- a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts +++ b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts @@ -200,7 +200,7 @@ export interface UserDefinedOptionsGeneralPart { * @group 3.一般配置 * @experimental * @remarks - * 当前仅在调用侧关闭 source map,且没有模块图、模块替换、ignore 调用/标签模板语义时尝试 OXC。 + * 默认在调用侧关闭 source map,且没有模块图、模块替换或 ignore 调用语义时尝试 OXC;配置了标签模板 ignore 且源码含标签模板时回退 Babel。传入 `false` 可关闭。 * Babel 8 链路要求 Node `^22.18.0 || >=24.11.0`。OXC 加载失败时仍会自动回退到 Babel。 */ experimentalJsFastPath?: boolean | 'oxc' | undefined diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts index 55867d2d53..4b5e3cc0b6 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts @@ -31,7 +31,7 @@ describe('bundlers/webpack WeappTailwindcss / process assets js cache', () => { }) const compilation = { compiler: { outputPath: path.resolve(process.cwd(), 'dist') }, - chunks: [{ id: 'main', hash: 'hash-1' }], + chunks: [{ id: 'main', hash: 'hash-1', files: ['index.js', 'index.wxs'] }], hooks: { processAssets: { tapPromise: (_options: unknown, handler: (assets: Record) => Promise) => { @@ -108,6 +108,11 @@ describe('bundlers/webpack WeappTailwindcss / process assets js cache', () => { expect(testState.currentContext.cache.has('index.js')).toBe(true) expect(testState.currentContext.cache.has('index.wxs')).toBe(true) + expect(testState.currentContext.jsHandler).toHaveBeenCalledWith( + js, + expect.any(Set), + expect.objectContaining({ moduleGraph: undefined }), + ) const assetStoreSecond = { 'index.wxml': html, diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts index 61c9f25fd6..ba63c59cb9 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts @@ -278,6 +278,7 @@ describe('bundlers/webpack v5-assets hook branch coverage', () => { 'entry.js': 'const cls = "old-entry bg-[#123456]"', 'linked.js': 'const linked = "old"', }, + chunkFiles: [], compilerOutputPath: outDir, context, }) @@ -316,6 +317,7 @@ describe('bundlers/webpack v5-assets hook branch coverage', () => { 'entry.js': 'const cls = "old-entry bg-[#123456]"', 'linked.js': 'const linked = "old"', }, + chunkFiles: [], compilerOutputPath: outDir, context, }) @@ -353,6 +355,7 @@ describe('bundlers/webpack v5-assets hook branch coverage', () => { 'entry.js': 'const cls = "object-entry-old bg-[#654321]"', 'linked.js': 'const linked = "object-old"', }), + chunkFiles: [], compilerOutputPath: outDir, context, }) diff --git a/packages/weapp-tailwindcss/test/context/handlers.test.ts b/packages/weapp-tailwindcss/test/context/handlers.test.ts index 97d423dca7..f4b8604d40 100644 --- a/packages/weapp-tailwindcss/test/context/handlers.test.ts +++ b/packages/weapp-tailwindcss/test/context/handlers.test.ts @@ -100,6 +100,7 @@ describe('createHandlersFromContext', () => { expect(jsHandlerFactory).toHaveBeenCalledWith(expect.objectContaining({ escapeMap: ctx.escapeMap, arbitraryValues: ctx.arbitraryValues, + experimentalJsFastPath: 'oxc', })) expect(templateHandlerFactory).toHaveBeenCalledWith(expect.objectContaining({ @@ -115,6 +116,22 @@ describe('createHandlersFromContext', () => { }) }) + it.each([ + ['disabled', false, false], + ['enabled', true, true], + ['oxc', 'oxc', 'oxc'], + ] as const)('preserves an explicitly %s JS fast path', async (_label, experimentalJsFastPath, expected) => { + const { createHandlersFromContext } = await import('@/context/handlers') + const ctx = createContext() + ctx.experimentalJsFastPath = experimentalJsFastPath + + createHandlersFromContext(ctx, customAttributesEntities, true) + + expect(jsHandlerFactory).toHaveBeenCalledWith(expect.objectContaining({ + experimentalJsFastPath: expected, + })) + }) + it.each([ ['enabled', true], ['disabled', false], diff --git a/packages/weapp-tailwindcss/test/js/oxc-fast-path.test.ts b/packages/weapp-tailwindcss/test/js/oxc-fast-path.test.ts index 2adf3847ac..05a07b2489 100644 --- a/packages/weapp-tailwindcss/test/js/oxc-fast-path.test.ts +++ b/packages/weapp-tailwindcss/test/js/oxc-fast-path.test.ts @@ -129,6 +129,27 @@ describe('OXC JS fast path', () => { expect(oxcJsHandler('cn("w-[100px]")', options)).toBeUndefined() }) + it('uses OXC with tagged-template ignore options when the AST has no tagged template', () => { + const options = { + ...createOptions(), + ignoreTaggedTemplateExpressionIdentifiers: ['weappTwIgnore'], + } + const source = 'const cls = "w-[100px]"' + + expect(canUseOxcJsFastPath(options)).toBe(false) + expect(oxcJsHandler(source, options)?.code).toBe(jsHandler(source, options).code) + }) + + it('falls back to Babel when tagged-template ignore options meet any tagged template', () => { + const options = { + ...createOptions(), + ignoreTaggedTemplateExpressionIdentifiers: ['weappTwIgnore'], + } + + expect(oxcJsHandler('other`w-[100px]`', options)).toBeUndefined() + expect(oxcJsHandler('weappTwIgnore`w-[100px]`', options)).toBeUndefined() + }) + it('falls back when arbitrary-value fallback needs Babel class context', () => { const options = { ...createOptions(), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0432be39c..29dcfeb2a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -746,12 +746,6 @@ importers: only-allow: specifier: ^1.2.2 version: 1.2.2 - oxc-parser: - specifier: ^0.140.0 - version: 0.140.0 - oxc-walker: - specifier: ^1.0.0 - version: 1.0.0(oxc-parser@0.140.0)(rolldown@1.1.5) pathe: specifier: ^2.0.3 version: 2.0.3 @@ -4306,6 +4300,12 @@ importers: micromatch: specifier: ^4.0.8 version: 4.0.8 + oxc-parser: + specifier: ^0.140.0 + version: 0.140.0 + oxc-walker: + specifier: ^1.0.0 + version: 1.0.0(oxc-parser@0.140.0)(rolldown@1.2.0) semver: specifier: ~7.8.5 version: 7.8.5 @@ -62052,6 +62052,13 @@ snapshots: oxc-parser: 0.140.0 rolldown: 1.1.5 + oxc-walker@1.0.0(oxc-parser@0.140.0)(rolldown@1.2.0): + dependencies: + magic-regexp: 0.11.0 + optionalDependencies: + oxc-parser: 0.140.0 + rolldown: 1.2.0 + oxfmt@0.35.0: dependencies: tinypool: 2.1.0 From e06bd9c91930dc3c79428b588b1b4f24f82ee735 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 10:45:40 +0800 Subject: [PATCH 09/14] =?UTF-8?q?fix(ci):=20=E8=AE=A9=20Taro=20=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E9=97=A8=E7=A6=81=E6=89=A7=E8=A1=8C=E7=9C=9F=E5=AE=9E?= =?UTF-8?q?=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benchmark/version-compare/scripts/projects.mjs | 12 ++++++++++++ benchmark/version-compare/scripts/run-matrix.mjs | 3 +++ .../test/ci/benchmark-report.test.ts | 6 +++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/benchmark/version-compare/scripts/projects.mjs b/benchmark/version-compare/scripts/projects.mjs index 2bdb3586da..830b623773 100644 --- a/benchmark/version-compare/scripts/projects.mjs +++ b/benchmark/version-compare/scripts/projects.mjs @@ -33,6 +33,9 @@ export const benchmarkProjects = [ project: 'demo/taro-vite-react-tailwindcss-v4', target: 'mp-weixin', buildScript: 'build', + buildEnv: { + TARO_BUILD_STRICT: '1', + }, sourceFile: 'src/pages/index/index.tsx', outputTemplate: 'dist/pages/index/index.wxml', outputProbeTemplates: ['dist/pages/index/index.js'], @@ -59,6 +62,9 @@ export const benchmarkProjects = [ project: 'demo/taro-vite-vue3-tailwindcss-v4', target: 'mp-weixin', buildScript: 'build', + buildEnv: { + TARO_BUILD_STRICT: '1', + }, sourceFile: 'src/pages/index/index.vue', outputTemplate: 'dist/pages/index/index.wxml', outputProbeTemplates: ['dist/pages/index/index.js'], @@ -85,6 +91,9 @@ export const benchmarkProjects = [ project: 'demo/taro-webpack-react-tailwindcss-v4', target: 'mp-weixin', buildScript: 'build', + buildEnv: { + TARO_BUILD_STRICT: '1', + }, sourceFile: 'src/pages/index/index.tsx', outputTemplate: 'dist/pages/index/index.wxml', outputProbeTemplates: ['dist/pages/index/index.js'], @@ -111,6 +120,9 @@ export const benchmarkProjects = [ project: 'demo/taro-webpack-vue3-tailwindcss-v4', target: 'mp-weixin', buildScript: 'build', + buildEnv: { + TARO_BUILD_STRICT: '1', + }, sourceFile: 'src/pages/index/index.vue', outputTemplate: 'dist/pages/index/index.wxml', outputProbeTemplates: ['dist/pages/index/index.js'], diff --git a/benchmark/version-compare/scripts/run-matrix.mjs b/benchmark/version-compare/scripts/run-matrix.mjs index ce09d4b235..154e2770fb 100644 --- a/benchmark/version-compare/scripts/run-matrix.mjs +++ b/benchmark/version-compare/scripts/run-matrix.mjs @@ -358,6 +358,9 @@ async function runBuildOnce(cwd, buildScript, timeoutMs, buildEnv = {}) { if (logs.includes('[uni-build-guard]') && logs.includes('已跳过 uni-app 的真实构建')) { throw new Error(`build skipped by uni-build-guard; set project buildEnv.UNI_BUILD_STRICT=1 for benchmark builds\n${logs.slice(-4000)}`) } + if (logs.includes('[taro-build-guard]') && logs.includes('已跳过 Taro demo/app 的 weapp 构建')) { + throw new Error(`build skipped by taro-build-guard; set project buildEnv.TARO_BUILD_STRICT=1 for benchmark builds\n${logs.slice(-4000)}`) + } const pluginTiming = resolvePluginTimingSample(logs.split(/\r?\n/)) return { diff --git a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts index 413adf7766..06afc23a9f 100644 --- a/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts +++ b/packages/weapp-tailwindcss/test/ci/benchmark-report.test.ts @@ -50,7 +50,9 @@ describe('benchmark ci report', () => { expect(mpxMpWeixin?.hmrPluginStatistic).toBe('median') expect(mpxMpWeixin?.hmrEndToEndGuard).toBe(false) expect(mpxMpWeixin?.hmrGuardNote).toContain('processAssets median remains guarded') - expect(benchmarkProjects.filter(project => project.key.includes('taro') && project.target === 'mp-weixin').every(project => project.hmrMode === 'watch')).toBe(true) + const taroMpWeixinProjects = benchmarkProjects.filter(project => project.key.includes('taro') && project.target === 'mp-weixin') + expect(taroMpWeixinProjects.every(project => project.buildEnv?.TARO_BUILD_STRICT === '1')).toBe(true) + expect(taroMpWeixinProjects.every(project => project.hmrMode === 'watch')).toBe(true) const realDevServerTargets = benchmarkProjects.filter(project => (project.target === 'h5' || project.target === 'web') && !project.key.includes('hbuilderx')) expect(realDevServerTargets.every(project => project.hmrMode === 'watch')).toBe(true) expect(realDevServerTargets.every(project => project.hmrDriver === 'dev-server')).toBe(true) @@ -631,6 +633,8 @@ describe('benchmark ci report', () => { expect(source).toContain('outputProbeTemplates') expect(source).toContain('buildEnv.UNI_BUILD_STRICT=1') expect(source).toContain('build skipped by uni-build-guard') + expect(source).toContain('buildEnv.TARO_BUILD_STRICT=1') + expect(source).toContain('build skipped by taro-build-guard') expect(source).toContain('createProcessMemorySampler') }) From dc6e9a7d0367342bbe7f8c4f5d7d00de055e2e5a Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 11:54:35 +0800 Subject: [PATCH 10/14] =?UTF-8?q?fix(build):=20=E6=8C=89=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E5=90=AF=E7=94=A8=20OXC=20?= =?UTF-8?q?=E5=BF=AB=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/babel-eight-module-packages.md | 2 +- .../generate-bundle/js-handler-options.ts | 2 ++ .../bundlers/vite/generate-bundle/runtime.ts | 2 +- .../create-framework-plugins-runtime.ts | 2 +- .../webpack/BaseUnifiedPlugin/v5-assets.ts | 1 + .../v5-assets/html-js-tasks.ts | 3 ++- .../weapp-tailwindcss/src/context/handlers.ts | 2 +- .../src/types/user-defined-options/general.ts | 2 +- .../bundlers/vite-js-processing.unit.test.ts | 19 +++++++++++++++++ .../process-assets-js-cache.cases.ts | 2 +- .../v5-assets.hook-branches.cases.ts | 21 ++++++++++++------- .../test/context/handlers.test.ts | 2 +- 12 files changed, 45 insertions(+), 15 deletions(-) diff --git a/.changeset/babel-eight-module-packages.md b/.changeset/babel-eight-module-packages.md index 718b34f89b..f39c81d5a0 100644 --- a/.changeset/babel-eight-module-packages.md +++ b/.changeset/babel-eight-module-packages.md @@ -12,4 +12,4 @@ "weapp-style-injector": patch --- -升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch 热更新复用解析缓存并采用轻量 AST 签名遍历,默认在完整语义约束允许时使用 OXC AST 快路径,并在不支持的输入或运行时自动回退 Babel。Webpack chunk 直接使用 compilation 产物图独立转译,原生 JS/WXS 才保留输出模块图关联,避免把 runtime bootstrap `require()` 误当作源码链接,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。Webpack 产物中的 harmony import 注释与 JSDoc import type 不再误触发模块图解析。 +升级核心 Babel 工具链到 Babel 8,并将 Node.js 最低版本提升到 `^22.18.0 || >=24.11.0`。相关包默认采用 ESM 语义,继续同时发布 ESM 与 CommonJS 入口;ESM 产物使用 `.js`,CommonJS 产物使用 `.cjs`,原有公开包名与子路径保持不变。同时收紧 tsdown 的依赖外置策略,避免 ESM 无条件内联可直接消费的依赖,并保证 CommonJS 不会同步加载 ESM-only 依赖。Webpack loader 与 CommonJS runtime 复用同一构建图,避免重复加载 Babel 8 等内联依赖;watch/serve 热更新复用解析缓存并采用轻量 AST 签名遍历,在完整语义约束允许时默认使用 OXC AST 快路径,并在普通 build、不支持的输入或运行时自动回退 Babel,避免冷构建同时加载双解析器。Webpack chunk 直接使用 compilation 产物图独立转译,原生 JS/WXS 才保留输出模块图关联,避免把 runtime bootstrap `require()` 误当作源码链接,降低 MPX、Taro Webpack 等链路的内存和插件处理耗时。Webpack 产物中的 harmony import 注释与 JSDoc import type 不再误触发模块图解析。 diff --git a/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/js-handler-options.ts b/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/js-handler-options.ts index 4b871973c6..402de97a64 100644 --- a/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/js-handler-options.ts +++ b/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/js-handler-options.ts @@ -2,6 +2,7 @@ import type { CreateJsHandlerOptions, InternalUserDefinedOptions } from '@/types import { isUniAppXEnabled } from '@/uni-app-x/options' interface JsHandlerOptionsFactoryOptions { + getExperimentalJsFastPath?: () => CreateJsHandlerOptions['experimentalJsFastPath'] getMajorVersion: () => number | undefined moduleGraph: CreateJsHandlerOptions['moduleGraph'] } @@ -14,6 +15,7 @@ export function createJsHandlerOptionsFactory(options: JsHandlerOptionsFactoryOp return (absoluteFilename: string, extra?: CreateJsHandlerOptions): CreateJsHandlerOptions => ({ ...extra, generateMap: false, + experimentalJsFastPath: options.getExperimentalJsFastPath?.(), filename: absoluteFilename, tailwindcssMajorVersion: options.getMajorVersion(), moduleGraph: options.moduleGraph, diff --git a/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/runtime.ts b/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/runtime.ts index 707bbd273d..cdbac33483 100644 --- a/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/runtime.ts +++ b/packages/weapp-tailwindcss/src/bundlers/vite/generate-bundle/runtime.ts @@ -274,7 +274,7 @@ function createGenerateBundleHook(context): any { const transformRuntimeSignature = createCandidateSignature(transformRuntime) const shouldProcessTailwindGeneration = !useIncrementalMode || hasRuntimeAffectingChanges || generatorCandidatesChanged || snapshot.processFiles.css.size > 0 const { applyLinkedUpdates, pendingLinkedUpdates } = createLinkedUpdateHelpers({ jsEntries, onUpdate, debug }) - const createBaseHandlerOptions = createJsHandlerOptionsFactory({ getMajorVersion: () => runtimeState.tailwindRuntime.majorVersion, moduleGraph: moduleGraphOptions }) + const createBaseHandlerOptions = createJsHandlerOptionsFactory({ getExperimentalJsFastPath: () => opts.experimentalJsFastPath ?? (resolvedConfig?.build?.watch != null ? 'oxc' : false), getMajorVersion: () => runtimeState.tailwindRuntime.majorVersion, moduleGraph: moduleGraphOptions }) const resolveFrameworkJsHandlerOptions = absoluteFilename => context.cssPipelineStrategy?.getServeJsHandlerOptions?.({ ...cssPipelineContext, file: absoluteFilename }) const createHandlerOptions = (absoluteFilename, extra) => { const frameworkExtra = resolveFrameworkJsHandlerOptions(absoluteFilename); return createBaseHandlerOptions(absoluteFilename, frameworkExtra || extra ? { ...frameworkExtra, ...extra } : void 0) } const shouldTransformJsBundle = !isWebGeneratorTarget || context.cssPipelineStrategy?.shouldTransformServeJs?.(cssPipelineContext) === true diff --git a/packages/weapp-tailwindcss/src/bundlers/vite/shared/create-framework-plugins-runtime.ts b/packages/weapp-tailwindcss/src/bundlers/vite/shared/create-framework-plugins-runtime.ts index cd96129541..aaa18300ee 100644 --- a/packages/weapp-tailwindcss/src/bundlers/vite/shared/create-framework-plugins-runtime.ts +++ b/packages/weapp-tailwindcss/src/bundlers/vite/shared/create-framework-plugins-runtime.ts @@ -301,7 +301,7 @@ function createViteFrameworkPlugins(options = {}, frameworkBranch): any { const resolveCssAssetIdentity = createViteCssAssetIdentityResolver({ generatorPlaceholderFile: generatorPlaceholderCssFile, isKnownProcessedSource: processedCssRegistry.matchesIdentity }) const isViteProcessedCssAsset = (asset, file) => resolveCssAssetIdentity(asset, file).kind === 'bundler-generated' const transformCssHandlerOptions = createCssHandlerOptionsCache({ getAppType: () => opts.appType, mainCssChunkMatcher, getMajorVersion: () => runtimeState.tailwindRuntime.majorVersion, getOutputRoot: () => resolvedConfig?.build?.outDir ? path.resolve(resolvedConfig.root, resolvedConfig.build.outDir) : resolvedConfig?.root, getExtraOptions: file => ({ ...resolveViteCssHandlerExtraOptions(file), ...frameworkCssPipelineStrategy?.getCssHandlerExtraOptions?.({ ...createCssPipelineContext(), file }) ?? {} }), getDynamicCssOptions: () => ({ cssPreflight: opts.cssPreflight }) }) - const serveJsHandlerOptions = createJsHandlerOptionsFactory({ getMajorVersion: () => runtimeState.tailwindRuntime.majorVersion, moduleGraph: void 0 }) + const serveJsHandlerOptions = createJsHandlerOptionsFactory({ getExperimentalJsFastPath: () => opts.experimentalJsFastPath ?? 'oxc', getMajorVersion: () => runtimeState.tailwindRuntime.majorVersion, moduleGraph: void 0 }) const shouldAdaptFrameworkWatchCss = () => { const platform = resolveViteStylePlatform(); return shouldAdaptFrameworkWatchCssBeforeCache({ enabled: frameworkBranch.adaptWatchCssBeforeFrameworkCache === true, ownsTailwindGeneration: shouldOwnTailwindGeneration, isWatchBuild: isWatchBuild(), isWebGeneratorBranch: resolveCurrentGeneratorBranch().isWeb, platform }) } const generateTailwindCssForVitePipeline = async (id, code, hookContext) => { if (!shouldOwnTailwindGeneration) { diff --git a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets.ts b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets.ts index 77e3b5cfff..9096f30573 100644 --- a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets.ts +++ b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets.ts @@ -416,6 +416,7 @@ export function setupWebpackV5ProcessAssetsHook(options: SetupWebpackV5ProcessAs runtimeState, transformRuntimeSet, updateAssetIfChanged, + watchMode, }) const cssTaskContext = { ConcatSource, affectedCompilationScopes, assetHashByChunk, compilation, compilationChanges, compilerOptions, configuredCssEntryFiles, configuredMainCssEntryFiles, createRuntimeSetHash, cssSourceTraceSignature, cssSources, cssTaskFactories, debug, enqueueTask, finalizeCssAssetSource, finalizeTracedCss, generatedCssSources, generatorRuntimeSet, getCompilationDependencyRevision, getCssHandlerOptions, getCssUserHandlerOptions, getGeneratorRuntimeSet, hasConfiguredTailwindV4SourceRoots, isKnownWebpackProcessedCssAsset, isSameWebpackSourceScope, isWebGeneratorTarget, isWebpackProcessedCssAsset, processedCssAssetSkipDecisionCache, rememberProcessCacheKey, resolveWebpackCssSourceFile, runtimeAffectingSourceHash, runtimeState, transformRuntimeSet, updateAssetIfChanged, watchMode, webpackSourceCandidateSet, webpackSourceCandidateValueSignature, webpackSourceCandidates } for (const element of groupedEntries.css) { diff --git a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts index 589fee9269..c752642a25 100644 --- a/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts +++ b/packages/weapp-tailwindcss/src/bundlers/webpack/BaseUnifiedPlugin/v5-assets/html-js-tasks.ts @@ -9,7 +9,7 @@ import { export * from './pipeline-helpers' export async function enqueueWebpackHtmlAndJsTasks(context: any) { - const { ConcatSource, applyWebpackLinkedJsResults, assetHashByChunk, compilation, compilerOptions, debug, defaultTemplateHandlerOptions, enqueueTask, groupedEntries, isWebGeneratorTarget, jsAssets, moduleGraphOptions, outputDir, rememberProcessCacheKey, rememberTransformedRuntimeCandidates, runtimeState, transformRuntimeSet, updateAssetIfChanged } = context + const { ConcatSource, applyWebpackLinkedJsResults, assetHashByChunk, compilation, compilerOptions, debug, defaultTemplateHandlerOptions, enqueueTask, groupedEntries, isWebGeneratorTarget, jsAssets, moduleGraphOptions, outputDir, rememberProcessCacheKey, rememberTransformedRuntimeCandidates, runtimeState, transformRuntimeSet, updateAssetIfChanged, watchMode } = context const htmlTaskFactories: Array<() => Promise> = [] if (!isWebGeneratorTarget && Array.isArray(groupedEntries.html)) { for (const element of groupedEntries.html) { @@ -101,6 +101,7 @@ export async function enqueueWebpackHtmlAndJsTasks(context: any) { const handlerOptions = { tailwindcssMajorVersion: runtimeState.tailwindRuntime.majorVersion, generateMap: false, + experimentalJsFastPath: compilerOptions.experimentalJsFastPath ?? (watchMode ? 'oxc' : false), filename: absoluteFile, moduleGraph: outputModuleGraphOptions, babelParserOptions: { diff --git a/packages/weapp-tailwindcss/src/context/handlers.ts b/packages/weapp-tailwindcss/src/context/handlers.ts index b1963f10f2..24c3135bbc 100644 --- a/packages/weapp-tailwindcss/src/context/handlers.ts +++ b/packages/weapp-tailwindcss/src/context/handlers.ts @@ -54,7 +54,7 @@ export function createHandlersFromContext( tailwindcssMajorVersion, generateMap: true, babelParserOptions, - experimentalJsFastPath: experimentalJsFastPath ?? 'oxc', + experimentalJsFastPath, ignoreCallExpressionIdentifiers, ignoreTaggedTemplateExpressionIdentifiers, uniAppX: uniAppXEnabled, diff --git a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts index a2581efc07..4932a13a51 100644 --- a/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts +++ b/packages/weapp-tailwindcss/src/types/user-defined-options/general.ts @@ -200,7 +200,7 @@ export interface UserDefinedOptionsGeneralPart { * @group 3.一般配置 * @experimental * @remarks - * 默认在调用侧关闭 source map,且没有模块图、模块替换或 ignore 调用语义时尝试 OXC;配置了标签模板 ignore 且源码含标签模板时回退 Babel。传入 `false` 可关闭。 + * bundler watch/serve 链路默认在关闭 source map,且没有模块图、模块替换或 ignore 调用语义时尝试 OXC;普通 build 默认使用 Babel,避免同时加载双解析器。配置了标签模板 ignore 且源码含标签模板时回退 Babel。可显式传入 `true` 或 `'oxc'` 强制尝试,传入 `false` 可关闭。 * Babel 8 链路要求 Node `^22.18.0 || >=24.11.0`。OXC 加载失败时仍会自动回退到 Babel。 */ experimentalJsFastPath?: boolean | 'oxc' | undefined diff --git a/packages/weapp-tailwindcss/test/bundlers/vite-js-processing.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/vite-js-processing.unit.test.ts index 8ce3cee08d..fac796e2e5 100644 --- a/packages/weapp-tailwindcss/test/bundlers/vite-js-processing.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/vite-js-processing.unit.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it, vi } from 'vitest' +import { createJsHandlerOptionsFactory } from '@/bundlers/vite/generate-bundle/js-handler-options' import { processJsBundleEntry } from '@/bundlers/vite/generate-bundle/js-processing' import { createTransformFilter, createTransformFilterSignature, shouldSkipViteJsChunkTransform } from '@/bundlers/vite/generate-bundle/transform-filter' import { createCache } from '@/cache' @@ -44,6 +45,24 @@ function createSnapshot(file: string, sourceHash: string) { } describe('bundlers/vite js processing', () => { + it('selects the JS fast path from the current bundler lifecycle', () => { + let experimentalJsFastPath: false | 'oxc' = false + const createHandlerOptions = createJsHandlerOptionsFactory({ + getExperimentalJsFastPath: () => experimentalJsFastPath, + getMajorVersion: () => 4, + moduleGraph: undefined, + }) + + expect(createHandlerOptions('/repo/dist/index.js')).toMatchObject({ + experimentalJsFastPath: false, + }) + + experimentalJsFastPath = 'oxc' + expect(createHandlerOptions('/repo/dist/index.js')).toMatchObject({ + experimentalJsFastPath: 'oxc', + }) + }) + it('directly replays cached clean incremental chunks without scheduling js work', () => { const cache = createCache() const file = 'assets/index.js' diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts index 4b5e3cc0b6..0a748d8871 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/process-assets-js-cache.cases.ts @@ -111,7 +111,7 @@ describe('bundlers/webpack WeappTailwindcss / process assets js cache', () => { expect(testState.currentContext.jsHandler).toHaveBeenCalledWith( js, expect.any(Set), - expect.objectContaining({ moduleGraph: undefined }), + expect.objectContaining({ experimentalJsFastPath: false, moduleGraph: undefined }), ) const assetStoreSecond = { diff --git a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts index ba63c59cb9..f81de252d1 100644 --- a/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts +++ b/packages/weapp-tailwindcss/test/bundlers/webpack.v5.unit/v5-assets.hook-branches.cases.ts @@ -796,27 +796,29 @@ describe('bundlers/webpack v5-assets hook branch coverage', () => { }) it('marks initial watch runtime assets before syncing the runtime set', async () => { + const candidate = 'bg-[#123456]' + const escapedCandidate = 'bg-_b_#123456_B_' const runtimeClassSetManager = { - sync: vi.fn(async () => new Set(['bg-red-500'])), + sync: vi.fn(async () => new Set([candidate])), reset: vi.fn(async () => {}), } const context = createContext({ cssMatcher: (file: string) => file.endsWith('.css'), htmlMatcher: (file: string) => file.endsWith('.wxml'), jsMatcher: (file: string) => file.endsWith('.js'), - templateHandler: vi.fn(async (code: string) => code.replace('bg-red-500', 'bg-blue-500')), - jsHandler: vi.fn(async (code: string) => ({ code: code.replace('bg-red-500', 'bg-blue-500') })), + templateHandler: vi.fn(async (code: string) => code.replace(candidate, escapedCandidate)), + jsHandler: vi.fn(async (code: string) => ({ code: code.replace(candidate, escapedCandidate) })), tailwindRuntime: { ...createContext().tailwindRuntime, majorVersion: 4, - getClassSet: vi.fn(async () => new Set(['bg-red-500'])), - getClassSetSync: vi.fn(() => new Set(['bg-red-500'])), + getClassSet: vi.fn(async () => new Set([candidate])), + getClassSetSync: vi.fn(() => new Set([candidate])), }, }) const harness = createHookHarness({ assetStore: { - 'pages/index.wxml': '', - 'pages/index.js': 'const cls = "bg-red-500"', + 'pages/index.wxml': ``, + 'pages/index.js': `const cls = "${candidate}"`, }, chunkFiles: ['pages/index.wxml', 'pages/index.js'], context, @@ -829,6 +831,11 @@ describe('bundlers/webpack v5-assets hook branch coverage', () => { await harness.processAssets() expect(runtimeClassSetManager.sync).toHaveBeenCalled() + expect(context.jsHandler).toHaveBeenCalledWith( + expect.any(String), + expect.any(Set), + expect.objectContaining({ experimentalJsFastPath: 'oxc' }), + ) }) it('consumes loader generated css directly when no asset user css is present', async () => { diff --git a/packages/weapp-tailwindcss/test/context/handlers.test.ts b/packages/weapp-tailwindcss/test/context/handlers.test.ts index f4b8604d40..0efd755a65 100644 --- a/packages/weapp-tailwindcss/test/context/handlers.test.ts +++ b/packages/weapp-tailwindcss/test/context/handlers.test.ts @@ -100,7 +100,7 @@ describe('createHandlersFromContext', () => { expect(jsHandlerFactory).toHaveBeenCalledWith(expect.objectContaining({ escapeMap: ctx.escapeMap, arbitraryValues: ctx.arbitraryValues, - experimentalJsFastPath: 'oxc', + experimentalJsFastPath: undefined, })) expect(templateHandlerFactory).toHaveBeenCalledWith(expect.objectContaining({ From a8b150076939b5cddbbbb4cf57ff1b1bc50c9a59 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 15:35:57 +0800 Subject: [PATCH 11/14] =?UTF-8?q?fix(ci):=20=E6=8B=86=E5=88=86=20Windows?= =?UTF-8?q?=20Taro=20watch=20=E9=97=A8=E7=A6=81=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20Vue=20HMR=20=E6=8E=A2=E9=92=88=E7=AB=9E=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/e2e-watch.yml | 51 +++++++++++---- .../test/ci/workflows.test.ts | 65 ++++++++++++++----- .../test/watch-hmr-regression.unit.test.ts | 61 ++++++++++++++++- .../cases/demo/extended.ts | 7 +- 4 files changed, 151 insertions(+), 33 deletions(-) diff --git a/.github/workflows/e2e-watch.yml b/.github/workflows/e2e-watch.yml index 2e4d0553d9..e1376b9aca 100644 --- a/.github/workflows/e2e-watch.yml +++ b/.github/workflows/e2e-watch.yml @@ -335,13 +335,29 @@ jobs: - os: windows-latest runner_label: windows watch_case: taro-vite-vue3-tailwindcss-v4 - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 60 + # Windows PR 只跑主包与两个分包的真实主样式 HMR;完整多轮由 Linux/macOS 矩阵覆盖。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 watch_timeout_ms: '420000' watch_poll_ms: '40' - watch_max_plugin_process_ms: '60000' - watch_command_timeout_ms: '3000000' + watch_max_plugin_process_ms: '18000' + watch_command_timeout_ms: '2400000' + - os: windows-latest + runner_label: windows + watch_case: taro-vite-vue3-tailwindcss-v4 + round_profile: web-only + watch_save_snapshots: '1' + # Web HMR 独立运行,避免小程序长轮次失败后从头重跑并耗尽 job 预算。 + watch_web_only: '1' + watch_max_attempts: '1' + timeout_minutes: 25 + watch_timeout_ms: '420000' + watch_poll_ms: '40' + watch_command_timeout_ms: '1200000' - os: windows-latest runner_label: windows watch_case: taro-webpack-vue3-tailwindcss-v4 @@ -383,14 +399,17 @@ jobs: runner_label: windows watch_case: taro-vite-react-tailwindcss-v4:tt artifact_case: taro-vite-react-tailwindcss-v4-tt - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 70 - watch_timeout_ms: '600000' + # Windows TT 完整多轮已在 Linux/macOS 覆盖;PR 保留主包与两个分包的主样式 HMR。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 + watch_timeout_ms: '420000' watch_poll_ms: '40' - # Windows TT 独立分包 added-class 会触发较重的冷态构建,需要独立处理预算。 watch_max_plugin_process_ms: '18000' - watch_command_timeout_ms: '3300000' + watch_command_timeout_ms: '2400000' - os: windows-latest runner_label: windows watch_case: taro-vite-vue3-tailwindcss-v4:alipay @@ -411,13 +430,17 @@ jobs: runner_label: windows watch_case: taro-vite-vue3-tailwindcss-v4:tt artifact_case: taro-vite-vue3-tailwindcss-v4-tt - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 70 - watch_timeout_ms: '600000' + # Windows TT 完整多轮已在 Linux/macOS 覆盖;PR 保留主包与两个分包的主样式 HMR。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 + watch_timeout_ms: '420000' watch_poll_ms: '40' - watch_max_plugin_process_ms: '10000' - watch_command_timeout_ms: '3300000' + watch_max_plugin_process_ms: '18000' + watch_command_timeout_ms: '2400000' - os: windows-latest runner_label: windows watch_case: uni-app-vite-tailwindcss-v4:mp-weixin diff --git a/packages/weapp-tailwindcss/test/ci/workflows.test.ts b/packages/weapp-tailwindcss/test/ci/workflows.test.ts index 1e489a4cc6..a191172524 100644 --- a/packages/weapp-tailwindcss/test/ci/workflows.test.ts +++ b/packages/weapp-tailwindcss/test/ci/workflows.test.ts @@ -670,12 +670,16 @@ describe('e2e watch workflow', () => { expect(cases).toContain('macos:22:demo-core:main-style') expect(cases).toContain('windows:22:demo-uni:default') for (const watchCase of windowsSplitDemoCases) { - const profile = watchCase === 'mpx-tailwindcss-v4' ? 'main-style' : 'default' + const profile = watchCase === 'mpx-tailwindcss-v4' || watchCase === 'taro-vite-vue3-tailwindcss-v4' + ? 'main-style' + : 'default' expect(cases, `windows should split ${watchCase}`).toContain(`windows:22:${watchCase}:${profile}`) } for (const runner of ['linux', 'windows']) { for (const watchCase of completeMiniProgramCases) { - const profile = runner === 'windows' && watchCase.endsWith(':alipay') ? 'main-style' : 'default' + const profile = runner === 'windows' && (watchCase.endsWith(':alipay') || watchCase.endsWith(':tt')) + ? 'main-style' + : 'default' expect(cases, `${runner} should cover ${watchCase}`).toContain(`${runner}:22:${watchCase}:${profile}`) } } @@ -685,7 +689,7 @@ describe('e2e watch workflow', () => { expect(macosPlatformCases).toEqual(['uni-app-vite-tailwindcss-v4:mp-weixin']) expect(rows.filter(row => row.runner_label === 'macos')).toHaveLength(9) expect(rows.filter(row => row.runner_label === 'linux')).toHaveLength(12) - expect(rows.filter(row => row.runner_label === 'windows')).toHaveLength(17) + expect(rows.filter(row => row.runner_label === 'windows')).toHaveLength(18) for (const row of [ rows.find(row => row.runner_label === 'macos' && row.watch_case === 'demo-core'), rows.find(row => row.runner_label === 'windows' && row.watch_case === 'mpx-tailwindcss-v4'), @@ -852,16 +856,19 @@ describe('e2e watch workflow', () => { watch_max_plugin_process_ms: '10000', watch_command_timeout_ms: '3300000', })) - const slowWindowsTaroTtPrBudgets = [ - { watchCase: 'taro-vite-react-tailwindcss-v4:tt', pluginBudget: '18000' }, - { watchCase: 'taro-vite-vue3-tailwindcss-v4:tt', pluginBudget: '10000' }, - ].map(({ watchCase, pluginBudget }) => ({ + const minimalWindowsTaroTtPrBudgets = [ + 'taro-vite-react-tailwindcss-v4:tt', + 'taro-vite-vue3-tailwindcss-v4:tt', + ].map(watchCase => ({ watch_case: watchCase, - round_profile: 'default', - timeout_minutes: 70, - watch_timeout_ms: '600000', - watch_max_plugin_process_ms: pluginBudget, - watch_command_timeout_ms: '3300000', + round_profile: 'main-style', + watch_main_style_only: '1', + watch_main_style_subpackage_limit: '2', + watch_max_attempts: '1', + timeout_minutes: 45, + watch_timeout_ms: '420000', + watch_max_plugin_process_ms: '18000', + watch_command_timeout_ms: '2400000', })) const slowLinuxTaroAlipayPrBudgets = [ { watchCase: 'taro-vite-react-tailwindcss-v4:alipay', pluginBudget: '10000' }, @@ -874,10 +881,9 @@ describe('e2e watch workflow', () => { watch_max_plugin_process_ms: pluginBudget, watch_command_timeout_ms: '2700000', })) - const windowsSplitDemoPrBudgets = [ + const defaultWindowsSplitDemoPrBudgets = [ 'gulp-tailwindcss-v4', 'weapp-vite-tailwindcss-v4', - 'taro-vite-vue3-tailwindcss-v4', ].map(watchCase => ({ watch_case: watchCase, round_profile: 'default', @@ -886,6 +892,26 @@ describe('e2e watch workflow', () => { watch_max_plugin_process_ms: '60000', watch_command_timeout_ms: '3000000', })) + const minimalWindowsTaroVuePrBudget = { + watch_case: 'taro-vite-vue3-tailwindcss-v4', + round_profile: 'main-style', + watch_main_style_only: '1', + watch_main_style_subpackage_limit: '2', + watch_max_attempts: '1', + timeout_minutes: 45, + watch_timeout_ms: '420000', + watch_max_plugin_process_ms: '18000', + watch_command_timeout_ms: '2400000', + } + const windowsTaroVueWebPrBudget = { + watch_case: 'taro-vite-vue3-tailwindcss-v4', + round_profile: 'web-only', + watch_web_only: '1', + watch_max_attempts: '1', + timeout_minutes: 25, + watch_timeout_ms: '420000', + watch_command_timeout_ms: '1200000', + } const slowWindowsTaroReactPrBudgets = [ { watch_case: 'taro-vite-react-tailwindcss-v4', @@ -1024,7 +1050,14 @@ describe('e2e watch workflow', () => { })) } } - for (const budget of windowsSplitDemoPrBudgets) { + for (const budget of defaultWindowsSplitDemoPrBudgets) { + expect(prRows).toContainEqual(expect.objectContaining({ + os: 'windows-latest', + runner_label: 'windows', + ...budget, + })) + } + for (const budget of [minimalWindowsTaroVuePrBudget, windowsTaroVueWebPrBudget]) { expect(prRows).toContainEqual(expect.objectContaining({ os: 'windows-latest', runner_label: 'windows', @@ -1050,7 +1083,7 @@ describe('e2e watch workflow', () => { ...budget, })) } - for (const budget of slowWindowsTaroTtPrBudgets) { + for (const budget of minimalWindowsTaroTtPrBudgets) { expect(prRows).toContainEqual(expect.objectContaining({ os: 'windows-latest', runner_label: 'windows', diff --git a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts index 7c8d28a08e..b790a432ba 100644 --- a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts +++ b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts @@ -3216,6 +3216,28 @@ describe('watch-hmr regression cases', () => { expect(uniAppCase?.webHmr?.touchCssEntryOnSourceMutation).toBe(false) }) + it('keeps Taro Vite Vue3 Web HMR marker and utility class in one template mutation', () => { + const demoExtendedCases = buildDemoExtendedCases('/repo') + const taroVue3Case = demoExtendedCases.find(watchCase => watchCase.name === 'taro-vite-vue3-tailwindcss-v4') + const webHmr = taroVue3Case?.webHmr + + expect(webHmr?.injectMarkerElement).toBe(false) + expect(webHmr?.touchCssEntryOnSourceMutation).toBe(false) + expect(webHmr).toBeDefined() + + const mutated = webHmr?.mutate( + '\n', + { + marker: 'watch-marker', + classLiteral: 'bg-[#123456] w-[88px] h-[44px]', + classVariableName: '__twWatchWebClass', + }, + ) + + expect(mutated).toContain('watch-marker-web') + expect(mutated).toMatch(/', snippet) }, sourceDomReplacementSequence: [ { From 92e85fb5738fb33d80cd934d55a57ab7fad9da58 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 16:41:15 +0800 Subject: [PATCH 12/14] =?UTF-8?q?fix(vite):=20=E9=81=BF=E5=85=8D=20watch?= =?UTF-8?q?=20=E7=94=9F=E6=88=90=E6=9C=9F=E9=97=B4=E6=8F=90=E5=89=8D?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E7=BC=96=E8=AF=91=E4=BC=9A=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generator-css/pipeline/execution.ts | 10 +++ .../bundlers/shared/generator-css/validate.ts | 10 +++ .../src/compiler/compiler-owner-state.ts | 66 ++++++++++++++++- .../test/bundlers/generator-css.unit.test.ts | 72 +++++++++++++++++++ .../test/compiler/owner-lifecycle.test.ts | 40 +++++++++++ 5 files changed, 197 insertions(+), 1 deletion(-) diff --git a/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/pipeline/execution.ts b/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/pipeline/execution.ts index 3c09424ecb..f65689f005 100644 --- a/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/pipeline/execution.ts +++ b/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/pipeline/execution.ts @@ -4,6 +4,7 @@ import type { GeneratorPipelineExecutionContext, GeneratorPipelineOutputContext import type { CompilationScopeDependency } from '@/compiler' import process from 'node:process' import { getCompilationSessionPool } from '@/compiler' +import { runCompilerOwnerActivity } from '@/compiler/compiler-owner-state' import { getTailwindGenerationSessionPool } from '@/compiler/tailwind-generation-session-pool' import { shouldUseMiniProgramCssBranch } from '@/runtime-branch' import { filterUnsupportedMiniProgramTailwindV4Candidates } from '@/tailwindcss/v4-engine/candidates' @@ -57,6 +58,15 @@ function resolveCompilationDependencies(dependencies: Iterable): Compila export async function executeGeneratorPipeline( context: GeneratorPipelineExecutionContext, +): Promise { + return runCompilerOwnerActivity( + context.runtimeState, + () => executeGeneratorPipelineWithOwner(context), + ) +} + +async function executeGeneratorPipelineWithOwner( + context: GeneratorPipelineExecutionContext, ): Promise { const { cssHandlerOptions, diff --git a/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/validate.ts b/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/validate.ts index 99afabd7e6..d00beaccb5 100644 --- a/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/validate.ts +++ b/packages/weapp-tailwindcss/src/bundlers/shared/generator-css/validate.ts @@ -1,4 +1,5 @@ import type { GenerateCssByGeneratorOptions } from './types' +import { runCompilerOwnerActivity } from '@/compiler/compiler-owner-state' import { getTailwindGenerationSessionPool } from '@/compiler/tailwind-generation-session-pool' import { normalizeWeappTailwindcssGeneratorOptions } from '@/generator' import { collectGeneratedRawSourceCandidates } from './class-selectors' @@ -12,6 +13,15 @@ export interface ValidateCandidatesByGeneratorOptions extends Omit> { + return runCompilerOwnerActivity( + options.runtimeState, + () => validateCandidatesByGeneratorWithOwner(options), + ) +} + +async function validateCandidatesByGeneratorWithOwner( + options: ValidateCandidatesByGeneratorOptions, ): Promise> { const { candidates, diff --git a/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts b/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts index b36d72c462..2a7e902c7a 100644 --- a/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts +++ b/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts @@ -1,4 +1,8 @@ const compilerOwnerDisposals = new WeakMap>() +const compilerOwnerActivities = new WeakMap void> +}>() export function ensureCompilerOwnerActive(owner: object) { if (compilerOwnerDisposals.has(owner)) { @@ -6,6 +10,63 @@ export function ensureCompilerOwnerActive(owner: object) { } } +async function acquireCompilerOwnerActivity(owner: object) { + const currentDisposal = compilerOwnerDisposals.get(owner) + if (currentDisposal) { + await currentDisposal + } + + let state = compilerOwnerActivities.get(owner) + if (!state) { + state = { + active: 0, + idleWaiters: new Set(), + } + compilerOwnerActivities.set(owner, state) + } + state.active += 1 + + let released = false + return () => { + if (released) { + return + } + released = true + state.active -= 1 + if (state.active > 0) { + return + } + compilerOwnerActivities.delete(owner) + for (const resolve of state.idleWaiters) { + resolve() + } + state.idleWaiters.clear() + } +} + +function waitForCompilerOwnerIdle(owner: object) { + const state = compilerOwnerActivities.get(owner) + if (!state || state.active === 0) { + return Promise.resolve() + } + return new Promise((resolve) => { + state.idleWaiters.add(resolve) + }) +} + +export async function runCompilerOwnerActivity( + owner: object, + activity: () => T | Promise, +) { + const release = await acquireCompilerOwnerActivity(owner) + try { + return await activity() + } + finally { + release() + } +} + export function runCompilerOwnerDisposal( owner: object, dispose: () => Promise, @@ -14,7 +75,10 @@ export function runCompilerOwnerDisposal( if (currentDisposal) { return currentDisposal } - const disposal = Promise.resolve().then(dispose).finally(() => { + const disposal = Promise.resolve().then(async () => { + await waitForCompilerOwnerIdle(owner) + await dispose() + }).finally(() => { if (compilerOwnerDisposals.get(owner) === disposal) { compilerOwnerDisposals.delete(owner) } diff --git a/packages/weapp-tailwindcss/test/bundlers/generator-css.unit.test.ts b/packages/weapp-tailwindcss/test/bundlers/generator-css.unit.test.ts index 7b7ac370b7..c76e6ef54f 100644 --- a/packages/weapp-tailwindcss/test/bundlers/generator-css.unit.test.ts +++ b/packages/weapp-tailwindcss/test/bundlers/generator-css.unit.test.ts @@ -230,6 +230,78 @@ describe('bundlers/shared generator css', () => { }) }) + it('keeps the compiler owner alive until an in-flight generation finishes', async () => { + let releaseGeneration: (() => void) | undefined + let markGenerationStarted: (() => void) | undefined + const generationGate = new Promise((resolve) => { + releaseGeneration = resolve + }) + const generationStarted = new Promise((resolve) => { + markGenerationStarted = resolve + }) + let disposed = false + const dispose = vi.fn(() => { + disposed = true + }) + vi.doMock('@/generator', () => createDefaultGeneratorMock({ + createWeappTailwindcssGenerator: vi.fn(() => ({ + dispose, + async generate() { + markGenerationStarted?.() + await generationGate + if (disposed) { + throw new Error('generator was disposed during generation') + } + return { + css: '.text-\\[24rpx\\]{font-size:24rpx}', + rawCss: '.text-\\[24rpx\\]{font-size:24rpx}', + target: 'weapp', + classSet: new Set(['text-[24rpx]']), + dependencies: [], + root: null, + } + }, + })), + })) + + const runtimeState = { + tailwindRuntime: { majorVersion: 4 } as any, + readyPromise: Promise.resolve(), + } + const { generateTailwindV4Css } = await import('@/bundlers/shared/v4-generation-core') + const { disposeCompilerOwner } = await import('@/compiler') + const generation = generateTailwindV4Css({ + opts: { + generator: { target: 'weapp' }, + styleHandler: vi.fn(async (code: string) => ({ css: code })), + } as any, + runtimeState, + runtime: new Set(['text-[24rpx]']), + rawSource: '@import "tailwindcss";', + file: '/workspace/src/app.css', + outputFile: 'app.wxss', + cssHandlerOptions: { + isMainChunk: true, + majorVersion: 4, + } as any, + cssUserHandlerOptions: {} as any, + styleHandler: vi.fn(async (code: string) => ({ css: code })), + debug: vi.fn(), + }) + + await generationStarted + const disposal = disposeCompilerOwner(runtimeState) + await Promise.resolve() + expect(dispose).not.toHaveBeenCalled() + + releaseGeneration?.() + await expect(generation).resolves.toMatchObject({ + classSet: new Set(['text-[24rpx]']), + }) + await disposal + expect(dispose).toHaveBeenCalledTimes(1) + }) + it('adapts generated mini-program CSS through the complete framework PostCSS pipeline', async () => { const frameworkPlugin = { postcssPlugin: 'framework-token-transform', diff --git a/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts b/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts index 010090b6f4..4c260d6fc2 100644 --- a/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts +++ b/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts @@ -117,6 +117,46 @@ describe('compiler owner lifecycle', () => { expect(getCompilationSessionPool(owner)).not.toBe(pool) }) + it('waits for owner activity before disposal and queues the next build behind it', async () => { + const { + runCompilerOwnerActivity, + runCompilerOwnerDisposal, + } = await import('@/compiler/compiler-owner-state') + const owner = {} + let releaseCurrent: (() => void) | undefined + const currentGate = new Promise((resolve) => { + releaseCurrent = resolve + }) + let currentStarted = false + let disposed = false + let nextStarted = false + + const current = runCompilerOwnerActivity(owner, async () => { + currentStarted = true + await currentGate + }) + await vi.waitFor(() => expect(currentStarted).toBe(true)) + + const disposal = runCompilerOwnerDisposal(owner, async () => { + disposed = true + }) + const next = runCompilerOwnerActivity(owner, async () => { + nextStarted = true + }) + + await Promise.resolve() + expect(disposed).toBe(false) + expect(nextStarted).toBe(false) + + releaseCurrent?.() + await current + await disposal + await next + + expect(disposed).toBe(true) + expect(nextStarted).toBe(true) + }) + it('does not retain owner-bound state across 100 build lifecycles', async () => { const dispose = vi.fn() const createGenerator = vi.fn(() => ({ From d3983fcbf5af5176284ac2f111d5de9c4452baa7 Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 18:24:15 +0800 Subject: [PATCH 13/14] =?UTF-8?q?fix(ci):=20=E6=8B=86=E5=88=86=20Windows?= =?UTF-8?q?=20Taro=20watch=20=E9=95=BF=E8=BD=AE=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/e2e-watch.yml | 72 +++++++++++++++---- .../test/ci/workflows.test.ts | 68 +++++++++--------- .../test/watch-hmr-regression.unit.test.ts | 23 ++++++ 3 files changed, 115 insertions(+), 48 deletions(-) diff --git a/.github/workflows/e2e-watch.yml b/.github/workflows/e2e-watch.yml index e1376b9aca..eebc70fcd2 100644 --- a/.github/workflows/e2e-watch.yml +++ b/.github/workflows/e2e-watch.yml @@ -314,24 +314,56 @@ jobs: - os: windows-latest runner_label: windows watch_case: taro-vite-react-tailwindcss-v4 - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 80 + # Windows PR 只跑主包与两个分包的真实主样式 HMR;完整多轮由 Linux/macOS 与 nightly 覆盖。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 watch_timeout_ms: '420000' watch_poll_ms: '40' - watch_max_plugin_process_ms: '60000' - watch_command_timeout_ms: '4200000' + watch_max_plugin_process_ms: '18000' + watch_command_timeout_ms: '2400000' + - os: windows-latest + runner_label: windows + watch_case: taro-vite-react-tailwindcss-v4 + round_profile: web-only + watch_save_snapshots: '1' + # Web HMR 独立运行,避免小程序长轮次失败后从头重跑并耗尽 job 预算。 + watch_web_only: '1' + watch_max_attempts: '1' + timeout_minutes: 25 + watch_timeout_ms: '420000' + watch_poll_ms: '40' + watch_command_timeout_ms: '1200000' - os: windows-latest runner_label: windows watch_case: taro-webpack-react-tailwindcss-v4 - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 80 + # Webpack 轮询重建在 Windows 上单轮接近一分钟,PR 只保留主包与两个分包的主样式契约。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 watch_timeout_ms: '420000' watch_poll_ms: '40' - watch_max_plugin_process_ms: '60000' + watch_max_plugin_process_ms: '18000' taro_dev_ready_timeout_ms: '900000' - watch_command_timeout_ms: '4200000' + watch_command_timeout_ms: '2400000' + - os: windows-latest + runner_label: windows + watch_case: taro-webpack-react-tailwindcss-v4 + round_profile: web-only + watch_save_snapshots: '1' + # Webpack H5 独立验证浏览器 HMR,避免和 20 余次小程序重建串行。 + watch_web_only: '1' + watch_max_attempts: '1' + timeout_minutes: 25 + watch_timeout_ms: '600000' + watch_poll_ms: '40' + watch_command_timeout_ms: '1200000' - os: windows-latest runner_label: windows watch_case: taro-vite-vue3-tailwindcss-v4 @@ -361,14 +393,30 @@ jobs: - os: windows-latest runner_label: windows watch_case: taro-webpack-vue3-tailwindcss-v4 - round_profile: default + round_profile: main-style watch_save_snapshots: '1' - timeout_minutes: 80 + # 一次默认轮次会串行触发 20 余次完整 Webpack 重建;PR 改为主包与两个分包的主样式门禁。 + watch_main_style_only: '1' + watch_main_style_subpackage_limit: '2' + watch_max_attempts: '1' + timeout_minutes: 45 watch_timeout_ms: '600000' watch_poll_ms: '40' - watch_max_plugin_process_ms: '60000' + watch_max_plugin_process_ms: '18000' taro_dev_ready_timeout_ms: '900000' - watch_command_timeout_ms: '4200000' + watch_command_timeout_ms: '2400000' + - os: windows-latest + runner_label: windows + watch_case: taro-webpack-vue3-tailwindcss-v4 + round_profile: web-only + watch_save_snapshots: '1' + # Vue3 Web HMR 单独运行,避免小程序轮次失败后连同 H5 从头重跑。 + watch_web_only: '1' + watch_max_attempts: '1' + timeout_minutes: 25 + watch_timeout_ms: '600000' + watch_poll_ms: '40' + watch_command_timeout_ms: '1200000' - os: windows-latest runner_label: windows watch_case: demo-uni diff --git a/packages/weapp-tailwindcss/test/ci/workflows.test.ts b/packages/weapp-tailwindcss/test/ci/workflows.test.ts index a191172524..bb95331e32 100644 --- a/packages/weapp-tailwindcss/test/ci/workflows.test.ts +++ b/packages/weapp-tailwindcss/test/ci/workflows.test.ts @@ -670,7 +670,7 @@ describe('e2e watch workflow', () => { expect(cases).toContain('macos:22:demo-core:main-style') expect(cases).toContain('windows:22:demo-uni:default') for (const watchCase of windowsSplitDemoCases) { - const profile = watchCase === 'mpx-tailwindcss-v4' || watchCase === 'taro-vite-vue3-tailwindcss-v4' + const profile = watchCase === 'mpx-tailwindcss-v4' || watchCase.startsWith('taro-') ? 'main-style' : 'default' expect(cases, `windows should split ${watchCase}`).toContain(`windows:22:${watchCase}:${profile}`) @@ -689,7 +689,7 @@ describe('e2e watch workflow', () => { expect(macosPlatformCases).toEqual(['uni-app-vite-tailwindcss-v4:mp-weixin']) expect(rows.filter(row => row.runner_label === 'macos')).toHaveLength(9) expect(rows.filter(row => row.runner_label === 'linux')).toHaveLength(12) - expect(rows.filter(row => row.runner_label === 'windows')).toHaveLength(18) + expect(rows.filter(row => row.runner_label === 'windows')).toHaveLength(21) for (const row of [ rows.find(row => row.runner_label === 'macos' && row.watch_case === 'demo-core'), rows.find(row => row.runner_label === 'windows' && row.watch_case === 'mpx-tailwindcss-v4'), @@ -912,34 +912,35 @@ describe('e2e watch workflow', () => { watch_timeout_ms: '420000', watch_command_timeout_ms: '1200000', } - const slowWindowsTaroReactPrBudgets = [ - { - watch_case: 'taro-vite-react-tailwindcss-v4', - round_profile: 'default', - timeout_minutes: 80, - watch_timeout_ms: '420000', - watch_max_plugin_process_ms: '60000', - watch_command_timeout_ms: '4200000', - }, - { - watch_case: 'taro-webpack-react-tailwindcss-v4', - round_profile: 'default', - timeout_minutes: 80, - watch_timeout_ms: '420000', - watch_max_plugin_process_ms: '60000', - taro_dev_ready_timeout_ms: '900000', - watch_command_timeout_ms: '4200000', - }, - ] - const slowWindowsTaroWebpackVuePrBudget = { - watch_case: 'taro-webpack-vue3-tailwindcss-v4', - round_profile: 'default', - timeout_minutes: 80, - watch_timeout_ms: '600000', - watch_max_plugin_process_ms: '60000', - taro_dev_ready_timeout_ms: '900000', - watch_command_timeout_ms: '4200000', - } + const minimalWindowsTaroPrBudgets = [ + { watchCase: 'taro-vite-react-tailwindcss-v4', timeoutMs: '420000' }, + { watchCase: 'taro-webpack-react-tailwindcss-v4', timeoutMs: '420000', taroReadyTimeoutMs: '900000' }, + { watchCase: 'taro-webpack-vue3-tailwindcss-v4', timeoutMs: '600000', taroReadyTimeoutMs: '900000' }, + ].map(({ watchCase, timeoutMs, taroReadyTimeoutMs }) => ({ + watch_case: watchCase, + round_profile: 'main-style', + watch_main_style_only: '1', + watch_main_style_subpackage_limit: '2', + watch_max_attempts: '1', + timeout_minutes: 45, + watch_timeout_ms: timeoutMs, + watch_max_plugin_process_ms: '18000', + ...(taroReadyTimeoutMs == null ? {} : { taro_dev_ready_timeout_ms: taroReadyTimeoutMs }), + watch_command_timeout_ms: '2400000', + })) + const windowsTaroWebPrBudgets = [ + { watchCase: 'taro-vite-react-tailwindcss-v4', timeoutMs: '420000' }, + { watchCase: 'taro-webpack-react-tailwindcss-v4', timeoutMs: '600000' }, + { watchCase: 'taro-webpack-vue3-tailwindcss-v4', timeoutMs: '600000' }, + ].map(({ watchCase, timeoutMs }) => ({ + watch_case: watchCase, + round_profile: 'web-only', + watch_web_only: '1', + watch_max_attempts: '1', + timeout_minutes: 25, + watch_timeout_ms: timeoutMs, + watch_command_timeout_ms: '1200000', + })) const slowWindowsTaroAlipayPrBudgets = [ 'taro-vite-react-tailwindcss-v4:alipay', 'taro-vite-vue3-tailwindcss-v4:alipay', @@ -1064,18 +1065,13 @@ describe('e2e watch workflow', () => { ...budget, })) } - for (const budget of slowWindowsTaroReactPrBudgets) { + for (const budget of [...minimalWindowsTaroPrBudgets, ...windowsTaroWebPrBudgets]) { expect(prRows).toContainEqual(expect.objectContaining({ os: 'windows-latest', runner_label: 'windows', ...budget, })) } - expect(prRows).toContainEqual(expect.objectContaining({ - os: 'windows-latest', - runner_label: 'windows', - ...slowWindowsTaroWebpackVuePrBudget, - })) for (const budget of slowLinuxTaroTtPrBudgets) { expect(prRows).toContainEqual(expect.objectContaining({ os: 'ubuntu-latest', diff --git a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts index b790a432ba..5b259db643 100644 --- a/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts +++ b/packages/weapp-tailwindcss/test/watch-hmr-regression.unit.test.ts @@ -3315,6 +3315,29 @@ describe('watch-hmr regression cases', () => { watch_web_only: '1', watch_max_attempts: '1', }), + ...[ + 'taro-vite-react-tailwindcss-v4', + 'taro-webpack-react-tailwindcss-v4', + 'taro-webpack-vue3-tailwindcss-v4', + ].flatMap(watchCase => [ + expect.objectContaining({ + os: 'windows-latest', + runner_label: 'windows', + watch_case: watchCase, + round_profile: 'main-style', + watch_main_style_only: '1', + watch_main_style_subpackage_limit: '2', + watch_max_attempts: '1', + }), + expect.objectContaining({ + os: 'windows-latest', + runner_label: 'windows', + watch_case: watchCase, + round_profile: 'web-only', + watch_web_only: '1', + watch_max_attempts: '1', + }), + ]), expect.objectContaining({ os: 'windows-latest', runner_label: 'windows', From adddbf5cf178eed318e41a190f7aba15b44bc30b Mon Sep 17 00:00:00 2001 From: ice breaker <1324318532@qq.com> Date: Tue, 21 Jul 2026 18:25:45 +0800 Subject: [PATCH 14/14] =?UTF-8?q?perf(vite):=20=E6=B6=88=E9=99=A4=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E4=BC=9A=E8=AF=9D=E7=A7=9F=E7=BA=A6=E7=9A=84=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E8=B7=AF=E5=BE=84=E8=B0=83=E5=BA=A6=E5=BC=80=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/compiler/compiler-owner-state.ts | 29 ++++++++++++++----- .../test/compiler/owner-lifecycle.test.ts | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts b/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts index 2a7e902c7a..5a6e4915fb 100644 --- a/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts +++ b/packages/weapp-tailwindcss/src/compiler/compiler-owner-state.ts @@ -4,16 +4,20 @@ const compilerOwnerActivities = new WeakMap void> }>() +type CompilerOwnerActivityRelease = () => void + export function ensureCompilerOwnerActive(owner: object) { if (compilerOwnerDisposals.has(owner)) { throw new Error('Compiler owner 正在释放,不能创建新的编译状态。') } } -async function acquireCompilerOwnerActivity(owner: object) { +function acquireCompilerOwnerActivity( + owner: object, +): CompilerOwnerActivityRelease | Promise { const currentDisposal = compilerOwnerDisposals.get(owner) if (currentDisposal) { - await currentDisposal + return currentDisposal.then(() => acquireCompilerOwnerActivity(owner)) } let state = compilerOwnerActivities.get(owner) @@ -54,16 +58,27 @@ function waitForCompilerOwnerIdle(owner: object) { }) } -export async function runCompilerOwnerActivity( +export function runCompilerOwnerActivity( owner: object, activity: () => T | Promise, -) { - const release = await acquireCompilerOwnerActivity(owner) +): Promise> { + const acquired = acquireCompilerOwnerActivity(owner) + if (typeof acquired !== 'function') { + return acquired.then(release => runCompilerOwnerActivityWithRelease(activity, release)) + } + return runCompilerOwnerActivityWithRelease(activity, acquired) +} + +function runCompilerOwnerActivityWithRelease( + activity: () => T | Promise, + release: CompilerOwnerActivityRelease, +): Promise> { try { - return await activity() + return Promise.resolve(activity()).finally(release) } - finally { + catch (error) { release() + return Promise.reject(error) } } diff --git a/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts b/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts index 4c260d6fc2..626b915933 100644 --- a/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts +++ b/packages/weapp-tailwindcss/test/compiler/owner-lifecycle.test.ts @@ -135,7 +135,7 @@ describe('compiler owner lifecycle', () => { currentStarted = true await currentGate }) - await vi.waitFor(() => expect(currentStarted).toBe(true)) + expect(currentStarted).toBe(true) const disposal = runCompilerOwnerDisposal(owner, async () => { disposed = true