From 14b89d536b91a10933003df7f661a58beff3042a Mon Sep 17 00:00:00 2001 From: songchenglin3 <353833373@qq.com> Date: Fri, 12 Jun 2026 11:58:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3taro=E7=89=88?= =?UTF-8?q?=E6=9C=ACdemo=E5=8F=98=E9=87=8F=E6=96=87=E4=BB=B6=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E6=B3=A8=E5=85=A5=E5=AF=BC=E8=87=B4=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/skills/nutui-taro-weapp-wxss/SKILL.md | 106 +++++++++++++++++ scripts/build-taro.mjs | 11 +- scripts/harmony/update-taro-entry.js | 1 - scripts/taro/generate-nutui-taro.js | 14 ++- scripts/taro/generate-taro-route.js | 1 - .../nutui.react.scss.taro.bundle.scss | 107 ++++++++++++++++++ 6 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 .cursor/skills/nutui-taro-weapp-wxss/SKILL.md create mode 100644 src/packages/nutui.react.scss.taro.bundle.scss diff --git a/.cursor/skills/nutui-taro-weapp-wxss/SKILL.md b/.cursor/skills/nutui-taro-weapp-wxss/SKILL.md new file mode 100644 index 0000000000..22291132d3 --- /dev/null +++ b/.cursor/skills/nutui-taro-weapp-wxss/SKILL.md @@ -0,0 +1,106 @@ +--- +name: nutui-taro-weapp-wxss +description: >- + NutUI React Taro 小程序 WXSS 编译超时修复:nutui-taro-demo 样式 bundle 合并、 + 删除无效 renderingMode、app-origin.wxss 体积治理。Use when 微信小程序报 + [ WXSS 文件编译错误] something must be wrong、wcsc timeout、app-origin.wxss + 过大、predev:taro 重写 app.config、或修改 generate-nutui-taro.js / + nutui.react.scss.taro.bundle.scss。 +--- + +# NutUI Taro 小程序 WXSS 编译治理 + +## 1. 背景与根因 + +**现象**:`[ WXSS 文件编译错误] something must be wrong` + `Error: timeout`;偶发 `无效的 app.json ["renderingMode"]`。 + +**根因**:`app.ts` → `nutui.react.scss.taro.ts` 曾 **100+ 条**独立 `import` 组件 scss;Taro `sass.resource` 向**每个**文件注入 `variables.scss` + `theme-default.scss`(含 base64 `@font-face`)。 + +| 指标 | 修复前 | 修复后(bundle) | +| --- | --- | --- | +| `app-origin.wxss` | ~4MB | ~0.3–0.9MB | +| `@font-face` 重复 | ~216 | ~2–10 | + +**不是**单个组件(如 `switch.scss`)的 bug,而是 **demo 全量样式打包方式** 导致。 + +**数据流(修复后)**: + +```text +app.ts → nutui.react.scss.taro.ts → nutui.react.scss.taro.bundle.scss + ├─ variables + theme(各 1 次) + └─ 全部组件 scss → dist/weapp/app-origin.wxss +``` + +--- + +## 2. 最小改动清单 + +| 文件 | 改动 | +| --- | --- | +| `scripts/taro/generate-nutui-taro.js` | 新增 `bundleScssStr`;遍历组件拼 `@import`;`nutui.react.scss.taro.ts` 改为单 import bundle;新增写 `nutui.react.scss.taro.bundle.scss` | +| `src/packages/nutui.react.scss.taro.bundle.scss` | variables/theme + 全部组件 `@import`(**自动生成,勿手改**) | +| `scripts/build-taro.mjs` | `buildCSS` / `buildHarmonyCSS` 的 glob 排除 `nutui.react.scss.taro.bundle.scss`,避免打进 npm 按组件发包 | +| `scripts/harmony/update-taro-entry.js` | 删除 `renderingMode: 'mixed'` | +| `scripts/taro/generate-taro-route.js` | 同上 | + +- `nutui.react.scss.ts`(H5)**不变**,`generate-nutui.js` 仍生成 100+ 条 JS import +- **勿只改** `app.config.ts`:`predev:taro` 会跑 `update-taro-entry.js` 覆盖 +- **不在最小集**:`config/index.js` minimize、各组件 scss calc 优化、`package.json` dev:weapp + +### 边界说明(H5 / 发包) + +| 场景 | 是否走 bundle | 说明 | +| --- | --- | --- | +| H5 文档站 `sites/mobile` + `nutui.react.scss.ts` | 否 | Vite `additionalData` 只注入 variables,theme 在 `main.tsx` 单独 import 一次,无 wcsc 超时问题 | +| Taro demo `dev:taro`(weapp / h5) | 是 | `app.ts` → `nutui.react.scss.taro.ts` → bundle | +| Taro 发包 `build:taro` | 否 | bundle 被 glob exclude;构建结束会删除 `nutui.react.scss.js`;业务方仍 `import '@nutui/nutui-react-taro/dist/es/packages/xxx/style'` | + +--- + +## 3. 解决 / 好处 / 影响 + +**解决**:WXSS 超时;无效 `renderingMode` 警告;demo 可预览(需登录开发者工具 + 清缓存)。 + +**好处**:样式单入口;不改 `build:taro` 发包;新增组件仍由 `generate-nutui-taro.js` 写入 bundle。 + +| 命令 | 影响 | +| --- | --- | +| `dev:taro weapp` | 有 | +| `build:taro` / `build:taro:demo` | 无(bundle 已在 `build-taro.mjs` glob 中排除) | +| `prepare` / `generate:file:taro` | 有(再生 bundle) | +| `VITE_APP_PROJECT_ID=jmapp` | bundle 写死 default 主题,需另行验证 | + +**已知限制**:`build:weapp` 生产压缩时 postcss-calc 可能破坏嵌套 `var+calc`(dev 无此问题);游客模式 `webapi_getwxaasyncsecinfo:fail` 为环境问题。 + +--- + +## 4. 验证 + +```bash +pnpm run dev:taro weapp +wc -c packages/nutui-taro-demo/dist/weapp/app-origin.wxss +grep -c '@font-face' packages/nutui-taro-demo/dist/weapp/app-origin.wxss +``` + +期望:体积远小于 4MB;`@font-face` 为个位数。 + +--- + +## 5. 未采纳方案(备查) + +| 方案 | 未采纳原因 | +| --- | --- | +| 各组件 scss 局部 CSS 变量 | 非主因,扩大 diff | +| `config/index.js` minimize(false) | dev 不需要 | +| `webpackImporter: false` | 引发 Module not found | +| sass.resource 置空 | 嵌套 @import(popup→overlay)缺变量 | +| 手改 app.config.ts | predev:taro 会覆盖 | + +--- + +## 6. Agent 自检 + +- [ ] 只改生成脚本 + bundle + `build-taro.mjs` exclude,未扩大组件 scss diff? +- [ ] `build-taro.mjs` 已排除 `nutui.react.scss.taro.bundle.scss`? +- [ ] 两个生成脚本已去掉 `renderingMode`? +- [ ] 仍超时:查 `app-origin.wxss` 体积、游客模式、是否未重新 dev diff --git a/scripts/build-taro.mjs b/scripts/build-taro.mjs index 4380c57b82..bf7446d930 100644 --- a/scripts/build-taro.mjs +++ b/scripts/build-taro.mjs @@ -348,7 +348,11 @@ async function copyStyles() { // 构建样式 async function buildCSS(themeName = '') { const componentScssFiles = await glob(['src/packages/**/*.scss'], { - ignore: ['src/packages/**/demo.scss'], + ignore: [ + 'src/packages/**/demo.scss', + // demo 专用全量 bundle,不参与 npm 按组件发包 + 'src/packages/nutui.react.scss.taro.bundle.scss', + ], }) const variables = await readFile( @@ -438,7 +442,10 @@ async function buildCSS(themeName = '') { // 构建样式 async function buildHarmonyCSS(themeName = '') { const componentScssFiles = await glob(['src/packages/**/*.scss'], { - ignore: ['src/packages/**/demo.scss'], + ignore: [ + 'src/packages/**/demo.scss', + 'src/packages/nutui.react.scss.taro.bundle.scss', + ], }) const variables = await readFile( diff --git a/scripts/harmony/update-taro-entry.js b/scripts/harmony/update-taro-entry.js index 88a92e77aa..540c0fef21 100644 --- a/scripts/harmony/update-taro-entry.js +++ b/scripts/harmony/update-taro-entry.js @@ -72,7 +72,6 @@ export default defineAppConfig({ navigationBarTitleText: 'NutUI-React', navigationBarTextStyle: 'black' }, - renderingMode: 'mixed', components: ['pages/index/index', ...(subPackages.map(subPackage => { return subPackage.pages.map(page => \`\${subPackage.root}/\${page}\`) }).flat())] diff --git a/scripts/taro/generate-nutui-taro.js b/scripts/taro/generate-nutui-taro.js index 9cb481ad19..2480d3da11 100644 --- a/scripts/taro/generate-nutui-taro.js +++ b/scripts/taro/generate-nutui-taro.js @@ -7,6 +7,7 @@ let importStr = `` let importRNStr = `` let importMarkdownStr = `` let importScssStr = `\n` +let bundleScssStr = `@import '../styles/variables.scss';\n@import '../styles/theme-default.scss';\n` const packages = [] const mds = [] const raws = [] @@ -21,6 +22,7 @@ config.nav.map((item) => { importRNStr += `import ${name} from '@/packages/${name.toLowerCase()}/index.${rn?'rn':'taro'}'\n` importRNStr += `export * from '@/packages/${name.toLowerCase()}/index.${rn?'rn':'taro'}'\n` importScssStr += `import '@/packages/${name.toLowerCase()}/${name.toLowerCase()}.scss'\n` + bundleScssStr += `@import './${name.toLowerCase()}/${name.toLowerCase()}.scss';\n` packages.push(name) glob @@ -99,8 +101,7 @@ fs.outputFile( // } // ) -let taroScssfileStr = ` -${importScssStr} +let taroScssfileStr = `import './nutui.react.scss.taro.bundle.scss' export default { "NutUI":"NutUI-Taro" };` fs.outputFile( path.resolve(__dirname, '../../src/packages/nutui.react.scss.taro.ts'), @@ -111,6 +112,15 @@ fs.outputFile( } ) +fs.outputFile( + path.resolve(__dirname, '../../src/packages/nutui.react.scss.taro.bundle.scss'), + bundleScssStr, + 'utf8', + (error) => { + if (error) throw error + } +) + fs.outputFile( path.resolve(__dirname, '../../src/packages/nutui.react.scss.ts'), importScssStr, diff --git a/scripts/taro/generate-taro-route.js b/scripts/taro/generate-taro-route.js index a695e0979f..6d45e68bfe 100644 --- a/scripts/taro/generate-taro-route.js +++ b/scripts/taro/generate-taro-route.js @@ -42,7 +42,6 @@ export default defineAppConfig ({ navigationBarTitleText: 'NutUI-React', navigationBarTextStyle: 'black' }, - renderingMode: 'mixed', components: ['pages/index/index', ...(subPackages.map(subPackage => { return subPackage.pages.map(page => \`\${subPackage.root}/\${page}\`) }).flat())] diff --git a/src/packages/nutui.react.scss.taro.bundle.scss b/src/packages/nutui.react.scss.taro.bundle.scss new file mode 100644 index 0000000000..839d068077 --- /dev/null +++ b/src/packages/nutui.react.scss.taro.bundle.scss @@ -0,0 +1,107 @@ +@import '../styles/variables.scss'; +@import '../styles/theme-default.scss'; +@import './button/button.scss'; +@import './cell/cell.scss'; +@import './cellgroup/cellgroup.scss'; +@import './configprovider/configprovider.scss'; +@import './image/image.scss'; +@import './overlay/overlay.scss'; +@import './divider/divider.scss'; +@import './grid/grid.scss'; +@import './griditem/griditem.scss'; +@import './layout/layout.scss'; +@import './col/col.scss'; +@import './row/row.scss'; +@import './safearea/safearea.scss'; +@import './space/space.scss'; +@import './sticky/sticky.scss'; +@import './backtop/backtop.scss'; +@import './elevator/elevator.scss'; +@import './fixednav/fixednav.scss'; +@import './hoverbutton/hoverbutton.scss'; +@import './hoverbuttonitem/hoverbuttonitem.scss'; +@import './navbar/navbar.scss'; +@import './sidebar/sidebar.scss'; +@import './sidebaritem/sidebaritem.scss'; +@import './tabbar/tabbar.scss'; +@import './tabbaritem/tabbaritem.scss'; +@import './tabpane/tabpane.scss'; +@import './tabs/tabs.scss'; +@import './address/address.scss'; +@import './calendar/calendar.scss'; +@import './calendaritem/calendaritem.scss'; +@import './calendarcard/calendarcard.scss'; +@import './cascader/cascader.scss'; +@import './checkbox/checkbox.scss'; +@import './checkboxgroup/checkboxgroup.scss'; +@import './datepicker/datepicker.scss'; +@import './datepickerview/datepickerview.scss'; +@import './form/form.scss'; +@import './formitem/formitem.scss'; +@import './input/input.scss'; +@import './inputnumber/inputnumber.scss'; +@import './menu/menu.scss'; +@import './menuitem/menuitem.scss'; +@import './numberkeyboard/numberkeyboard.scss'; +@import './picker/picker.scss'; +@import './pickerview/pickerview.scss'; +@import './radio/radio.scss'; +@import './radiogroup/radiogroup.scss'; +@import './range/range.scss'; +@import './rate/rate.scss'; +@import './searchbar/searchbar.scss'; +@import './shortpassword/shortpassword.scss'; +@import './signature/signature.scss'; +@import './switch/switch.scss'; +@import './textarea/textarea.scss'; +@import './uploader/uploader.scss'; +@import './actionsheet/actionsheet.scss'; +@import './badge/badge.scss'; +@import './dialog/dialog.scss'; +@import './drag/drag.scss'; +@import './empty/empty.scss'; +@import './infiniteloading/infiniteloading.scss'; +@import './loading/loading.scss'; +@import './noticebar/noticebar.scss'; +@import './notify/notify.scss'; +@import './popover/popover.scss'; +@import './popup/popup.scss'; +@import './pulltorefresh/pulltorefresh.scss'; +@import './resultpage/resultpage.scss'; +@import './skeleton/skeleton.scss'; +@import './swipe/swipe.scss'; +@import './toast/toast.scss'; +@import './animate/animate.scss'; +@import './animatingnumbers/animatingnumbers.scss'; +@import './audio/audio.scss'; +@import './avatar/avatar.scss'; +@import './avatargroup/avatargroup.scss'; +@import './circleprogress/circleprogress.scss'; +@import './collapse/collapse.scss'; +@import './collapseitem/collapseitem.scss'; +@import './countdown/countdown.scss'; +@import './ellipsis/ellipsis.scss'; +@import './imagepreview/imagepreview.scss'; +@import './indicator/indicator.scss'; +@import './lottie/lottie.scss'; +@import './pagination/pagination.scss'; +@import './price/price.scss'; +@import './progress/progress.scss'; +@import './segmented/segmented.scss'; +@import './step/step.scss'; +@import './steps/steps.scss'; +@import './swiper/swiper.scss'; +@import './swiperitem/swiperitem.scss'; +@import './table/table.scss'; +@import './tag/tag.scss'; +@import './tour/tour.scss'; +@import './video/video.scss'; +@import './virtuallist/virtuallist.scss'; +@import './quickenter/quickenter.scss'; +@import './avatarcropper/avatarcropper.scss'; +@import './barrage/barrage.scss'; +@import './card/card.scss'; +@import './timedetail/timedetail.scss'; +@import './timeselect/timeselect.scss'; +@import './trendarrow/trendarrow.scss'; +@import './watermark/watermark.scss'; From 6e19b26c6c2e00af345450d0b7a96d4b099ee624 Mon Sep 17 00:00:00 2001 From: songchenglin3 <353833373@qq.com> Date: Fri, 12 Jun 2026 15:00:42 +0800 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20=E8=A7=A3=E5=86=B3=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/build.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/build.mjs b/scripts/build.mjs index 91a7b71bc4..02805d4e1a 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -297,7 +297,11 @@ async function copyStyles() { // 构建样式 async function buildCSS(themeName = '') { const componentScssFiles = await glob(['src/packages/**/*.scss'], { - ignore: ['src/packages/**/demo.scss'], + ignore: [ + 'src/packages/**/demo.scss', + // Taro demo 专用全量 bundle,不参与 H5 npm 按组件发包 + 'src/packages/nutui.react.scss.taro.bundle.scss', + ], }) const variables = await readFile(