@arms/rum-browser-vue
v0.1.1
Published
Vue plugin for @arms/rum-browser SDK (Vue 2/3 error capture + vue-router view tracking + useRum)
Readme
@arms/rum-browser-vue
Vue 插件 for @arms/rum-browser RUM SDK —— 同时支持 Vue 2.x + Vue 3.x(vue-router v3 / v4)。
能力范围:
- Vue 异常捕获:接管
errorHandler(链式保留原 handler),自动上报source: 'vue'的异常事件(含snapshotsJSON 快照,内部携带component_stack/component_name/lifecycle_hook/handling) - 路由视图追踪:传入
router实例后,经router.afterEach驱动Shell.startView(手动 view 模式),view.name 收敛为路由模板(如/user/:id),popstate / 首屏 / 懒加载时序问题根治 - useRum / $rum:Vue 3 提供
useRum()Composition hook,两端均提供this.$rum与getRum()单例
不含组件性能监控(列入后续演进)。
安装
本插件不独立工作 —— 需与主包 @arms/rum-browser(必需 peer dependency)同时安装,并完成主包初始化(见「Vue 3 接入 / Vue 2 接入」):
npm install @arms/rum-browser @arms/rum-browser-vue版本可用性:上游依赖 @arms/[email protected] 与 @arms/[email protected] 均已在 npm registry 发布,本包 peerDependencies 下限与 registry 实际产物对齐,外部安装可正常解析(版本约束与发布顺序说明见下文「发布前置条件」)。
发布前置条件
发布顺序(严格按序,前一步发版在 registry 生效后,再发布下一步):
@arms/rum-core@>=0.1.11:含Shell.startView与IConfiguration.trackViewsManually能力的发版@arms/rum-browser@>=0.1.16:含 PvCollector 手动模式防护(trackViewsManually早退,避免双发 PV)的发版@arms/rum-browser-vue(本包)
上游发版状态(peer 下限已与 registry 对齐):
@arms/[email protected]与@arms/[email protected]已在 npm registry 发布,本包 peerDependencies(@arms/rum-core >=0.1.11、@arms/rum-browser >=0.1.16)可正常解析,外部项目npm install @arms/rum-browser-vue不再出现早期的 ERESOLVE 失败(该下限曾为有意占位:安装失败优于运行期缺Shell.startView能力而损坏,现已解除)- 后续版本迭代仍需遵循上述发布顺序(依赖包发版在 registry 生效后,再发布本包),保证 peer 下限始终对应 registry 上具备所需能力的真实产物
- 仓库内开发期经 workspace 直链源码使用(无需等待发版),安装依赖请遵循仓库惯例使用
yarn或scripts/bootstrap.sh
版本要求
| 依赖 | 版本要求 | 说明 |
| ------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| @arms/rum-core | >=0.1.11 | 含 Shell.startView 与 IConfiguration.trackViewsManually 的发版(已发布;发布顺序与下限校准见上方「发布前置条件」) |
| @arms/rum-browser | >=0.1.16 | 含 PvCollector 手动模式防护(trackViewsManually 早退)的发版(已发布) |
| vue | 2 \|\| 3 | — |
| vue-router | 3 \|\| 4 | optional,不接入路由时可省略(此时仅启用异常捕获与 $rum,view 仍由 SDK 自动采集) |
开发期在 monorepo 内通过 workspace 直链源码使用,无需等待发版。
Vue 3 接入
// main.ts
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import ArmsRum from '@arms/rum-browser';
import { ArmsRumVue } from '@arms/rum-browser-vue/vue3';
import App from './App.vue';
import { routes } from './router';
var app = createApp(App);
var router = createRouter({ history: createWebHistory(), routes: routes });
ArmsRum.init({
endpoint: 'https://your-endpoint',
});
// 插件接入不再依赖 init 完成,可在 init 前后任意时序同步调用
app.use(ArmsRumVue, { rum: ArmsRum, router: router });
app.mount('#app');时序说明:插件接入(
Vue.use(ArmsRumVue, ...))不再依赖主包 init 完成,可在 init 前后任意时序同步调用;init 与插件接入的先后顺序可互换,两者等价安全。路由首次导航会被内部 pending 机制暂存、init 完成后补发(loading_type: 'initial_load'),首屏不丢失。注意:init 完成前触发的错误与自定义事件不会被采集(默认配置下 init 几乎瞬间完成;但 Vue2 等同步渲染框架的首屏渲染期错误可能落入此窗口)。若需捕获首屏渲染期错误,可将应用挂载(mount)置于 init 完成后(仅 mount 时序保留.then/await,插件接入不再需要)。
useRum(Composition API)
<script setup lang="ts">
import { useRum } from '@arms/rum-browser-vue/vue3';
var rum = useRum();
function onCheckout() {
try {
submitOrder();
rum.sendCustom({ type: 'biz', name: 'checkout_click', value: 1 });
} catch (e) {
rum.addVueError(e);
}
}
</script>
<template>
<button @click="onCheckout">结算</button>
</template>Options API 组件可直接使用 this.$rum(install 时自动挂载到 app.config.globalProperties)。
Vue 2 接入
// main.ts
import Vue from 'vue';
import VueRouter from 'vue-router';
import ArmsRum from '@arms/rum-browser';
import { ArmsRumVue } from '@arms/rum-browser-vue/vue2';
Vue.use(VueRouter);
var router = new VueRouter({ routes: routes });
ArmsRum.init({
endpoint: 'https://your-endpoint',
});
// 插件接入不再依赖 init 完成,可在 init 前后任意时序同步调用
Vue.use(ArmsRumVue, { rum: ArmsRum, router: router });
new Vue({
router: router,
render: function (h) {
return h(App);
},
}).$mount('#app');Vue 2 无 Composition API,不提供 useRum:组件内使用 this.$rum(install 时自动挂载到 Vue.prototype),或从入口导入单例:
import { getRum } from '@arms/rum-browser-vue/vue2';
getRum().sendCustom({ type: 'biz', name: 'checkout_click', value: 1 });路由追踪说明
警告:传入
router后 view/PV 完全由afterEach驱动,主包自动 PV 被禁用插件在
vueCollector.setup中注入trackViewsManually: true:主包 PvCollector 跳过首屏 PV 与 history 拦截(避免双发),view 的创建、命名、计时完全依赖router.afterEach驱动(内部调用shell.startView)。这意味着 view 上报以传入的 router 实例真实承载应用导航为前提 —— 若传入的 router 从未完成导航(如仅创建未挂载到应用),view 将不会上报(无报错、无告警)。不传
router则不注入手动 view 模式,主包 PvCollector 保留自动 PV(URL path 命名),仅启用异常捕获与$rum能力 —— 无路由追踪诉求时请勿传入router。
传入 router 后,插件内部:
- 在
vueCollector.setup中注入trackViewsManually: true(禁用 PvCollector 自动 PV,避免双发) - 挂载
router.afterEach,导航成功后调用shell.startView(viewName, { url, loading_type }) - view.name 按
to.matched末段路由模板计算(嵌套拼接),动态段:param原样保留;catch-all(v4/:pathMatch(.*)*、v3*)展开为实际访问路径 - 导航失败(v4 afterEach 第三参
failure)与 query-only 变化不计为新视图;同路径重复导航由Shell.startView同名去重 loading_type:ctx 已有 view 时为route_change,否则initial_load
// 访问 /user/123 时上报的 view 事件:
// { event_type: 'view', type: 'pv', name: '/user/:id', loading_type: 'initial_load', ... }不传 router 时不会注入手动 view 模式,view 仍由 SDK 自动采集(URL path 命名)。
异常捕获说明
install 时接管 errorHandler 并链式保留原 handler:先经 addVueError 上报,再调用你已有的 handler(未设置时保持 Vue 默认的 console.error 可见性,不会吞错)。
上报字段:
{
event_type: 'exception',
type: 'error',
source: 'vue',
name: 'TypeError', // error.name(非 Error 值自动 normalize)
message: "Cannot read properties of undefined",
stack: '...',
// 扩展信息收敛为单一 JSON 字符串字段(值为 undefined 的内部键不会出现)
snapshots: JSON.stringify({
component_stack: 'at <OrderList>\nat <UserPage>', // 当前组件在前,沿父链向上
component_name: 'OrderList',
lifecycle_hook: 'hook:mounted', // Vue errorHandler 的 info 参数
handling: 'handled',
}),
times: 1,
}也可在自定义 errorHandler 中手动上报(插件已接管时无需重复调用):
import { addVueError } from '@arms/rum-browser-vue';
app.config.errorHandler = function (err, instance, info) {
addVueError(err, { lifecycle_hook: info });
};API
主入口 @arms/rum-browser-vue
| 导出 | 说明 |
| -------------------------------------------------------- | --------------------------------------------------------------------------------- |
| addVueError(error: unknown, context?: VueErrorContext) | 手动上报 Vue 异常(component_stack / component_name / lifecycle_hook 可选) |
| getRum(): VueRumApi | RUM API 单例(addVueError / sendCustom / sendEvent / getConfig) |
子入口 @arms/rum-browser-vue/vue3
在主入口基础上增加:
| 导出 | 说明 |
| --------------------- | --------------------------------------------------- |
| ArmsRumVue | Vue 3 插件:app.use(ArmsRumVue, { rum, router? }) |
| useRum(): VueRumApi | Composition hook,返回与 this.$rum 相同的单例 |
子入口 @arms/rum-browser-vue/vue2
在主入口基础上增加:
| 导出 | 说明 |
| ------------ | ---------------------------------------------------------------------------- |
| ArmsRumVue | Vue 2 插件:Vue.use(ArmsRumVue, { rum, router? }),组件内 this.$rum 可用 |
VuePluginOptions
app.use(ArmsRumVue, options) / Vue.use(ArmsRumVue, options) 的第二参数(源 src/types/index.ts):
| 字段 | 类型 | 必填 | 说明 |
| -------- | ----------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| rum | Shell | 是 | 主 SDK 实例(@arms/rum-browser 默认导出的 armsRum,或任意 Shell 子类实例)。可在 armsRum.init() 前后任意时序同步传入;反向时序经 pending 队列兜底同样安全 |
| router | AnyRouter | 否 | vue-router 实例(v3 VueRouter / v4 Router 均可,仅依赖 afterEach 最小接口)。传入后启用路由视图追踪(注入手动 view 模式,经 afterEach 驱动 startView);不传则仅启用异常捕获与 $rum,view 由 SDK 自动采集 |
getRum()
返回 VueRumApi 单例,包含 addVueError / sendCustom / sendEvent / getConfig 四个方法。Vue 3 的 useRum()、组件内 this.$rum(Vue 3 挂载于 app.config.globalProperties、Vue 2 挂载于 Vue.prototype)与 getRum() 返回同一实例 —— API 本身无状态,仅持有模块级 shell 引用,插件未初始化时各方法安全降级(打印告警并跳过,不抛错)。
兼容性
Vue / vue-router 版本
| 依赖 | 支持版本 | 说明 |
| ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Vue 3 | 3.x | ./vue3 子入口:app.use(ArmsRumVue, ...) + useRum() + this.$rum |
| Vue 2.7 | 2.7 | ./vue2 子入口(examples 有 2.7.16 + vue-router 3.6.5 实测冒烟工程) |
| Vue 2.6 | 2.6 | ./vue2 子入口。无 Composition API 不影响本插件 —— vue2 入口本就不提供 useRum,组件内用 this.$rum 或导入 getRum() 单例 |
| @vue/composition-api | 不支持 | Vue 2 + composition-api 插件场景请使用 ./vue2 入口 + getRum()(不提供经该插件的 useRum 形态) |
| vue-router | 3 \| 4 | optional;插件仅依赖 afterEach 最小接口(AnyRouter),不包装 createRouter、不替换任何 import |
打包器与消费形态
| 环境 | 支持情况 | 说明 |
| --------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Vite / webpack 5 等 | ✅ | 经 exports 字段解析 ./vue2 / ./vue3 子入口(types/import/require/default 四条件) |
| webpack 4 | ✅ 存根兜底 | webpack 4 不识别 exports 字段,包根提供 vue2.js / vue3.js 同名 CJS 存根(含于 files),旧构建链可直接 require('@arms/rum-browser-vue/vue2') 解析;同时配对提供根级 vue2.d.ts / vue3.d.ts 类型存根(export * 转发 es/entries/ 入口全部具名导出,含于 files),moduleResolution: "node"(经典模式)的 TS 工程亦有完整类型,子路径 API 不回落 any |
| CDN / <script> 标签 | ❌ 不适用 | 本包不出 UMD dist 产物,仅经 bundler 消费 —— 与主包 CDN 全局模式互斥;CDN 场景请直接使用主包 @arms/rum-browser(自动 PV + 全局异常采集,无 Vue 专属能力) |
产物压缩说明:
es/lib产物已经过 terser 压缩与混淆,且不附带 sourcemap(与 browser-react 包一致的体积/混淆 trade-off)。排查线上堆栈时请对照仓库源码与 CHANGELOG 版本定位对应发布版本。
SSR / Nuxt
- 模块级
import安全:源码零顶层window/document访问(唯一 DOM 触点getCurrentUrl在函数内 try-catch 防护,非浏览器环境返回空串),服务端模块加载不会抛错; install须在客户端生命周期调用:Nuxt 场景请在 client plugin(如plugins/rum.client.ts)中完成armsRum.init()与nuxtApp.vueApp.use(ArmsRumVue, { rum, router: nuxtApp.$router });- 无 Nuxt 专属适配(文件路由命名归一、
app:error启动错误钩子),按普通 Vue 3 方式接入可用但丢失 Nuxt 专属观测语义(列入后续演进)。
已知限制
以下限制是当前 MVP 设计所固有的,后续版本计划改进。
单实例约束
插件为 collector 级单例(模块级状态持有 shell/ctx 引用)。向已绑定的插件重复传入另一个 rum 实例时(多 app 传入不同 options.rum),插件会打印 logger.warn 提示(vue plugin is bound to another rum instance, only a single SDK instance is supported, refreshing shell reference)并跳过重复注册、仅刷新 shell 引用 —— 最后一次绑定的实例生效,$rum / useRum() / addVueError 的上报会路由到该实例。微前端多子应用各自持有独立 RUM 实例的场景暂不支持,未来版本计划评估注入形态解除该限制。
source='vue' 错误不受 collectors.jsError 采样管控
通过插件接管或 addVueError 上报的 Vue 错误携带 source: 'vue'。browser SDK 的 SessionProcessor 采样键映射当前仅覆盖 console / onError / unhandled 三类 source('vue' 不在其中),这意味着这些错误会绕过 collectors.jsError 采样配置。如需禁用 Vue 错误上报,请使用 collectors.exception(设置为 false)。后续版本可能会在 browser session-processor 中新增 'vue' → 'js' 的 source 映射。
errorHandler 覆盖边界
插件仅接管 config.errorHandler(Vue 3 app.config.errorHandler / Vue 2 Vue.config.errorHandler,链式保留原 handler)。以下边界场景不在覆盖范围内:
- 组件
errorCaptured返回false:按 Vue 语义该错误被视为"已处理"并阻止继续传播,全局errorHandler不会被调用 —— 插件捕获不到此类错误(Vue 框架行为,非插件可拦截); warnHandler不覆盖:Vue 运行时警告(如 prop 校验失败)不会进入 RUM 异常事件;unhandledrejection:Promise 未捕获拒绝由主包@arms/rum-browser的 jsError 采集器覆盖,无需本插件处理。
初始化时序
插件接入(app.use(ArmsRumVue, ...) / Vue.use(ArmsRumVue, ...))不再依赖 armsRum.init() 完成 —— 可在 init 前后任意时序同步调用,先后顺序可互换。初始化完成之前调用 useRum / $rum 的 sendCustom / sendEvent、或 addVueError 等需 shell 的能力时,将安全降级(打印告警并跳过操作,不抛错),init 完成前触发的错误与自定义事件不会被采集。init 前触发的路由导航经插件内部 pending 队列兜底,collector.setup 完成后自动补发首个 view(loading_type: 'initial_load'),首屏不丢失。useRum() / getRum() 本身可在任意时刻调用 —— 它们返回稳定单例引用,在初始化完成后即可正常使用。
License
ISC
