- 可观测性
【免费下载链接】sentry-javascript
Official Sentry SDKs for JavaScript
本篇指南以 sentry-javascript 仓库中 solid-static 测试应用 为核心,讲清这个纯静态部署的 Solid 单页应用如何在端到端(E2E)测试体系中被构建、被注入本地构建的 Sentry SDK、以及如何通过 Playwright + 事件代理服务器验证错误捕获、错误边界与页面加载事务(pageload transaction)的完整链路。读完本文,你将掌握:该模板的可用脚本与部署方式、Sentry.init中每个参数的作用(尤其是traceLifecycle: 'static'与tunnel代理)、以及如何在仓库内实际运行这个 E2E 应用并理解其测试断言原理。
一、solid-static 在仓库中的定位
solid-static 位于dev-packages/e2e-tests/test-applications/目录下,是 sentry-javascript 单体仓库 E2E 测试体系中的一员。需要先明确它的定位:根据 E2E 测试总 README 的警告说明,这些测试应用不是用来当示例项目或模板的,它们可能包含用于向后兼容测试的过期依赖版本、甚至有意保留的已知安全漏洞。它的真正目的是"验证本仓库各包如同已发布状态下的实际行为"(verify the behavior of the packages in this repository as if they were to be published)。
具体到 solid-static,它依赖的是@sentry/solid(官方 Solid 平台 SDK,见 packages/solid),用于在真实浏览器环境中验证:
- 未捕获异常(uncaught error)能否被全局 handler 捕获并上报;
- Solid 错误边界(ErrorBoundary)配合
withSentryErrorBoundary的受控捕获(handled error)是否带上正确的 mechanism; - 页面加载事务(pageload transaction)的
op、origin、事务名等字段是否符合预期。
二、模板特性与可用脚本(README 核心内容)
模板 README 说明了该应用的三个要点,本文按 README 原脉络逐一展开并结合源码补充。
2.1 模板目标:展示 Solid 的路由能力
README 指出,该模板的目标是展示 Solid 的路由(routing)功能,并展示路由与 Suspense 如何协作、通过.data.ts模式将数据获取与路由并行化(这一模式属于 Solid 生态@solidjs/router的路由数据加载范式)。
对照当前快照的源码可以看到其路由组织方式:routes.ts 定义了四条路由,其中参数化路由/user/:id与 404 兜底路由**均采用lazy(() => import(...))懒加载,配合 Solid 的 Suspense 实现按路由切分的代码分割:
export const routes = [ { path: '/', component: Home }, { path: '/user/:id', component: lazy(() => import('./pages/user')) }, { path: '/error-boundary-example', component: ErrorBoundaryExample }, { path: '**', component: lazy(() => import('./errors/404')) }, ];导航骨架由 pageroot.tsx 提供,使用@solidjs/router的<A>组件渲染 Home / Error Boundary Example / Error 三个导航入口。
2.2 依赖管理与安装方式
README 明确说明:模板依赖通过 pnpm 维护(pnpm up -Lri全链路升级),仓库中能看到pnpm-lock.yaml即源于此;不过任何包管理器都可用,克隆模板后该锁文件可以安全删除。基本安装命令:
npm install # 或 pnpm install 或 yarn install查看 package.json 可以印证依赖构成:运行时依赖只有solid-js@^1.8.18和@sentry/solid;开发依赖包括vite@^5.4.11、vite-plugin-solid、tailwindcss、solid-devtools、PostCSS 工具链以及测试用的@playwright/test@~1.63.0。值得注意的是 SDK 的引入方式:
"dependencies": { "solid-js": "^1.8.18", "@sentry/solid": "file:../../packed/sentry-solid-packed.tgz" }SDK 不是从 npm registry 拉取,而是指向dev-packages/e2e-tests/packed/下的本地打包 tarball(见 E2E README 的 "How they work":仓库会把各包构建成 tarball 并注入 pnpm overrides,使测试应用"如同已发布"地安装本地构建产物)。这正是该应用与真实业务项目最关键的差异,也是运行前必须先执行yarn build:tarball的原因。
2.3 可用脚本
| 脚本 | 等价命令 | 作用 |
|---|---|---|
npm run dev/npm start | vite | 开发模式启动,热更新,打开 http://localhost:3000 查看(README 描述) |
npm run build | vite build | 生产构建到dist目录,production 模式打包、压缩、文件名带 hash |
npm run preview | vite preview | 本地预览构建产物(Playwright 测试即依赖它,见下文) |
pnpm test:prod | TEST_ENV=production playwright test | 在生产构建上跑 Playwright 断言 |
pnpm test:build | pnpm install && pnpm build | E2E 框架约定的构建阶段入口 |
pnpm test:assert | pnpm test:prod | E2E 框架约定的断言阶段入口 |
pnpm clean | npx rimraf node_modules pnpm-lock.yaml dist | 清理本应用产物 |
其中test:build/test:assert是 E2E 测试框架对每个测试应用的强制约定(E2E README 要求新建测试应用必须提供这两个命令)。
构建行为由 vite.config.ts 决定:启用vite-plugin-solid、构建目标esnext,并且设置了envPrefix: 'PUBLIC_'—— 这意味着只有PUBLIC_前缀的环境变量才会通过import.meta.env暴露给应用代码,下一节的PUBLIC_E2E_TEST_DSN正依赖这一配置才能被注入。
三、SDK 初始化配置逐项解析
应用的入口 src/index.tsx 展示了@sentry/solid的完整初始化配置(L7-L16):
Sentry.init({ traceLifecycle: 'static', dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, debug: true, environment: 'qa', // dynamic sampling bias to keep transactions integrations: [Sentry.browserTracingIntegration()], release: 'e2e-test', tunnel: 'http://localhost:3031/', // proxy server tracesSampleRate: 1.0, }); render(() => <App />, document.getElementById('root'));各参数在本测试场景中的作用:
traceLifecycle: 'static':选择"静态 span 生命周期"模式。从源码结构看,client.ts 中,任何非'static'的取值都会归一化为默认值'stream'(span streaming);当为'static'时,span 在结束前不会流式上报,且 spanStreaming 集成 会直接跳过初始化。若你在static模式下配置了beforeSendSpan,还需用Sentry.withStaticSpan包裹回调,否则客户端会在 client.ts 中做一致性校验并提示。dsn: import.meta.env.PUBLIC_E2E_TEST_DSN:DSN 不硬编码,而是由 E2E 测试基础设施通过环境变量注入(.env中配置,经 Vite 的PUBLIC_前缀规则暴露到浏览器端)。tunnel: 'http://localhost:3031/':事件不直接发到 Sentry,而是发往本地事件代理服务器(event proxy)。该代理由 start-event-proxy.mjs 启动,内部调用@sentry-internal/test-utils的startEventProxyServer({ port: 3031, proxyServerName: 'solid-static' })。Playwright 测试正是通过这个代理"拦截"并断言 SDK 实际发出的事件,而不是依赖真实 Sentry 项目。environment: 'qa':配合注释 "dynamic sampling bias to keep transactions",即利用 Sentry 的动态采样规则让qa环境的 transaction 更容易被保留,避免测试事务被采样丢弃。release: 'e2e-test'、debug: true:统一的发布标识便于在代理端区分事件来源;debug: true打开 SDK 日志,也符合 E2E README 排障章节的第一条调试建议。tracesSampleRate: 1.0+browserTracingIntegration():100% 采样所有浏览器事务,确保 pageload/navigation 事务必然产生。
四、应用层:两种错误路径与路由结构
sr c/app.tsx 是该应用的核心"测试桩",它构造了两条互不相同的错误路径:
- 未捕获错误:
#errorBtn按钮的onClick直接throw new Error('Error thrown from Solid E2E test app'),不经过任何本地处理,交由浏览器全局 handler(window.onerror)捕获,验证 SDK 的auto.browser.global_handlers.onerror机制。 - 受控错误 + Sentry 错误边界:
#caughtErrorBtn触发后渲染一个在onMount中抛错的组件,被外层SentryErrorBoundary捕获。该边界由Sentry.withSentryErrorBoundary(ErrorBoundary)包装 Solid 原生的ErrorBoundary而成(实现见 packages/solid/src/errorboundary.ts),其fallback渲染错误信息与 Reset 按钮,点击后setCount(count() + 1)使错误消息自增并调用reset()恢复子树——这正是"捕获第二次异常"测试的基础。
导航壳 pageroot.tsx 使用 Tailwind 类名组织了一个包含 Home / Error Boundary Example / Error 链接的nav,/error链接会命中**通配路由渲染 404 页,用于覆盖路由参数化场景。
五、Playwright 测试如何验证 SDK 行为
playwright.config.mjs 使用@sentry-internal/test-utils的getPlaywrightConfig({ startCommand: 'pnpm preview --port 3030', port: 3030 })生成配置。从 dev-packages/test-utils/src/playwright-config.ts 的源码结构看,当传入startCommand时,配置会在webServer中追加以该命令启动的服务器项——即测试运行前 Playwright 会先pnpm preview --port 3030把生产构建(dist)挂起来,应用跑在 3030 端口,事件代理跑在 3031 端口(对应tunnel配置)。
tests 目录下有三个测试文件,分别验证上面三件事:
5.1 错误上报(errors.test.ts)
tests/errors.test.ts 通过waitForError('solid-static', ...)订阅代理端事件流,点击#errorBtn后断言事件对象:
expect(error).toMatchObject({ exception: { values: [{ type: 'Error', value: 'Error thrown from Solid E2E test app', mechanism: { type: 'auto.browser.global_handlers.onerror', handled: false, }, }], }, transaction: '/', });断言覆盖了三个维度:错误类型与消息、mechanism 标记其为未处理(handled: false)且来自全局 onerror handler、以及事件携带的关联事务名/。
5.2 Sentry 错误边界(errorboundary.test.ts)
tests/errorboundary.test.ts 包含两个用例:
- 点击
#caughtErrorBtn后,断言捕获的事件 mechanism 为auto.function.solid.error_boundary且handled: true,错误消息为Error 1 thrown from Sentry ErrorBoundary in Solid E2E test app——证明错误被边界受控处理,并与 SDK 的 mechanism 标记体系一致; - 随后点击 Reset 按钮再次触发,断言第二条事件消息为
Error 2 ...,验证reset()恢复后边界仍可继续捕获新错误(对应 app.tsx 中count自增的设计)。
5.3 页面加载事务(performance.test.ts)
tests/performance.test.ts 用waitForTransaction('solid-static', ...)等待代理端收到事务事件,page.goto('/')后断言:
expect(pageloadTransaction).toMatchObject({ contexts: { trace: { op: 'pageload', origin: 'auto.pageload.browser', }, }, transaction: '/', transaction_info: { source: 'url' }, });这验证了browserTracingIntegration在纯客户端路由的静态 SPA 上正确生成了pageload事务,且事务名是原始 URL(source: 'url'表示名称来源于原始 URL 而非服务端约定名)。
六、构建、运行与部署
6.1 在仓库内运行该 E2E 应用
按照 E2E README 的标准流程:
- 复制
.env.example为.env(PUBLIC_E2E_TEST_DSN等变量由此注入;纯本地断言不需要真实 Sentry 凭证,因为事件走本地代理); - 在仓库根目录执行
yarn build:tarball,把packages/下各 SDK 打成 tarball 并建立packed/软链(packages/有任何改动后都必须重跑); - 只运行本应用:
yarn test:run solid-static框架会依次调用本应用package.json中的test:build(安装依赖 + 生产构建)与test:assert(TEST_ENV=production playwright test)。也可以交互式地用仓库提供的 Makefile(需fzf):make list列出全部测试应用,make run打开模糊搜索菜单选择运行。CI 侧则由dev-packages/e2e-tests/lib/getTestMatrix.mjs生成测试矩阵,且基于 nx affected projects 按依赖变更自动裁剪——只有依赖链上的 SDK 包有改动时,solid-static 才会被触发。
6.2 作为普通项目使用(README 的部署说明)
若剥离 E2E 基础设施、把该模板当作普通 Solid 项目使用,README 给出的路径是:
npm run dev # 开发模式,http://localhost:3000,编辑即刷新 npm run build # 生产构建输出到 dist(压缩、文件名含 hash)"Deployment" 一节的结论是:dist文件夹可部署到任意静态托管服务(README 列举了 netlify、surge、now 等)。这与应用形态自洽——纯客户端渲染、无服务端数据获取(.data.ts模式在本静态快照中未启用),路由切换全部发生在浏览器内,因此对静态托管零要求。
6.3 本地手动调试组合
理解两个端口即可手动复现测试环境:pnpm build && pnpm preview --port 3030启动应用;同时运行 start-event-proxy.mjs(如node start-event-proxy.mjs)在 3031 端口起事件代理;配合Sentry.init中的debug: true,浏览器控制台会输出 SDK 完整日志,代理端则能看到 SDK 实际发出的原始事件,逐字段对照测试断言。
七、小结
solid-static 是一个麻雀虽小五脏俱全的 E2E 测试应用:README 交代了模板的安装、脚本与静态部署方式;package.json 与 tarball 机制保证它测试的是"即将发布"的@sentry/solid;index.tsx 的traceLifecycle: 'static'+tunnel+ 1.0 采样率构成了一套可完全本地观测的埋点环境;app.tsx 与 routes.ts 提供受控/未受控两条错误路径和懒加载路由;三个 Playwright 测试文件则把错误 mechanism、错误边界行为与 pageload 事务字段逐条钉死。它示范的"本地 tarball + 事件代理 + 生产构建 + Playwright 断言"套路,是理解整个 sentry-javascript E2E 体系的最好切入口。
- 可观测性
【免费下载链接】sentry-javascript
Official Sentry SDKs for JavaScript
相关推荐
TanStack Start(Solid)静态预渲染(Static Prerendering)完全指南
TanStack Start(Solid)静态预渲染(Static Prerendering)完全指南 静态预渲染(Static Prerendering)是
前端路由SSRTanStack Solid Start 可观测性实战指南:Sentry 集成、内置监控模式与 OpenTelemetry
TanStack Solid Start 可观测性实战指南:Sentry 集成、内置监控模式与 OpenTelemetry 可观测性(Observability
前端路由SSRTanStack Solid Router 与 Solid Query 的 SSR 流式查询集成:solid-router-ssr-query 实战指南
TanStack Solid Router 与 Solid Query 的 SSR 流式查询集成:solid router ssr query 实战指南 @ta
前端路由SSR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考