项目全面审核报告
审计日期:2026-05-16
审计目录:C:\Users\Administrator\WorkBuddy\Claw\lessjs-origin-main
报告语言:中文 + English
范围说明:递归扫描项目自身 TS/JS 前端、构建、SSR/SSG、Web Component、测试与 CI 配置。排除 node_modules/、vendor/、deliverables/、www/dist/、dist-test-ssg-render/ 等依赖、生成物和报告产物。当前工作树仅发现未跟踪目录 dist-test-ssg-render/。
验证命令 / Verification:
deno task fmt:check:通过,184 files checked。
deno task lint:通过,183 files checked。
deno task typecheck:通过。
deno audit:通过,No known vulnerabilities found。
deno task test:通过,493 passed / 0 failed。
deno task build:通过,生成 298 HTML 页面,客户端 island JS 总量 175 KB。
deno task test:e2e:通过,92 passed。
1. 项目概况
- 项目类型:Deno workspace 下的 Web Standards-first 前端框架 / Deno workspace web framework, focused on Web Components, SSR/SSG, Declarative Shadow DOM, islands, docs site and CLI.
- 主框架:LessJS 自研框架 + Lit + Vite + Hono + Deno / LessJS internal framework with Lit, Vite, Hono and Deno.
- 入口文件:
- Workspace 配置:
deno.json
- 统一插件入口:
packages/app/src/index.ts:52
- 核心运行时入口:
packages/core/src/index.ts:20
- Vite adapter 入口:
packages/adapter-vite/src/index.ts:225
- 官网构建入口:
www/vite.config.ts:12
- 代码规模(估算):183 个 TS/JS 源码文件,约 31,858 行。
packages/ 约 122 文件 / 21,575 行;www/ 约 60 文件 / 10,223 行;functions/ 1 文件 / 60 行。
- 构建工具:Deno task + Vite 8.0.10 +
@lessjs/adapter-vite 三阶段构建;测试使用 Deno test 和 Playwright。
English:
- Type: Deno workspace web framework and docs site.
- Main stack: LessJS, Lit, Vite, Hono, Deno, Web Components and DSD.
- Scale: 183 TS/JS source files, about 31.9K lines.
- Build: Deno tasks, Vite 8.0.10, LessJS adapter-vite, Playwright e2e.
2. 严重问题(必须立即修复)
-
问题1:package island 元数据可进入生成 JS,但没有做字符串安全生成和严格校验。
- 位置:
packages/adapter-vite/src/entry-generators.ts:26-28,packages/adapter-vite/src/route-scanner.ts:295-303
- 原因:
tagName 和 modulePath 被直接拼进生成代码:'${i.tagName}': () => import('${i.modulePath}')。scanPackageIslands() 只检查字段存在,没有校验自定义元素名、模块路径、控制字符、引号或换行。
- 风险:如果未来支持第三方 package / 一键 install / registry hub,恶意包可以通过
islands 元数据破坏生成代码,严重时造成构建期或客户端代码注入。
- 修复方案:用
JSON.stringify() 生成所有 JS 字面量;新增 validatePackageIslandMeta(),校验 tagName 必须符合 Custom Element name 规则,modulePath 必须是合法 bare specifier / relative URL,禁止引号、换行、控制字符和协议型危险输入;为恶意 tagName/modulePath 添加单元测试。
- English: Package island metadata is interpolated into generated JavaScript without strict validation. This becomes a code-generation injection risk once third-party packages or a registry are supported.
-
问题2:PWA service worker 会拦截并缓存同源非静态请求,API 响应可能被缓存。
- 位置:
packages/adapter-vite/src/cli/ssg-render.ts:493-519
- 原因:fetch handler 只排除了跨域请求;
/api/ 只是影响 isAsset 判断,仍会进入 networkFirst(),并在 res.ok 时写入 Cache Storage。
- 风险:启用 PWA 后,同源 GET API、用户相关响应或未来动态接口可能被缓存;离线时可能返回过期或不该缓存的数据。非 GET 请求也会被 service worker 处理,行为不可预测。
- 修复方案:在 service worker 顶部加入
if (e.request.method !== 'GET') return;;对 /api/、/rpc/、认证路径直接 return;只缓存 document、script、style、image 等明确允许的资源;为 /api/status、POST 请求、带 Authorization 请求添加 e2e。
- English: The generated service worker caches same-origin non-asset responses. API routes must be excluded explicitly.
-
问题3:构建产物测试实际检查了错误目录,并且缺失时静默跳过。
- 位置:
www/__tests__/build-output.test.ts:13,www/__tests__/build-output.test.ts:17,www/__tests__/build-output.test.ts:30
- 原因:
DIST = join(import.meta.dirname, '..', '..', 'dist') 指向仓库根目录 dist/,但真实构建输出是 www/dist/。目录不存在时测试直接 return,导致“通过”但没有检查任何产物。
- 风险:
no Hono virtual entry 和 client island JS < 200KB 两个关键产物约束在单测中是 false positive。发布前可能漏掉大 bundle 或 SSR 内部入口泄漏。
- 修复方案:改为
join(import.meta.dirname ?? '.', '..', 'dist');如果 www/dist 不存在应 throw,不要跳过;在 CI 中保证该测试运行前执行 deno task build。
- English: Build-output tests point to the wrong directory and silently skip when artifacts are missing. This invalidates two artifact-level safety checks.
3. 高危问题(建议尽快修复)
-
问题1:大量测试把布尔断言写成 assertExists(boolean),会让 false 也通过。
- 位置:
packages/create/__tests__/cli.test.ts:71-101,packages/adapter-vite/__tests__/entry-generators.test.ts:5-94,packages/adapter-vite/__tests__/build-manifest.test.ts:52-56
- 原因:
assertExists(false) 不会失败,它只检查值不是 null/undefined。
- 风险:脚手架模板版本、生成代码内容、构建 manifest 阈值等测试可能没有真实断言。例:
packages/create/__tests__/cli.test.ts:94-101 仍检查旧版本片段,但即使条件为 false 也会通过。
- 修复方案:把布尔表达式统一替换为
assert(...) 或 assertEquals(condition, true);为全仓添加 lint 脚本扫描 assertExists(.*includes|assertExists(.*>|assertExists(.*===)。
- English: Many tests use
assertExists() for boolean expressions, so false conditions pass. Replace with assert() or assertEquals().
-
问题2:package island 扫描会在构建期执行包入口代码。
- 位置:
packages/adapter-vite/src/route-scanner.ts:274-284
- 原因:
scanPackageIslands() 通过动态 import(pkg) 读取 islands 数组。
- 风险:一旦支持第三方 registry 或
less add,安装包的任意顶层代码会在构建期执行,扩大供应链攻击面。
- 修复方案:优先读取静态 manifest,如
custom-elements.json 或 lessjs.manifest.json;仅在显式 trustedPackageCode: true 时允许执行包入口;manifest 必须走 JSON schema 验证。
- English: Build-time package discovery executes package entry code. Registry-style workflows should use static manifests instead.
-
问题3:api-consumer 的 AbortController 断开后不会重建,组件重连会一直失败。
- 位置:
www/app/islands/api-consumer.ts:14,www/app/islands/api-consumer.ts:226-240,www/app/islands/api-consumer.ts:251-268
- 原因:
_abortController 在字段初始化时只创建一次,disconnectedCallback() 调用 abort() 后,后续重连仍复用已 aborted signal。
- 风险:页面切换、局部重挂载或未来 view transition 复用场景下,该 island 的 API 请求会立即失败,并可能把 abort 当作错误展示。
- 修复方案:每次请求前创建新的
AbortController;在 catch 中忽略 AbortError;connectedCallback() 中如果 signal.aborted 则重建 controller。
- English: The API demo island reuses an aborted controller after disconnect, causing reconnect fetches to fail.
-
问题4:TOC 对中文标题生成空 id,中文文档锚点可能失效。
- 位置:
www/app/islands/less-toc.ts:99-108,www/app/islands/less-toc.ts:163-168
- 原因:slug 规则
replace(/[^a-z0-9]+/g, '-') 只保留英文数字。中文标题会得到空字符串,第一个标题 id 可能为空,后续变成 -1。
- 风险:中文 guide 页右侧目录链接可能跳转到
# 或错误锚点,影响真实用户阅读。
- 修复方案:使用 Unicode slug:
text.normalize('NFKD').toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, '-');若结果为空,回退到 section-${index};加中文标题单测/e2e。
- English: The TOC slug generator is ASCII-only. Chinese headings can produce empty anchors.
-
问题5:无 JS 或本地脚本失败时,anti-flash 可能让整页一直隐藏。
- 位置:
www/vite.config.ts:109-110,www/public/theme-init.js:21-23
- 原因:页面注入
<style id="less-anti-flash">html{visibility:hidden}</style>,只依赖 theme-init.js 删除。
- 风险:脚本被 CSP、浏览器扩展、网络或用户禁用时,页面不可见。LessJS 的定位是 SSR/SSG 和少 JS,这个行为与产品目标冲突。
- 修复方案:改成只隐藏 body 短时间,加入
<noscript><style>html{visibility:visible}</style></noscript>;或用 CSS 默认主题避免隐藏整页。
- English: The anti-flash cloak can hide the whole page forever if JavaScript does not run.
-
问题6:严格 CSP 下,样式加载优化使用 inline onload 会失效。
- 位置:
www/vite.config.ts:39-48,packages/adapter-vite/src/index.ts:311-318,packages/core/src/html-escape.ts:100-123
- 原因:当前结构化 stylesheet 允许传入任意 attrs,站点配置使用
onload="this.media='all'"。由于 structured injection 会设置 allowHeadExtrasScripts = true,运行时不会剥离 on* 事件属性。
- 风险:如果启用
script-src 'self' 且不允许 inline handler,CSS media 切换不会执行;如果未来开放用户配置 attrs,也会形成 XSS 边界。
- 修复方案:禁止
inject.stylesheets[].attrs 中的 on* 属性;用普通 stylesheet、preload + 安全 JS 模块,或由 framework 生成受控模式;补 CSP e2e。
- English: Inline
onload attributes conflict with strict CSP and should not be accepted through generic attrs.
-
问题7:Cloudflare/Deno Deploy workflow 指向不存在的 demo/ 目录。
- 位置:
.github/workflows/deploy-api.yml:7-8,.github/workflows/deploy-api.yml:20-23
- 原因:workflow 触发路径和部署命令都使用
demo/,但当前仓库没有该目录,实际 API 在 functions/api/term.ts。
- 风险:手动触发或后续误用会直接失败;团队会误以为 API 部署链路仍有效。
- 修复方案:删除该 workflow,或改为 Cloudflare Pages / Deno Deploy 当前真实目录;触发路径改为
functions/**,并加一次 dry-run 验证。
- English: The deployment workflow references a non-existent
demo/ folder. It is stale and will fail.
4. 一般问题(优化项)
-
问题1:PackageIslandMeta 协议过薄,支撑不了 registry hub、自动注册、自动渲染、自动水合。
- 位置:
packages/core/src/types.ts:11-19
- 原因:目前只有
tagName/modulePath/strategy,缺少 export 名、SSR renderability、hydrate events、slots、parts、states、diagnostics、bundle cost、a11y 信息。
- 风险:未来 registry 做大后会靠约定和 README 补信息,工具无法验证。
- 修复方案:新增
LessComponentManifest 或 CEM-compatible 扩展;先做 less validate-manifest,再做 less add。
- English: The package island protocol is too small for registry automation.
-
问题2:root formatter 明确排除了路由和博客源码,真实页面代码缺少格式化保护。
- 位置:
deno.json:89-90,www/app/routes/blog/[slug].ts:1,www/app/routes/decisions/[slug].ts:217-218
- 原因:
www/app/routes/ 和 www/content/blog/ 被 fmt/fmt:check 排除;部分路由还有 deno-fmt-ignore-file,并出现 import 放在文件底部的情况。
- 风险:页面代码长期漂移,review 成本增加,也容易掩盖模板字符串中的真实语法问题。
- 修复方案:把无法格式化的少数文件单独 ignore;其余 route 重新纳入
deno fmt --check;底部 import 移到文件顶部。
- English: Route code is mostly outside formatting checks, which increases maintenance drift.
-
问题3:pre-commit hook 覆盖范围小于 CI。
- 位置:
.githooks/pre-commit:11-24
- 原因:hook 只格式化/lint
packages/,typecheck 只覆盖 core/rpc/ui/adapter-lit/signals/create,遗漏 adapter-vite、app、content、i18n、www。
- 风险:本地提交前通过,但 CI 才发现构建/类型错误。
- 修复方案:hook 直接调用
deno task fmt:check && deno task lint && deno task typecheck;或至少同步 root typecheck entrypoints。
- English: The local pre-commit hook does not match CI coverage.
-
问题4:prism-init.js 在 Prism 不存在时无限重试。
- 位置:
www/public/prism-init.js:9-12
- 原因:每 50ms
setTimeout(init, 50),没有最大次数或停止条件。
- 风险:CDN 被拦截或脚本加载失败时,会产生永久后台定时器。
- 修复方案:加入最大重试次数,例如 20 次;失败后停止并打印一次 debug。
- English: Prism fallback retries forever if Prism is unavailable.
-
问题5:demo 组件默认请求外部 API。
- 位置:
packages/ui/src/less-hero-ping.ts:107-129
- 原因:组件连接后自动 fetch,默认 URL 是
https://less-demo-api.sisyphuszheng.deno.net/api。
- 风险:第三方项目引入该组件时可能意外产生外部请求,影响隐私、离线和企业网络环境。
- 修复方案:默认不请求;只有设置
api-url 时启用;或默认使用相对路径并在 docs 中明确说明。
- English: A packaged UI component performs an external request by default.
-
问题6:终端 demo 文案硬编码测试数量,已经与真实结果不一致。
- 位置:
www/app/shared/term-commands.ts:20,www/app/shared/term-commands.ts:35
- 原因:
VERSION 和 tests 475 passing 为手写常量,当前真实测试结果是 493 passed。
- 风险:公开 demo 信息漂移,降低可信度。
- 修复方案:从版本文件/构建时常量生成;测试数量改为不写死,或由 CI 生成。
- English: The terminal demo has stale hard-coded project statistics.
5. 性能优化建议
-
渲染性能:
- 当前 DSD 渲染已有 metrics:
packages/core/src/types.ts:416-445,这是优势。
- 建议把 metrics 输出到构建 manifest,并按 route 展示慢组件、DSD size、最大嵌套深度。
- English: DSD metrics exist; expose them in build reports per route/component.
-
打包体积:
- 当前构建结果客户端 island JS 总量 175 KB,低于 200 KB 预算。
- 但 lazy island 会在 idle 时全部加载:
packages/adapter-vite/src/entry-generators.ts:102-113。
- 建议改为 DOM-gated lazy loading:只有
document.querySelector(tag) 命中时才 import;中期做 route-level island manifest。
- English: Total JS is within budget, but lazy imports still load all known islands after idle.
-
请求/资源:
www/vite.config.ts:55-98 注入多个 CDN Prism 脚本和 GoatCounter;已有 SRI 和 crossorigin,安全性较好。
- 建议合并 Prism 语言包或按页面需要加载;企业/离线模式提供本地 vendor 选项。
packages/ui/src/less-hero-ping.ts:128-129 默认外部请求应改为 opt-in。
- English: CDN scripts are protected by SRI, but resource count and default external API calls should be reduced.
-
运行时:
www/public/prism-init.js:9-12 无限重试需封顶。
www/app/islands/less-search.ts:174-199 搜索 index 加载失败时静默重置,可增加一次性错误状态,避免用户以为搜索无结果。
packages/adapter-vite/src/cli/ssg-render.ts:493-519 service worker 应减少拦截范围。
- English: Cap retry loops, improve search failure state, and narrow service worker interception.
6. 安全风险清单
-
XSS:
- 已有防护:Markdown 默认 sanitize:
packages/content/src/blog/markdown.ts:101-110;终端命令 escape:www/app/shared/term-commands.ts:10-17;headExtras 默认剥离 script/on*:packages/core/src/html-escape.ts:100-123。
- 风险点:package island 代码生成未安全转义:
packages/adapter-vite/src/entry-generators.ts:26-28;renderDSD() 的 sourceInfo 拼成属性时未 escape:packages/core/src/render-dsd.ts:116-119,并输出到 packages/core/src/render-dsd.ts:271、packages/core/src/render-dsd.ts:285;unsafeHTML(post.html) 依赖上游 sanitize:www/app/routes/blog/[slug].ts:69-90,www/app/routes/decisions/[slug].ts:206-218。
- 修复:所有生成 JS/HTML 的动态字段统一用
JSON.stringify、escapeAttr、schema validation;trustedHtml 必须在文档中标为危险开关。
- English: Sanitization is present, but generated JS, renderDSD sourceInfo and unsafeHTML trust boundaries need tighter contracts.
-
敏感信息:
- 未发现硬编码 API key、secret、token、private key。
- 发现硬编码外部服务:GoatCounter
www/vite.config.ts:95-98,demo API packages/ui/src/less-hero-ping.ts:128,CDN 脚本 www/vite.config.ts:55-91。
- 修复:把 analytics/demo API 标成站点级配置,不进入通用模板默认值。
- English: No secrets found, but external services are hard-coded in demo/site configuration.
-
依赖漏洞:
deno audit 当前无已知漏洞。
- 依赖集中在
deno.json:39-59,关键版本包括 Lit 3、Hono 4、Vite 8.0.10、Playwright 1.59.1、sanitize-html 2.17.4。
- 修复:继续把
deno audit 保留在 CI:.github/workflows/test.yml:28-43。
- English: No known vulnerabilities from
deno audit; keep audit in CI.
-
配置风险:
- PWA SW 缓存边界过宽:
packages/adapter-vite/src/cli/ssg-render.ts:493-519。
packages/create/deno.json:5 使用 deno run -A cli.ts,本地任务权限过宽。
- e2e 任务使用
-A:deno.json:85,可以接受但应限制在测试环境。
- English: Main config risks are broad SW caching and broad Deno permissions in local/test tasks.
7. 代码规范与可维护性
-
命名:
- 包结构清晰,
@lessjs/core、adapter-vite、adapter-lit、content、i18n、ui、app 分层合理。
PackageIslandMeta 命名准确,但协议字段不足:packages/core/src/types.ts:11-19。
- English: Package naming is clear; package-island protocol needs expansion.
-
注释:
- 优点:关键安全修复和 ADR 背景有注释,例如
packages/core/src/html-escape.ts:100-123。
- 问题:部分注释记录版本历史过多,容易变成 changelog;建议把历史移到 ADR/CHANGELOG,源码只保留当前原因。
- English: Comments explain safety decisions, but version-history comments should be reduced.
-
结构:
- 优点:
packages/app/src/index.ts:52-74 通过共享 LessBuildContext 串联 core/content/i18n,结构清晰。
- 问题:
adapter-vite 仍承担 route scan、entry generation、SSG、PWA、CSP、build manifest 等多职责,后续 registry/renderer kernel 应拆出 manifest/validation 子模块。
- English: The app entry is clean; adapter-vite carries many build responsibilities.
-
重复代码:
- 终端命令已抽到共享模块:
www/app/shared/term-commands.ts:1-8,这是正向改进。
- 测试断言模式重复错误:
assertExists(boolean) 多处出现,应批量修复。
- English: Shared command logic is good; repeated assertion misuse should be fixed repo-wide.
8. 构建/依赖风险
-
依赖冲突:
- 当前
deno task typecheck、deno task build、deno task test:e2e 均通过,未发现实际依赖冲突。
- package 内部 imports 多处依赖
jsr:@lessjs/*@^0.14.8,包版本为 0.14.11,语义上可解析到同一 minor,但发布时仍建议统一自动更新。
- English: No current dependency conflict, but internal JSR version ranges should be kept mechanically synchronized.
-
版本不兼容:
packages/create/__tests__/cli.test.ts:94-101 的旧版本片段说明脚手架测试仍有历史遗留。
- 修复:测试应从
buildTemplates() 的输入 fake version 断言,而不是写死旧版本。
- English: Create-package tests still contain stale version expectations.
-
打包异常点:
- 真实构建通过;Phase 1 临时 SSR 大 bundle 会在后处理清理,构建日志显示已移除 3 个 SSR artifact。
- 风险在于
www/__tests__/build-output.test.ts:13-30 当前没有检查真实 www/dist。
- English: Build passes, but artifact tests currently do not validate the actual output directory.
-
环境配置问题:
.github/workflows/deploy-api.yml:20-23 指向不存在的 demo/。
.githooks/pre-commit:11-24 本地校验范围低于 CI。
deno.json:89-90 排除了大量 route 源码格式化。
- English: Deployment workflow is stale, pre-commit is narrower than CI, and route formatting is excluded.
9. 总体评分(1-10)
- 代码质量:7.6
- 安全性:7.1
- 性能:7.4
- 可维护性:7.2
- 综合评分:7.3
English:
- Code quality: 7.6
- Security: 7.1
- Performance: 7.4
- Maintainability: 7.2
- Overall: 7.3
评分理由:当前工程验证非常强,fmt/lint/typecheck/audit/test/build/e2e 全部通过;核心架构方向清晰,DSD/island/build 分层有实际代码支撑。扣分主要来自 registry/一键安装方向的供应链边界尚未收紧、service worker 缓存策略过宽、若干测试是假阳性、route 格式化和本地 hook 覆盖不足。
10. 最终修复优先级清单(TOP 10)
- 修复 package island 生成代码注入风险:
entry-generators.ts:26-28 改用 JSON.stringify,route-scanner.ts:295-303 增加 schema validation。
- 修改 PWA service worker:跳过非 GET、
/api/、认证请求,只缓存明确静态资源。
- 修复
www/__tests__/build-output.test.ts:13-30 的 dist 路径和静默跳过。
- 批量替换
assertExists(boolean) 为 assert() / assertEquals()。
- 把 package island 扫描从动态 import 改为静态 manifest 优先。
- 修复
api-consumer AbortController 重连失败问题。
- 修复
less-toc 中文标题 slug 生成,增加中文 TOC 测试。
- 给 anti-flash 加 no-JS fallback,避免脚本失败导致空白页。
- 删除或修正
.github/workflows/deploy-api.yml 中不存在的 demo/ 部署路径。
- 缩小
deno.json formatter 排除范围,并让 .githooks/pre-commit 调用 root 级 fmt:check/lint/typecheck。
English TOP 10:
- Escape and validate package island metadata before generating JS.
- Narrow service worker caching to safe GET static resources.
- Fix build-output tests to check
www/dist and fail when missing.
- Replace boolean
assertExists() usages with real boolean assertions.
- Prefer static manifests over build-time package imports.
- Recreate AbortController in
api-consumer after reconnect.
- Support Unicode/fallback slugs in
less-toc.
- Add no-JS fallback for the anti-flash cloak.
- Remove or fix the stale
demo/ deploy workflow.
- Re-align formatting and pre-commit checks with root CI tasks.
项目全面审核报告
审计日期:2026-05-16
审计目录:
C:\Users\Administrator\WorkBuddy\Claw\lessjs-origin-main报告语言:中文 + English
范围说明:递归扫描项目自身 TS/JS 前端、构建、SSR/SSG、Web Component、测试与 CI 配置。排除
node_modules/、vendor/、deliverables/、www/dist/、dist-test-ssg-render/等依赖、生成物和报告产物。当前工作树仅发现未跟踪目录dist-test-ssg-render/。验证命令 / Verification:
deno task fmt:check:通过,184 files checked。deno task lint:通过,183 files checked。deno task typecheck:通过。deno audit:通过,No known vulnerabilities found。deno task test:通过,493 passed / 0 failed。deno task build:通过,生成 298 HTML 页面,客户端 island JS 总量 175 KB。deno task test:e2e:通过,92 passed。1. 项目概况
deno.jsonpackages/app/src/index.ts:52packages/core/src/index.ts:20packages/adapter-vite/src/index.ts:225www/vite.config.ts:12packages/约 122 文件 / 21,575 行;www/约 60 文件 / 10,223 行;functions/1 文件 / 60 行。@lessjs/adapter-vite三阶段构建;测试使用 Deno test 和 Playwright。English:
2. 严重问题(必须立即修复)
问题1:package island 元数据可进入生成 JS,但没有做字符串安全生成和严格校验。
packages/adapter-vite/src/entry-generators.ts:26-28,packages/adapter-vite/src/route-scanner.ts:295-303tagName和modulePath被直接拼进生成代码:'${i.tagName}': () => import('${i.modulePath}')。scanPackageIslands()只检查字段存在,没有校验自定义元素名、模块路径、控制字符、引号或换行。islands元数据破坏生成代码,严重时造成构建期或客户端代码注入。JSON.stringify()生成所有 JS 字面量;新增validatePackageIslandMeta(),校验tagName必须符合 Custom Element name 规则,modulePath必须是合法 bare specifier / relative URL,禁止引号、换行、控制字符和协议型危险输入;为恶意tagName/modulePath添加单元测试。问题2:PWA service worker 会拦截并缓存同源非静态请求,API 响应可能被缓存。
packages/adapter-vite/src/cli/ssg-render.ts:493-519/api/只是影响isAsset判断,仍会进入networkFirst(),并在res.ok时写入 Cache Storage。if (e.request.method !== 'GET') return;;对/api/、/rpc/、认证路径直接return;只缓存document、script、style、image等明确允许的资源;为/api/status、POST 请求、带Authorization请求添加 e2e。问题3:构建产物测试实际检查了错误目录,并且缺失时静默跳过。
www/__tests__/build-output.test.ts:13,www/__tests__/build-output.test.ts:17,www/__tests__/build-output.test.ts:30DIST = join(import.meta.dirname, '..', '..', 'dist')指向仓库根目录dist/,但真实构建输出是www/dist/。目录不存在时测试直接return,导致“通过”但没有检查任何产物。no Hono virtual entry和client island JS < 200KB两个关键产物约束在单测中是 false positive。发布前可能漏掉大 bundle 或 SSR 内部入口泄漏。join(import.meta.dirname ?? '.', '..', 'dist');如果www/dist不存在应throw,不要跳过;在 CI 中保证该测试运行前执行deno task build。3. 高危问题(建议尽快修复)
问题1:大量测试把布尔断言写成
assertExists(boolean),会让false也通过。packages/create/__tests__/cli.test.ts:71-101,packages/adapter-vite/__tests__/entry-generators.test.ts:5-94,packages/adapter-vite/__tests__/build-manifest.test.ts:52-56assertExists(false)不会失败,它只检查值不是null/undefined。packages/create/__tests__/cli.test.ts:94-101仍检查旧版本片段,但即使条件为 false 也会通过。assert(...)或assertEquals(condition, true);为全仓添加 lint 脚本扫描assertExists(.*includes|assertExists(.*>|assertExists(.*===)。assertExists()for boolean expressions, so false conditions pass. Replace withassert()orassertEquals().问题2:package island 扫描会在构建期执行包入口代码。
packages/adapter-vite/src/route-scanner.ts:274-284scanPackageIslands()通过动态import(pkg)读取islands数组。less add,安装包的任意顶层代码会在构建期执行,扩大供应链攻击面。custom-elements.json或lessjs.manifest.json;仅在显式trustedPackageCode: true时允许执行包入口;manifest 必须走 JSON schema 验证。问题3:
api-consumer的 AbortController 断开后不会重建,组件重连会一直失败。www/app/islands/api-consumer.ts:14,www/app/islands/api-consumer.ts:226-240,www/app/islands/api-consumer.ts:251-268_abortController在字段初始化时只创建一次,disconnectedCallback()调用abort()后,后续重连仍复用已 aborted signal。AbortController;在 catch 中忽略AbortError;connectedCallback()中如果signal.aborted则重建 controller。问题4:TOC 对中文标题生成空 id,中文文档锚点可能失效。
www/app/islands/less-toc.ts:99-108,www/app/islands/less-toc.ts:163-168replace(/[^a-z0-9]+/g, '-')只保留英文数字。中文标题会得到空字符串,第一个标题 id 可能为空,后续变成-1。#或错误锚点,影响真实用户阅读。text.normalize('NFKD').toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, '-');若结果为空,回退到section-${index};加中文标题单测/e2e。问题5:无 JS 或本地脚本失败时,anti-flash 可能让整页一直隐藏。
www/vite.config.ts:109-110,www/public/theme-init.js:21-23<style id="less-anti-flash">html{visibility:hidden}</style>,只依赖theme-init.js删除。<noscript><style>html{visibility:visible}</style></noscript>;或用 CSS 默认主题避免隐藏整页。问题6:严格 CSP 下,样式加载优化使用 inline
onload会失效。www/vite.config.ts:39-48,packages/adapter-vite/src/index.ts:311-318,packages/core/src/html-escape.ts:100-123onload="this.media='all'"。由于 structured injection 会设置allowHeadExtrasScripts = true,运行时不会剥离on*事件属性。script-src 'self'且不允许 inline handler,CSS media 切换不会执行;如果未来开放用户配置 attrs,也会形成 XSS 边界。inject.stylesheets[].attrs中的on*属性;用普通 stylesheet、preload+ 安全 JS 模块,或由 framework 生成受控模式;补 CSP e2e。onloadattributes conflict with strict CSP and should not be accepted through generic attrs.问题7:Cloudflare/Deno Deploy workflow 指向不存在的
demo/目录。.github/workflows/deploy-api.yml:7-8,.github/workflows/deploy-api.yml:20-23demo/,但当前仓库没有该目录,实际 API 在functions/api/term.ts。functions/**,并加一次 dry-run 验证。demo/folder. It is stale and will fail.4. 一般问题(优化项)
问题1:
PackageIslandMeta协议过薄,支撑不了 registry hub、自动注册、自动渲染、自动水合。packages/core/src/types.ts:11-19tagName/modulePath/strategy,缺少 export 名、SSR renderability、hydrate events、slots、parts、states、diagnostics、bundle cost、a11y 信息。LessComponentManifest或 CEM-compatible 扩展;先做less validate-manifest,再做less add。问题2:root formatter 明确排除了路由和博客源码,真实页面代码缺少格式化保护。
deno.json:89-90,www/app/routes/blog/[slug].ts:1,www/app/routes/decisions/[slug].ts:217-218www/app/routes/和www/content/blog/被fmt/fmt:check排除;部分路由还有deno-fmt-ignore-file,并出现 import 放在文件底部的情况。deno fmt --check;底部 import 移到文件顶部。问题3:pre-commit hook 覆盖范围小于 CI。
.githooks/pre-commit:11-24packages/,typecheck 只覆盖 core/rpc/ui/adapter-lit/signals/create,遗漏adapter-vite、app、content、i18n、www。deno task fmt:check && deno task lint && deno task typecheck;或至少同步 roottypecheckentrypoints。问题4:
prism-init.js在 Prism 不存在时无限重试。www/public/prism-init.js:9-12setTimeout(init, 50),没有最大次数或停止条件。问题5:demo 组件默认请求外部 API。
packages/ui/src/less-hero-ping.ts:107-129https://less-demo-api.sisyphuszheng.deno.net/api。api-url时启用;或默认使用相对路径并在 docs 中明确说明。问题6:终端 demo 文案硬编码测试数量,已经与真实结果不一致。
www/app/shared/term-commands.ts:20,www/app/shared/term-commands.ts:35VERSION和tests 475 passing为手写常量,当前真实测试结果是 493 passed。5. 性能优化建议
渲染性能:
packages/core/src/types.ts:416-445,这是优势。打包体积:
packages/adapter-vite/src/entry-generators.ts:102-113。document.querySelector(tag)命中时才 import;中期做 route-level island manifest。请求/资源:
www/vite.config.ts:55-98注入多个 CDN Prism 脚本和 GoatCounter;已有 SRI 和 crossorigin,安全性较好。packages/ui/src/less-hero-ping.ts:128-129默认外部请求应改为 opt-in。运行时:
www/public/prism-init.js:9-12无限重试需封顶。www/app/islands/less-search.ts:174-199搜索 index 加载失败时静默重置,可增加一次性错误状态,避免用户以为搜索无结果。packages/adapter-vite/src/cli/ssg-render.ts:493-519service worker 应减少拦截范围。6. 安全风险清单
XSS:
packages/content/src/blog/markdown.ts:101-110;终端命令 escape:www/app/shared/term-commands.ts:10-17;headExtras默认剥离 script/on*:packages/core/src/html-escape.ts:100-123。packages/adapter-vite/src/entry-generators.ts:26-28;renderDSD()的sourceInfo拼成属性时未 escape:packages/core/src/render-dsd.ts:116-119,并输出到packages/core/src/render-dsd.ts:271、packages/core/src/render-dsd.ts:285;unsafeHTML(post.html)依赖上游 sanitize:www/app/routes/blog/[slug].ts:69-90,www/app/routes/decisions/[slug].ts:206-218。JSON.stringify、escapeAttr、schema validation;trustedHtml必须在文档中标为危险开关。敏感信息:
www/vite.config.ts:95-98,demo APIpackages/ui/src/less-hero-ping.ts:128,CDN 脚本www/vite.config.ts:55-91。依赖漏洞:
deno audit当前无已知漏洞。deno.json:39-59,关键版本包括 Lit 3、Hono 4、Vite 8.0.10、Playwright 1.59.1、sanitize-html 2.17.4。deno audit保留在 CI:.github/workflows/test.yml:28-43。deno audit; keep audit in CI.配置风险:
packages/adapter-vite/src/cli/ssg-render.ts:493-519。packages/create/deno.json:5使用deno run -A cli.ts,本地任务权限过宽。-A:deno.json:85,可以接受但应限制在测试环境。7. 代码规范与可维护性
命名:
@lessjs/core、adapter-vite、adapter-lit、content、i18n、ui、app分层合理。PackageIslandMeta命名准确,但协议字段不足:packages/core/src/types.ts:11-19。注释:
packages/core/src/html-escape.ts:100-123。结构:
packages/app/src/index.ts:52-74通过共享LessBuildContext串联 core/content/i18n,结构清晰。adapter-vite仍承担 route scan、entry generation、SSG、PWA、CSP、build manifest 等多职责,后续 registry/renderer kernel 应拆出 manifest/validation 子模块。重复代码:
www/app/shared/term-commands.ts:1-8,这是正向改进。assertExists(boolean)多处出现,应批量修复。8. 构建/依赖风险
依赖冲突:
deno task typecheck、deno task build、deno task test:e2e均通过,未发现实际依赖冲突。jsr:@lessjs/*@^0.14.8,包版本为0.14.11,语义上可解析到同一 minor,但发布时仍建议统一自动更新。版本不兼容:
packages/create/__tests__/cli.test.ts:94-101的旧版本片段说明脚手架测试仍有历史遗留。buildTemplates()的输入 fake version 断言,而不是写死旧版本。打包异常点:
www/__tests__/build-output.test.ts:13-30当前没有检查真实www/dist。环境配置问题:
.github/workflows/deploy-api.yml:20-23指向不存在的demo/。.githooks/pre-commit:11-24本地校验范围低于 CI。deno.json:89-90排除了大量 route 源码格式化。9. 总体评分(1-10)
English:
评分理由:当前工程验证非常强,fmt/lint/typecheck/audit/test/build/e2e 全部通过;核心架构方向清晰,DSD/island/build 分层有实际代码支撑。扣分主要来自 registry/一键安装方向的供应链边界尚未收紧、service worker 缓存策略过宽、若干测试是假阳性、route 格式化和本地 hook 覆盖不足。
10. 最终修复优先级清单(TOP 10)
entry-generators.ts:26-28改用JSON.stringify,route-scanner.ts:295-303增加 schema validation。/api/、认证请求,只缓存明确静态资源。www/__tests__/build-output.test.ts:13-30的 dist 路径和静默跳过。assertExists(boolean)为assert()/assertEquals()。api-consumerAbortController 重连失败问题。less-toc中文标题 slug 生成,增加中文 TOC 测试。.github/workflows/deploy-api.yml中不存在的demo/部署路径。deno.jsonformatter 排除范围,并让.githooks/pre-commit调用 root 级fmt:check/lint/typecheck。English TOP 10:
www/distand fail when missing.assertExists()usages with real boolean assertions.api-consumerafter reconnect.less-toc.demo/deploy workflow.