Skip to content

Commit 2c7dc3f

Browse files
perf(weapp-tailwindcss): 优化多构建器热路径缓存复用 (#819)
* perf(weapp-tailwindcss): 优化多构建器热路径缓存复用 * perf(weapp-tailwindcss): 继续压缩 JS 与 gulp 热路径开销 * chore(deps): upgrade * perf(postcss): 优化 resolver 与 process options 缓存 * perf(postcss): 扩展简单样式选项缓存命中 * perf(postcss): 复用选择器热路径预计算结果 * perf(postcss): 减少 spacing 归一化重复扫描 * perf(postcss): 预计算 post 插件 host 追加条件 * perf(postcss): 复用默认 rem 与 px 转换配置 * perf(postcss): 复用 calc 默认插件配置 * perf(postcss): 收紧自定义属性清理解析条件 * perf(postcss): 精简样式流水线节点构建 * perf(weapp-tailwindcss): 复用模板替换参数对象 * perf(weapp-tailwindcss): 精简模板处理热路径 * perf(weapp-tailwindcss): 复用 js 与模板处理默认分支 * perf(weapp-tailwindcss): 减少候选解析与 legacy 回退开销 * perf(weapp-tailwindcss): 复用类名判定与 js 后处理结果 * perf(weapp-tailwindcss): 复用 eval 选项并收紧替换扫描 * perf(weapp-tailwindcss): 精简调用表达式遍历默认分支 * perf(weapp-tailwindcss): 精简名称匹配默认路径 * perf(weapp-tailwindcss): 复用标签忽略判定上下文 * perf(weapp-tailwindcss): 精简标签忽略名称匹配 * perf(weapp-tailwindcss): 延迟构建标签忽略匹配器 * perf(weapp-tailwindcss): 复用默认忽略路径集合 * perf(weapp-tailwindcss): 修正模块替换空输入快路径 * perf(weapp-tailwindcss): 延迟分配导入标记集合 * perf(weapp-tailwindcss): 延迟分配遍历去重集合 * perf(weapp-tailwindcss): 精简模块图空结果分支 * perf(weapp-tailwindcss): 精简模块替换判空分支 * perf(weapp-tailwindcss): 提前返回空路径更新分支 * perf(weapp-tailwindcss): 按需收集模块元数据 * perf(weapp-tailwindcss): 精简标签模板默认分支 * perf(weapp-tailwindcss): 精简 js 遍历默认分支 * perf(weapp-tailwindcss): 延迟分配调试样本列表 * perf(weapp-tailwindcss): 精简 class 语义关键字归一化 * perf(weapp-tailwindcss): 后移 class context 判定 * perf(weapp-tailwindcss): 提前过滤非 class helper 调用 * perf(weapp-tailwindcss): 延迟分配候选计划缓存 * perf(weapp-tailwindcss): 精简忽略注释扫描分支 * perf(weapp-tailwindcss): 精简字面量值读取分支 * perf(weapp-tailwindcss): 精简任意值候选判定分支 * perf(weapp-tailwindcss): 内联 fallback 启用态判定 * perf(weapp-tailwindcss): 按需收集调试采样信息 * perf(weapp-tailwindcss): 复用字面量级 replacement cache * perf(weapp-tailwindcss): 提前短路 fallback 候选扫描 * perf(weapp-tailwindcss): 复用最近 escaped candidate cache * fix(weapp-tailwindcss): harden hot-update comment carrier coverage * fix(packages): 修复 packages 目录下所有 ESLint error * fix(packages-runtime): 修复 packages-runtime 目录下所有 ESLint error * fix(e2e,scripts,apps): 修复 e2e/scripts/apps 目录下可修复的 ESLint error * fix(weapp-tailwindcss): 回退 Object.hasOwn 为 hasOwnProperty.call,兼容 ES2021 lib * chore(weapp-tailwindcss): 升级 tsconfig lib 至 ES2022,恢复 Object.hasOwn 用法 * fix(e2e): 修复 mpx same-class-literal escaped classes 断言不兼容 minRequired=0 的问题 summary 级断言原先硬编码 toBeGreaterThan(0),未考虑 mpx 等 minRequiredGlobalStyleEscapedClasses=0 的场景。现改为与 per-round 断言一致,使用 toBeGreaterThanOrEqual(minRequiredEscapedClasses)。 * fix(website): 修复 website 及周边文件的 ESLint e18e error 涉及 website/src、.claude/skills、.codex/skills、.github/scripts, 将函数内 regex 提取至模块作用域,修复 prefer-array-at / prefer-spread-syntax / prefer-timer-args 等规则。 * fix: 修复全局剩余 ESLint error 并优化 eslint 配置 - 修复 packages/weapp-tailwindcss 中 41 个 e18e/prefer-static-regex 错误 - 修复 website/scripts 中 58 个 e18e/prefer-static-regex 错误 - 修复 apps/tailwindcss-weapp/src/env.d.ts 中过时的 eslint-disable 注释 - eslint.config.js 新增 ignore 规则:markdown、test、benchmark、skills、d.ts 等 - website/eslint.config.mjs 将 better-tailwindcss 规则降级为 warn * fix: 修复 CI 剩余 15 个 ESLint error - packages-runtime/ui/vite.config.ts: 提取 /\.css$/ 正则到模块作用域 - vitest.config.ts: 提取 extractBaseDirFromGlob 中的正则到模块作用域 - website/config/blog.ts: 提取 require 调用并添加 eslint-disable 注释 - packages-runtime/ui/eslint.config.js: 忽略 test/scripts 目录,降级 better-tailwindcss 规则 * fix: vitest.config.ts 使用展开语法替代 Array.from * fix: .gitattributes 为源码文件添加 eol=lf 修复 Windows CI CRLF 问题 * fix: .gitattributes 全局默认 eol=lf 彻底修复 Windows CI CRLF 问题 * fix(demo): 修复 native-mina Windows spawn EINVAL 和 mpx-v4 序列化器重复注册 - native-mina: 在 Windows 上为 spawn 添加 shell: true 选项 - mpx-tailwindcss-v4: 禁用 webpack 持久化缓存避免序列化器重复注册 * feat(weapp-tailwindcss): 为所有编译插件入口新增 weappTailwindcss 别名导出 * fix(demo): 修复 mpx-tailwindcss-v4 webpack 序列化器重复注册问题 monkey-patch ObjectMiddleware.register 忽略重复注册错误, 该问题由 pnpm + webpack5 环境下模块多路径加载触发 * test(weapp-tailwindcss): 修复 Windows 路径分隔符导致的 21 个测试失败 * test(weapp-tailwindcss): 修复 normalizeCssEntries 测试在 Windows 下路径 drive letter 不匹配 * chore: 进入 changeset alpha 预发布模式 * chore(deps): upgrade * chore(deps): upgrade * fix(eslint): 忽略 apps 中生成的 result.json * Version Packages (alpha) * perf(weapp-tailwindcss): 优化 vite 构建与热更新路径 * chore: update * fix: 修复 vite basedir 对齐与快照回归 * fix: 修复 vite 增量 runtime set 对 rpx upx 的回退 * perf: 优化 vite css 增量缓存命中 * perf: 复用 vite 同轮重复 css 转换结果 * test: 完善 e2e watch 分组入口 * chore: 添加 e2e watch changeset * chore: upgrade to pnpm@10.32.1 * Version Packages (alpha) * chore(deps): upgrade * feat(e2e): 增强 watch 任意值回归 * fix: reduce generated file git noise * test: 调整 watch hmr 脚本 coverage 统计 * ci: 避免矩阵重复上传 coverage * chore(deps): upgrade tailwindcss-patch to 8.7.4-alpha.0 * fix(vite): fallback dynamic wxml arbitrary classes * fix: migrate weapp-tailwindcss to tailwindcss-patch v9 runtime * fix: finish tailwindcss-patch v9 alpha.2 migration * fix: restore monorepo build after patch v9 migration * fix: restore cross-framework style hmr stability * test: add internal style-only watch helper * Version Packages (alpha) * chore(deps): upgrade * ci: split website seo quality workflow * ci: remove seo gate from pull requests * refactor(build): isolate cli bundle for cac v7 * fix(cli): restore node 18 compatibility * fix(ci): resolve lint regression * fix: stabilize monorepo build pipeline * fix: resolve remaining ci build regressions * fix: address remaining cross-platform ci failures * fix: support node 20 postbuild snapshots * docs: clarify tailwindcss v4 css entry usage * fix(website): stabilize api docs build output * chore(deps): upgrade * chore(deps): upgrade * chore: update snap * docs: 补充 IntelliSense configFile 配置说明 * docs: 统一 taro vite 的样式入口写法 * test: add app-origin wxss snapshot fixtures * test: capture taro vite v4 app-origin css snapshots * docs: warn against taro vite usage * test: skip taro vite v4 e2e project * fix: preserve root helper selectors in runtime css prune * fix: narrow runtime css prune matching * refactor: remove runtime css prune * refactor: drop orphan runtime css prune file * test: update webpack runtime metadata assertions * test: extend vite bundler test timeouts * fix: normalize arbitrary hex case in js transform * chore(deps): upgrade * chore(deps): upgrade * chore(deps): upgrade * fix: 修复 uni-app vite 脚本任意值热更新 * fix: 完善 demo 和 apps 的 js 热更新回归校验 * ci: 增加多平台 watch hmr 分组回归 * fix: skip incompatible v4 patcher candidates * fix: relax watch hmr rollback fallback * ci: 收缩 actions 自动触发范围 * chore(deps): upgrade * chore(deps): upgrade * chore: ignore .weapp-vite * chore(deps): upgrade * fix: 收紧 JS classNameSet 命中并升级 tailwindcss-patch * test: 补齐 issue33 热更新 CRUD 与跨平台 watch 矩阵 * test: 修正 uni-app-vue3-vite shorthand 集成夹具断言 * chore: upgrade snap * chore: upgrade tailwindcss-patch: 9.0.0 * ci: 修正 e2e watch 工作流矩阵定义 * ci: 修正 e2e watch pull_request 路径过滤 * test: 扩大任意值热更新高风险回归覆盖 * test: 同步 e2e watch issue33 热更新断言 * feat(website): 优化赞助区与导航展示 * feat(website): 替换 weapp-vite 导航图标 * docs(website): 更新 v4 注册方式与智能提示说明 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 49e50d8 commit 2c7dc3f

File tree

435 files changed

+26236
-14753
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

435 files changed

+26236
-14753
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"weapp-tailwindcss": patch
3+
---
4+
5+
完善 `e2e:watch` 热更新回归流程:
6+
7+
- 新增 `demo``apps` 分组测试入口,避免分组执行时重复跑单 case 文件
8+
-`test:watch-hmr` 切换为 `node --import tsx` 启动,修复部分环境下 `tsx` IPC `EPERM` 导致的回归无法启动问题
9+
- 调整 `apps/taro-webpack-tailwindcss-v4` 的 watch 回归命令,确保 Taro webpack 场景下模板、脚本、样式热更新都能稳定校验

.changeset/honest-hounds-hug.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"weapp-tailwindcss": patch
3+
---
4+
5+
增强多平台热更新回归覆盖,补齐 `uni-app``uni-app-vue3-vite``mpx` 的 comment-carrier 场景,并新增汇总断言校验 same-class 稳定性、comment-carrier 命中数量与热更新时间指标。
6+
7+
修复 `uni-app-vue3-vite` 在 comment-carrier 场景下 marker 无法进入运行时输出导致 watch-hmr 卡住的问题,同时将关键 HMR 用例接入 `E2E Watch` 工作流,确保 PR 与夜间任务都能持续校验多平台热更新链路。

.changeset/pre.json

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"mode": "pre",
3+
"tag": "alpha",
4+
"initialVersions": {
5+
"react-app": "0.0.0",
6+
"rsmax-app-ts": "1.0.0",
7+
"tailwindcss-weapp": "0.0.1",
8+
"taro-webpack-tailwindcss-v4": "1.0.0",
9+
"uni-app-x-hbuilderx-tailwindcss3": "0.0.0",
10+
"uni-app-x-hbuilderx-tailwindcss4": "0.0.0",
11+
"vite-native": "1.0.19",
12+
"vite-native-skyline": "1.0.1",
13+
"vite-native-ts": "1.0.12",
14+
"vite-native-ts-skyline": "1.0.1",
15+
"vue-app": "0.0.0",
16+
"weapp-wechat-zhihu": "1.0.0",
17+
"@native-app/postcss7-compat": "1.0.1",
18+
"benchmark": "0.0.1",
19+
"benchmark-tailwindcss3": "0.0.8",
20+
"benchmark-tailwindcss4": "0.0.6",
21+
"@weapp-tailwindcss-demo/gulp-app": "0.0.5",
22+
"@weapp-tailwindcss-demo/mpx-app": "0.1.0",
23+
"@weapp-tailwindcss-demo/mpx-tailwindcss-v4": "0.1.0",
24+
"@weapp-tailwindcss-demo/native": "1.0.0",
25+
"@weapp-tailwindcss-demo/native-mina": "1.0.0",
26+
"@weapp-tailwindcss-demo/native-ts": "1.0.0",
27+
"@weapp-tailwindcss-demo/rax-app": "0.1.0",
28+
"@weapp-tailwindcss-demo/taro-app": "1.0.1",
29+
"@weapp-tailwindcss-demo/taro-app-vite": "1.0.0",
30+
"@weapp-tailwindcss-demo/taro-vite-tailwindcss-v4": "1.0.0",
31+
"@weapp-tailwindcss-demo/taro-vue3-app": "1.0.0",
32+
"@weapp-tailwindcss-demo/taro-webpack-tailwindcss-v4": "1.0.0",
33+
"@weapp-tailwindcss-demo/uni-app": "0.1.0",
34+
"@weapp-tailwindcss-demo/uni-app-tailwindcss-v4": "0.0.0",
35+
"@weapp-tailwindcss-demo/uni-app-vue3-vite": "0.0.1",
36+
"@weapp-tailwindcss-demo/uni-app-webpack-tailwindcss-v4": "0.1.0",
37+
"@weapp-tailwindcss-demo/uni-app-webpack5": "0.1.0",
38+
"@weapp-tailwindcss-demo/uni-app-x-hbuilderx-tailwindcss3": "0.0.0",
39+
"@weapp-tailwindcss-demo/uni-app-x-hbuilderx-tailwindcss4": "0.0.0",
40+
"@weapp-tailwindcss-demo/web": "1.0.0",
41+
"@weapp-tailwindcss/e2e": "0.0.0",
42+
"@weapp-tailwindcss/cva": "0.1.6",
43+
"@weapp-tailwindcss/merge": "2.1.6",
44+
"@weapp-tailwindcss/merge-v3": "0.1.6",
45+
"@weapp-tailwindcss/runtime": "0.1.5",
46+
"tailwind-variant-v3": "0.2.1",
47+
"theme-transition": "2.0.1",
48+
"@weapp-tailwindcss/typography": "0.2.6",
49+
"@weapp-tailwindcss/ui": "0.0.6",
50+
"@weapp-tailwindcss/variants": "0.2.1",
51+
"@weapp-tailwindcss/variants-v3": "0.1.1",
52+
"@weapp-tailwindcss/babel": "0.0.3",
53+
"@weapp-tailwindcss/build-all": "0.0.21",
54+
"@weapp-tailwindcss/debug-uni-app-x": "0.0.3",
55+
"@weapp-tailwindcss/experimental": "0.0.1",
56+
"@weapp-tailwindcss/init": "1.0.10",
57+
"@weapp-tailwindcss/logger": "1.1.0",
58+
"@weapp-tailwindcss/minify-preserve": "0.0.0",
59+
"@weapp-tailwindcss/postcss": "2.1.5",
60+
"@weapp-tailwindcss/shared": "1.1.2",
61+
"tailwindcss-config": "1.1.4",
62+
"tailwindcss-core-plugins-extractor": "0.2.0",
63+
"tailwindcss-injector": "1.0.10",
64+
"@weapp-tailwindcss/test-helper": "0.0.1",
65+
"weapp-style-injector": "0.0.1",
66+
"weapp-tailwindcss": "4.10.3",
67+
"weapp-tw": "0.0.0",
68+
"weapptw": "0.0.0",
69+
"wetw": "0.1.1",
70+
"@weapp-tailwindcss/website": "1.0.17"
71+
},
72+
"changesets": [
73+
"bright-horses-clean",
74+
"e2e-watch-group-entry",
75+
"honest-hounds-hug",
76+
"perf-hot-path-caching",
77+
"tailwindcss-patch-874-alpha",
78+
"weapp-tailwindcss-alias"
79+
]
80+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'weapp-tailwindcss': patch
3+
'weapp-tw': patch
4+
'tailwindcss-injector': patch
5+
'@weapp-tailwindcss/postcss': patch
6+
'@weapp-tailwindcss/ui': patch
7+
'@weapp-tailwindcss/shared': patch
8+
'@weapp-tailwindcss/init': patch
9+
'@weapp-tailwindcss/typography': patch
10+
'wetw': patch
11+
---
12+
13+
升级 `tailwindcss-patch``8.7.4-alpha.0`,同步消费最新的 alpha 版本依赖。
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'weapp-tailwindcss': minor
3+
---
4+
5+
为所有编译插件入口新增 `weappTailwindcss` 别名导出,方便用户统一简写引用:
6+
7+
- `weapp-tailwindcss/webpack``UnifiedWebpackPluginV5` 的别名
8+
- `weapp-tailwindcss/webpack4``UnifiedWebpackPluginV4` 的别名
9+
- `weapp-tailwindcss/vite``UnifiedViteWeappTailwindcssPlugin` 的别名
10+
- `weapp-tailwindcss/gulp``createPlugins` 的别名

.claude/skills/playwright-cli/references/test-generation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ test('login flow', async ({ page }) => {
4545
await page.getByRole('textbox', { name: 'Password' }).fill('password123')
4646
await page.getByRole('button', { name: 'Sign In' }).click()
4747

48-
// Add assertions
49-
await expect(page).toHaveURL(/.*dashboard/)
48+
// 验证跳转到 dashboard
49+
await expect(page).toHaveURL('https://example.com/dashboard')
5050
})
5151
```
5252

.codex/skills/playwright-cli/references/test-generation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ test('login flow', async ({ page }) => {
4545
await page.getByRole('textbox', { name: 'Password' }).fill('password123')
4646
await page.getByRole('button', { name: 'Sign In' }).click()
4747

48-
// Add assertions
49-
await expect(page).toHaveURL(/.*dashboard/)
48+
// 验证跳转到 dashboard
49+
await expect(page).toHaveURL('https://example.com/dashboard')
5050
})
5151
```
5252

.gitattributes

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
## Handle line endings automatically for files detected as
1515
## text and leave all files detected as binary untouched.
1616
## This will handle all files NOT defined below.
17-
* text=auto
17+
## 强制所有文本文件使用 LF,避免 Windows CI 上 CRLF 导致 prettier 报错
18+
* text=auto eol=lf
1819

1920
# Source code
2021
*.bash text eol=lf

.github/scripts/e2e-watch-report.cjs

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@ const fs = require('node:fs')
66
const path = require('node:path')
77
const process = require('node:process')
88

9+
/** 匹配换行符(兼容 CRLF) */
10+
const CRLF_RE = /\r?\n/
11+
/** 替换换行为转义表示 */
12+
const NEWLINE_REPLACE_RE = /\n/g
13+
/** 匹配 rollback 阶段(不区分大小写) */
14+
const ROLLBACK_RE = /rollback/i
15+
/** 按管道符分隔 token */
16+
const TOKEN_SEPARATOR_RE = /\s+\|\s+/
17+
/** 匹配截断的 bg hex / 未闭合 bg / 未闭合 px token(多行) */
18+
const BG_PX_FALLBACK_RE = /\bbg-\s+\[#?[0-9a-fA-F]{3,8}\]?|\bbg-\[[^\]]*$|\bpx-\[[^\]]*$/m
19+
/** 截断的 bg hex token */
20+
const TRUNCATED_BG_HEX_RE = /\bbg-\s+\[#?[0-9a-fA-F]{3,8}\]?/g
21+
/** 未闭合 bg token */
22+
const UNTERMINATED_BG_RE = /\bbg-\[[^\]]*$/gm
23+
/** 未闭合 px token */
24+
const UNTERMINATED_PX_RE = /\bpx-\[[^\]]*$/gm
25+
/** bg token 内含空白 */
26+
const BG_WHITESPACE_INSIDE_RE = /\bbg-\[[^\]\s]*\s[^\]\s]*\]/g
27+
/** px token 内含空白 */
28+
const PX_WHITESPACE_INSIDE_RE = /\bpx-\[[^\]\s]*\s[^\]\s]*\]/g
29+
/** 缓存失效相关关键词 */
30+
const CACHE_INVALIDATION_RE = /invalidation|context-not-found|cache/
31+
/** 文件系统竞态相关关键词 */
32+
const FS_RACE_RE = /enoent|eperm|ebusy|eacces|crlf|lf|rename|path/
33+
/** 进程/超时相关关键词 */
34+
const PROCESS_TIMEOUT_RE = /timeout|exceeded|watch process exited|sigkill|fatal|killed/
35+
/** 匹配 mutation kind */
36+
const MUTATION_KIND_RE = /mutation=(template|script|style)/g
37+
/** 匹配 round 名称 */
38+
const ROUND_NAME_RE = /round=([a-z0-9-]+)/g
39+
940
const ROOT_DIR = path.resolve(process.cwd(), 'e2e/benchmark/e2e-watch-hmr')
1041
const SNAPSHOTS_DIR = path.join(ROOT_DIR, 'snapshots')
1142
const FAILURES_DIR = path.join(ROOT_DIR, 'failures')
@@ -35,7 +66,7 @@ function listFilesSafe(dir, filter) {
3566

3667
function parseKvContent(content) {
3768
const out = {}
38-
for (const line of content.split(/\r?\n/)) {
69+
for (const line of content.split(CRLF_RE)) {
3970
const index = line.indexOf('=')
4071
if (index <= 0) {
4172
continue
@@ -61,10 +92,10 @@ function summarizeDiff(before, after) {
6192
}
6293
const beforeContext = before
6394
.slice(Math.max(0, index - 40), Math.min(before.length, index + 120))
64-
.replace(/\n/g, '\\n')
95+
.replace(NEWLINE_REPLACE_RE, '\\n')
6596
const afterContext = after
6697
.slice(Math.max(0, index - 40), Math.min(after.length, index + 120))
67-
.replace(/\n/g, '\\n')
98+
.replace(NEWLINE_REPLACE_RE, '\\n')
6899
return `firstDiff=${index}, len=${before.length}->${after.length}\n before=${beforeContext}\n after=${afterContext}`
69100
}
70101

@@ -99,7 +130,7 @@ function resolvePhase(rawPhase, errorText) {
99130
if (rawPhase === 'add' || rawPhase === 'modify') {
100131
return 'hot-update'
101132
}
102-
if (/rollback/i.test(errorText)) {
133+
if (ROLLBACK_RE.test(errorText)) {
103134
return 'rollback'
104135
}
105136
return 'hot-update'
@@ -118,13 +149,13 @@ function pickPrimaryFailure(failureLogs, failureSnapshots) {
118149
phase: resolvePhase(kv.phase || '', kv.error || ''),
119150
project: kv.project || 'unknown',
120151
sourceFile: kv.source || 'unknown',
121-
tokens: (kv.tokens || '').split(/\s+\|\s+/).filter(Boolean),
152+
tokens: (kv.tokens || '').split(TOKEN_SEPARATOR_RE).filter(Boolean),
122153
error: kv.error || '',
123154
}
124155
}
125156

126157
if (failureSnapshots.length > 0) {
127-
const item = failureSnapshots[failureSnapshots.length - 1]
158+
const item = failureSnapshots.at(-1)
128159
return {
129160
source: 'snapshot',
130161
file: item.dir,
@@ -164,7 +195,7 @@ function pickFailureSnapshot(primary, snapshots) {
164195
&& item.meta.roundName === primary.round
165196
&& item.meta.phase === primary.phaseRaw,
166197
)
167-
return exact || candidates[candidates.length - 1]
198+
return exact || candidates.at(-1)
168199
}
169200

170201
function pickMetricFromReport(report, primary) {
@@ -218,9 +249,7 @@ function pickSnippet(source, probes) {
218249
}
219250

220251
if (hitIndex < 0) {
221-
const fallback = source.match(
222-
/\bbg-\s+\[#?[0-9a-fA-F]{3,8}\]?|\bbg-\[[^\]]*$|\bpx-\[[^\]]*$/m,
223-
)
252+
const fallback = source.match(BG_PX_FALLBACK_RE)
224253
if (fallback?.index != null) {
225254
hitIndex = fallback.index
226255
}
@@ -237,11 +266,11 @@ function pickSnippet(source, probes) {
237266

238267
function detectTokenAnomalies(source) {
239268
const patterns = [
240-
{ name: 'truncated-bg-hex', re: /\bbg-\s+\[#?[0-9a-fA-F]{3,8}\]?/g },
241-
{ name: 'unterminated-bg-token', re: /\bbg-\[[^\]]*$/gm },
242-
{ name: 'unterminated-px-token', re: /\bpx-\[[^\]]*$/gm },
243-
{ name: 'bg-whitespace-inside-token', re: /\bbg-\[[^\]\s]*\s[^\]\s]*\]/g },
244-
{ name: 'px-whitespace-inside-token', re: /\bpx-\[[^\]\s]*\s[^\]\s]*\]/g },
269+
{ name: 'truncated-bg-hex', re: TRUNCATED_BG_HEX_RE },
270+
{ name: 'unterminated-bg-token', re: UNTERMINATED_BG_RE },
271+
{ name: 'unterminated-px-token', re: UNTERMINATED_PX_RE },
272+
{ name: 'bg-whitespace-inside-token', re: BG_WHITESPACE_INSIDE_RE },
273+
{ name: 'px-whitespace-inside-token', re: PX_WHITESPACE_INSIDE_RE },
245274
]
246275

247276
const findings = []
@@ -267,7 +296,7 @@ function scoreAttribution(primary, evidence) {
267296
['进程/超时问题', 0],
268297
])
269298

270-
if (/invalidation|context-not-found|cache/.test(text)) {
299+
if (CACHE_INVALIDATION_RE.test(text)) {
271300
scores.set(
272301
'cache key/invalidation',
273302
scores.get('cache key/invalidation') + 2,
@@ -286,13 +315,13 @@ function scoreAttribution(primary, evidence) {
286315
scores.get('transform emit mismatch') + 3,
287316
)
288317
}
289-
if (/enoent|eperm|ebusy|eacces|crlf|lf|rename|path/.test(text)) {
318+
if (FS_RACE_RE.test(text)) {
290319
scores.set(
291320
'文件系统竞态/路径换行差异',
292321
scores.get('文件系统竞态/路径换行差异') + 3,
293322
)
294323
}
295-
if (/timeout|exceeded|watch process exited|sigkill|fatal|killed/.test(text)) {
324+
if (PROCESS_TIMEOUT_RE.test(text)) {
296325
scores.set('进程/超时问题', scores.get('进程/超时问题') + 3)
297326
}
298327
if (primary.phase === 'rollback') {
@@ -393,7 +422,7 @@ function generateDiffSummary() {
393422
lines.push(`- ${path.basename(file)}`)
394423
const content = readUtf8(file).trim()
395424
if (content) {
396-
for (const line of content.split(/\r?\n/)) {
425+
for (const line of content.split(CRLF_RE)) {
397426
lines.push(` ${line}`)
398427
}
399428
}
@@ -619,8 +648,8 @@ function publishJobSummary() {
619648
for (const log of logs) {
620649
const content = fs.readFileSync(path.join(FAILURES_DIR, log), 'utf8')
621650
const kindMatches
622-
= content.match(/mutation=(template|script|style)/g) || []
623-
const roundMatches = content.match(/round=([a-z0-9-]+)/g) || []
651+
= content.match(MUTATION_KIND_RE) || []
652+
const roundMatches = content.match(ROUND_NAME_RE) || []
624653
for (const matched of kindMatches) {
625654
failedKinds.add(matched.replace('mutation=', ''))
626655
}

.github/workflows/ci.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ on:
55
# branches: ['main']
66
pull_request:
77
types: [opened, synchronize]
8+
paths-ignore:
9+
- 'website/**'
10+
- '**/*.md'
11+
- '.changeset/**'
812
workflow_dispatch:
913

14+
concurrency:
15+
group: ci-${{ github.event.pull_request.number || github.ref }}
16+
cancel-in-progress: true
17+
1018
permissions:
1119
contents: read
1220

@@ -17,8 +25,7 @@ jobs:
1725
strategy:
1826
fail-fast: false
1927
matrix:
20-
os: [ubuntu-latest, windows-latest, macos-latest]
21-
node-version: [20, 22, 24]
28+
include: ${{ fromJSON(github.event_name == 'workflow_dispatch' && '[{"os":"ubuntu-latest","node-version":22},{"os":"ubuntu-latest","node-version":20},{"os":"ubuntu-latest","node-version":24},{"os":"windows-latest","node-version":22},{"os":"macos-latest","node-version":22}]' || '[{"os":"ubuntu-latest","node-version":22}]') }}
2229
runs-on: ${{ matrix.os }}
2330
# Remote Caching enabled - configure TURBO_TOKEN and TURBO_TEAM in repository settings
2431
env:
@@ -50,9 +57,6 @@ jobs:
5057
- name: Lint
5158
run: pnpm lint
5259

53-
- name: SEO Quality Gate (website)
54-
run: pnpm --filter @weapp-tailwindcss/website seo:quality:strict
55-
5660
- name: Build
5761
run: pnpm build
5862

@@ -64,11 +68,13 @@ jobs:
6468
run: |
6569
{
6670
echo "## CI 状态说明"
67-
echo "- 本工作流负责:lint、website SEO 质量门禁、build、unit/integration tests、coverage 上传。"
71+
echo "- 本工作流负责:lint、build、unit/integration tests、coverage 上传。"
6872
echo "- \`pnpm e2e:watch\` 已拆分到独立工作流:\`E2E Watch\`(.github/workflows/e2e-watch.yml)。"
73+
echo "- website SEO 质量门禁已拆分到独立工作流:\`Website SEO Quality\`(.github/workflows/website-seo-quality.yml)。"
6974
} >> "$GITHUB_STEP_SUMMARY"
7075
7176
- name: Upload coverage reports to Codecov
77+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 22
7278
uses: codecov/codecov-action@v5
7379
env:
7480
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

0 commit comments

Comments
 (0)