@blueking/open-telemetry 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/package.json +4 -1
  2. package/playground/App.vue +0 -148
  3. package/playground/bk-ot.ts +0 -110
  4. package/playground/components/DemoLogPanel.vue +0 -89
  5. package/playground/composables/use-demo-log.ts +0 -39
  6. package/playground/index.html +0 -13
  7. package/playground/main.ts +0 -36
  8. package/playground/mock/index.ts +0 -43
  9. package/playground/pages/BlankScreenDemo.vue +0 -97
  10. package/playground/pages/BusinessDemo.vue +0 -74
  11. package/playground/pages/CustomPluginDemo.vue +0 -104
  12. package/playground/pages/ErrorDemo.vue +0 -75
  13. package/playground/pages/Home.vue +0 -133
  14. package/playground/pages/HttpDemo.vue +0 -120
  15. package/playground/pages/LongTaskDemo.vue +0 -66
  16. package/playground/pages/WebSocketDemo.vue +0 -100
  17. package/playground/router/index.ts +0 -92
  18. package/playground/style.css +0 -180
  19. package/src/browser.ts +0 -44
  20. package/src/core/config.ts +0 -327
  21. package/src/core/plugin.ts +0 -97
  22. package/src/core/processor.ts +0 -74
  23. package/src/core/route-observer.ts +0 -128
  24. package/src/core/sampling.ts +0 -64
  25. package/src/core/sdk.ts +0 -327
  26. package/src/core/url.ts +0 -66
  27. package/src/plugins/blank-screen.ts +0 -170
  28. package/src/plugins/common.ts +0 -131
  29. package/src/plugins/csp-violation.ts +0 -74
  30. package/src/plugins/device.ts +0 -91
  31. package/src/plugins/error.ts +0 -211
  32. package/src/plugins/http-body.ts +0 -437
  33. package/src/plugins/long-task.ts +0 -99
  34. package/src/plugins/page-view.ts +0 -83
  35. package/src/plugins/route-timing.ts +0 -89
  36. package/src/plugins/session.ts +0 -127
  37. package/src/plugins/web-vitals.ts +0 -159
  38. package/src/plugins/websocket.ts +0 -179
  39. package/tsconfig.app.json +0 -27
  40. package/tsconfig.dts.json +0 -13
  41. package/tsconfig.json +0 -7
  42. package/tsconfig.node.json +0 -26
  43. package/vite.config.ts +0 -70
@@ -1,104 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">自定义插件 · createPlugin</h2>
5
- <p class="demo-page__desc">
6
- SDK 通过 <code>createPlugin</code> 暴露统一的扩展点。本 playground 在初始化时挂载了一个名为
7
- <code>playground-bridge</code> 的演示插件:注入 runtime attributes,并在 window 上暴露
8
- <code>__bkotEmitDemoSpan</code> 用于手动产生 span。
9
- </p>
10
- </header>
11
-
12
- <div class="demo-card">
13
- <h3 class="demo-card__title">代码片段</h3>
14
- <pre class="demo-snippet">{{ snippet }}</pre>
15
- </div>
16
-
17
- <div class="demo-card">
18
- <h3 class="demo-card__title">手动触发自定义 span</h3>
19
- <p class="demo-card__hint">
20
- 查看控制台 <code>[bk-ot][traces]</code> 中带 <code>playground.manual=true</code> 的 span。
21
- </p>
22
- <div class="demo-actions">
23
- <input
24
- v-model="spanName"
25
- class="span-input"
26
- placeholder="span 名称"
27
- />
28
- <button
29
- class="demo-btn"
30
- :disabled="!spanName.trim()"
31
- type="button"
32
- @click="emitSpan"
33
- >
34
- 发射 span
35
- </button>
36
- </div>
37
- </div>
38
-
39
- <div class="demo-card">
40
- <DemoLogPanel
41
- :entries="entries"
42
- @clear="clear"
43
- />
44
- </div>
45
- </section>
46
- </template>
47
-
48
- <script setup lang="ts">
49
- import { shallowRef } from 'vue';
50
-
51
- import DemoLogPanel from '../components/DemoLogPanel.vue';
52
- import { useDemoLog } from '../composables/use-demo-log';
53
-
54
- type EmitDemoSpan = (name?: string) => void;
55
-
56
- const { entries, push, clear } = useDemoLog();
57
- const spanName = shallowRef('playground.custom_event');
58
-
59
- const emitSpan = () => {
60
- const fn = (globalThis as unknown as { __bkotEmitDemoSpan?: EmitDemoSpan }).__bkotEmitDemoSpan;
61
- if (typeof fn !== 'function') {
62
- push('__bkotEmitDemoSpan 未注册,请检查 SDK 是否成功启动', 'error');
63
- return;
64
- }
65
- fn(spanName.value.trim());
66
- push(`已通过自定义插件发射 span:${spanName.value}`);
67
- };
68
-
69
- const snippet = `import { initBkOT, createPlugin, type BkOTPlugin } from '@blueking/open-telemetry';
70
-
71
- const myPlugin: BkOTPlugin = createPlugin({
72
- name: 'playground-bridge',
73
- init(context) {
74
- context.setRuntimeAttributes({ 'playground.demo': true });
75
-
76
- // 自定义业务 span / metric / log,统一走 context 提供的 API
77
- const span = context.startSpan('boot.bridge_ready', { 'plugin.boot': true });
78
- span.end();
79
- },
80
- });
81
-
82
- initBkOT({
83
- plugins: [myPlugin],
84
- });`;
85
- </script>
86
-
87
- <style scoped>
88
- .span-input {
89
- flex: 1;
90
- min-width: 200px;
91
- padding: 8px 12px;
92
- font-family: inherit;
93
- font-size: 14px;
94
- color: var(--color-text-primary);
95
- background: var(--color-bg);
96
- border: 1px solid var(--color-border);
97
- border-radius: var(--radius-sm);
98
- }
99
-
100
- .span-input:focus {
101
- outline: 2px solid var(--color-primary);
102
- outline-offset: 1px;
103
- }
104
- </style>
@@ -1,75 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">错误捕获 · error 插件</h2>
5
- <p class="demo-page__desc">
6
- 监听 <code>window.error</code> 与 <code>unhandledrejection</code>,按错误堆栈 hash 节流(默认 60s 内同 hash 最多
7
- 5 条)。
8
- </p>
9
- </header>
10
-
11
- <div class="demo-card">
12
- <h3 class="demo-card__title">触发错误</h3>
13
- <p class="demo-card__hint">触发后查看控制台 <code>[bk-ot][traces]</code> 中 <code>browser.error</code> span。</p>
14
- <div class="demo-actions">
15
- <button
16
- class="demo-btn demo-btn--danger"
17
- type="button"
18
- @click="throwSync"
19
- >
20
- 同步抛错
21
- </button>
22
- <button
23
- class="demo-btn demo-btn--danger"
24
- type="button"
25
- @click="throwAsync"
26
- >
27
- 异步 Promise 拒绝
28
- </button>
29
- <button
30
- class="demo-btn demo-btn--warning"
31
- type="button"
32
- @click="throwBurst"
33
- >
34
- 连续抛 8 次(演示节流)
35
- </button>
36
- </div>
37
- </div>
38
-
39
- <div class="demo-card">
40
- <DemoLogPanel
41
- :entries="entries"
42
- @clear="clear"
43
- />
44
- </div>
45
- </section>
46
- </template>
47
-
48
- <script setup lang="ts">
49
- import DemoLogPanel from '../components/DemoLogPanel.vue';
50
- import { useDemoLog } from '../composables/use-demo-log';
51
-
52
- const { entries, push, clear } = useDemoLog();
53
-
54
- const throwSync = () => {
55
- push('准备触发同步异常', 'warn');
56
- // 用 setTimeout 让 error 真正进入 window.error 而不是被 click handler 吞掉
57
- setTimeout(() => {
58
- throw new Error('Demo: 同步异常 ' + Date.now());
59
- }, 0);
60
- };
61
-
62
- const throwAsync = () => {
63
- push('准备触发未捕获 Promise 拒绝', 'warn');
64
- void Promise.reject(new Error('Demo: 未处理 promise rejection ' + Date.now()));
65
- };
66
-
67
- const throwBurst = () => {
68
- push('一秒内连续抛 8 次相同错误,预期前 5 条上报、后 3 条被节流', 'warn');
69
- for (let i = 0; i < 8; i += 1) {
70
- setTimeout(() => {
71
- throw new Error('Demo: 节流测试错误');
72
- }, i * 50);
73
- }
74
- };
75
- </script>
@@ -1,133 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">@blueking/open-telemetry · Playground</h2>
5
- <p class="demo-page__desc">
6
- 本 playground 演示 SDK 全部内置插件与扩展点的实际用法。打开浏览器控制台即可看到 trace / log / metric
7
- 三类信号的完整产物。
8
- </p>
9
- </header>
10
-
11
- <div class="demo-card">
12
- <h3 class="demo-card__title">SDK 运行时状态</h3>
13
- <p class="demo-card__hint">
14
- 通过 <code>BkOTInstance.getRuntimeAttributes()</code> 获取当前所有 span / log 都会携带的公共属性。
15
- </p>
16
- <pre class="demo-snippet">{{ runtimeAttrsText }}</pre>
17
- <div class="demo-actions">
18
- <button
19
- class="demo-btn"
20
- type="button"
21
- @click="refresh"
22
- >
23
- 刷新运行时属性
24
- </button>
25
- <button
26
- class="demo-btn demo-btn--ghost"
27
- type="button"
28
- @click="forceFlush"
29
- >
30
- 手动 flush 信号
31
- </button>
32
- </div>
33
- </div>
34
-
35
- <div class="demo-card">
36
- <h3 class="demo-card__title">默认开启的内置插件</h3>
37
- <ul class="plugin-list">
38
- <li
39
- v-for="plugin in plugins"
40
- :key="plugin.name"
41
- >
42
- <strong>{{ plugin.name }}</strong>
43
- <span>{{ plugin.desc }}</span>
44
- </li>
45
- </ul>
46
- </div>
47
-
48
- <div class="demo-card">
49
- <h3 class="demo-card__title">最小初始化代码</h3>
50
- <pre class="demo-snippet">{{ snippet }}</pre>
51
- </div>
52
- </section>
53
- </template>
54
-
55
- <script setup lang="ts">
56
- import { shallowRef } from 'vue';
57
-
58
- import { bkot } from '../bk-ot';
59
-
60
- const runtimeAttrsText = shallowRef('');
61
- const refresh = () => {
62
- runtimeAttrsText.value = JSON.stringify(bkot.getRuntimeAttributes(), null, 2);
63
- };
64
- refresh();
65
-
66
- const forceFlush = async () => {
67
- await bkot.flush();
68
- };
69
-
70
- const plugins = [
71
- {
72
- name: 'common',
73
- desc: '基于 OpenTelemetry 官方 instrumentation 自动埋点 fetch/xhr/document-load/user-interaction',
74
- },
75
- { name: 'device', desc: '采集设备 / 浏览器 / 网络环境,作为持久 runtime attributes' },
76
- { name: 'session', desc: '维护匿名 session id,闲置 30 分钟后自动滚动' },
77
- { name: 'page-view', desc: '监听 SPA 路由变化(pushState / popstate / hashchange)上报 PV' },
78
- { name: 'error', desc: '捕获 window.error / unhandledrejection 并按 hash 节流上报' },
79
- { name: 'web-vitals', desc: '上报 LCP / CLS / INP / FCP / TTFB 等核心 Web Vitals 指标' },
80
- { name: 'blank-screen', desc: '在挂载延时后采样根节点像素分布,识别白屏' },
81
- { name: 'http-body', desc: '可选地抓取请求 / 响应体,支持 redact 脱敏' },
82
- { name: 'long-task', desc: '监听 PerformanceObserver longtask,超过阈值上报' },
83
- { name: 'route-timing', desc: '估算 SPA 路由切换耗时(双 raf + 一个宏任务)' },
84
- { name: 'csp-violation', desc: '监听 securitypolicyviolation 事件并上报' },
85
- { name: 'websocket', desc: '在 WebSocket 生命周期上挂钩,上报连接 / 消息事件' },
86
- ];
87
-
88
- const snippet = `import { initBkOT } from '@blueking/open-telemetry';
89
-
90
- initBkOT({
91
- endpoint: 'https://your-otlp-collector',
92
- token: 'your-report-token',
93
- debug: true,
94
- rum: {
95
- fetch: true,
96
- xhr: true,
97
- documentLoad: true,
98
- userInteraction: true,
99
- longTask: true,
100
- routeTiming: true,
101
- },
102
- });`;
103
- </script>
104
-
105
- <style scoped>
106
- .plugin-list {
107
- display: grid;
108
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
109
- gap: var(--space-sm);
110
- padding: 0;
111
- margin: 0;
112
- list-style: none;
113
- }
114
-
115
- .plugin-list li {
116
- display: flex;
117
- flex-direction: column;
118
- gap: 2px;
119
- padding: var(--space-sm) var(--space-md);
120
- background: var(--color-bg);
121
- border-radius: var(--radius-sm);
122
- }
123
-
124
- .plugin-list strong {
125
- font-family: var(--font-mono);
126
- color: var(--color-primary);
127
- }
128
-
129
- .plugin-list span {
130
- font-size: 12px;
131
- color: var(--color-text-secondary);
132
- }
133
- </style>
@@ -1,120 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">HTTP 请求 / http-body 插件</h2>
5
- <p class="demo-page__desc">
6
- common 插件会为 fetch / xhr 自动产生 client span;http-body 插件会按配置抓取请求与响应体(演示中
7
- <code>password</code> 字段会被 redact 替换为 <code>***</code>)。
8
- </p>
9
- </header>
10
-
11
- <div class="demo-card">
12
- <h3 class="demo-card__title">触发请求</h3>
13
- <p class="demo-card__hint">
14
- 点击按钮后查看控制台 <code>[bk-ot][traces]</code> 中携带 <code>http.*</code> 的 span。
15
- </p>
16
- <div class="demo-actions">
17
- <button
18
- class="demo-btn"
19
- :disabled="pending"
20
- type="button"
21
- @click="callFetchGet"
22
- >
23
- fetch GET
24
- </button>
25
- <button
26
- class="demo-btn"
27
- :disabled="pending"
28
- type="button"
29
- @click="callFetchPost"
30
- >
31
- fetch POST(带敏感字段)
32
- </button>
33
- <button
34
- class="demo-btn demo-btn--ghost"
35
- :disabled="pending"
36
- type="button"
37
- @click="callXhr"
38
- >
39
- XHR GET
40
- </button>
41
- <button
42
- class="demo-btn demo-btn--warning"
43
- :disabled="pending"
44
- type="button"
45
- @click="callFetchError"
46
- >
47
- fetch 404
48
- </button>
49
- </div>
50
- </div>
51
-
52
- <div class="demo-card">
53
- <DemoLogPanel
54
- :entries="entries"
55
- @clear="clear"
56
- />
57
- </div>
58
- </section>
59
- </template>
60
-
61
- <script setup lang="ts">
62
- import { shallowRef } from 'vue';
63
-
64
- import DemoLogPanel from '../components/DemoLogPanel.vue';
65
- import { useDemoLog } from '../composables/use-demo-log';
66
- import { httpEndpoints, samplePostBody } from '../mock';
67
-
68
- const { entries, push, clear } = useDemoLog();
69
- const pending = shallowRef(false);
70
-
71
- const wrap = async (label: string, runner: () => Promise<unknown>) => {
72
- pending.value = true;
73
- try {
74
- const result = await runner();
75
- push(`${label} 成功:${JSON.stringify(result).slice(0, 80)}…`);
76
- } catch (error) {
77
- push(`${label} 失败:${(error as Error).message}`, 'error');
78
- } finally {
79
- pending.value = false;
80
- }
81
- };
82
-
83
- const callFetchGet = () =>
84
- wrap('fetch GET', async () => {
85
- const response = await fetch(httpEndpoints.echoGet);
86
- return response.json();
87
- });
88
-
89
- const callFetchPost = () =>
90
- wrap('fetch POST', async () => {
91
- const response = await fetch(httpEndpoints.echoPost, {
92
- method: 'POST',
93
- headers: { 'content-type': 'application/json' },
94
- body: JSON.stringify(samplePostBody),
95
- });
96
- return response.json();
97
- });
98
-
99
- const callXhr = () =>
100
- wrap(
101
- 'XHR GET',
102
- () =>
103
- new Promise((resolve, reject) => {
104
- const xhr = new XMLHttpRequest();
105
- xhr.open('GET', httpEndpoints.echoGet);
106
- xhr.onload = () => resolve(xhr.status);
107
- xhr.onerror = () => reject(new Error('xhr error'));
108
- xhr.send();
109
- }),
110
- );
111
-
112
- const callFetchError = () =>
113
- wrap('fetch 404', async () => {
114
- const response = await fetch(httpEndpoints.notFound);
115
- if (!response.ok) {
116
- throw new Error(`status ${response.status}`);
117
- }
118
- return response.text();
119
- });
120
- </script>
@@ -1,66 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">长任务 · long-task 插件</h2>
5
- <p class="demo-page__desc">
6
- 监听 PerformanceObserver 的 <code>longtask</code> 条目,超过 <code>threshold</code>(默认 50ms,演示中为
7
- 50ms)的任务会上报。
8
- </p>
9
- </header>
10
-
11
- <div class="demo-card">
12
- <h3 class="demo-card__title">在主线程造一个长任务</h3>
13
- <p class="demo-card__hint">
14
- 点击按钮后会用同步 while 循环阻塞主线程指定时长,可对比 <code>&lt; 50ms</code> 时不上报、<code>&gt; 50ms</code>
15
- 时上报的差异。
16
- </p>
17
- <div class="demo-actions">
18
- <button
19
- class="demo-btn"
20
- type="button"
21
- @click="block(30)"
22
- >
23
- 阻塞 30ms(不上报)
24
- </button>
25
- <button
26
- class="demo-btn demo-btn--warning"
27
- type="button"
28
- @click="block(120)"
29
- >
30
- 阻塞 120ms
31
- </button>
32
- <button
33
- class="demo-btn demo-btn--danger"
34
- type="button"
35
- @click="block(450)"
36
- >
37
- 阻塞 450ms
38
- </button>
39
- </div>
40
- </div>
41
-
42
- <div class="demo-card">
43
- <DemoLogPanel
44
- :entries="entries"
45
- @clear="clear"
46
- />
47
- </div>
48
- </section>
49
- </template>
50
-
51
- <script setup lang="ts">
52
- import DemoLogPanel from '../components/DemoLogPanel.vue';
53
- import { useDemoLog } from '../composables/use-demo-log';
54
-
55
- const { entries, push, clear } = useDemoLog();
56
-
57
- // 用 while 循环刻意阻塞主线程,触发 PerformanceObserver longtask 条目
58
- const block = (durationMs: number) => {
59
- push(`即将阻塞主线程 ${durationMs}ms`, 'warn');
60
- const start = performance.now();
61
- while (performance.now() - start < durationMs) {
62
- // intentionally busy-wait
63
- }
64
- push(`阻塞结束(实际耗时 ${(performance.now() - start).toFixed(1)}ms)`);
65
- };
66
- </script>
@@ -1,100 +0,0 @@
1
- <template>
2
- <section class="demo-page">
3
- <header>
4
- <h2 class="demo-page__title">WebSocket · websocket 插件</h2>
5
- <p class="demo-page__desc">
6
- websocket 插件会在 WebSocket 生命周期(open / message / close / error)上挂钩,自动上报关键事件。
7
- </p>
8
- </header>
9
-
10
- <div class="demo-card">
11
- <h3 class="demo-card__title">演示连接</h3>
12
- <p class="demo-card__hint">
13
- 默认连接 <code>{{ websocketEndpoint }}</code
14
- >(一个公共 echo server)。点击连接后再点"发送消息"即可看到完整链路。
15
- </p>
16
- <div class="demo-actions">
17
- <button
18
- class="demo-btn"
19
- :disabled="connected"
20
- type="button"
21
- @click="connect"
22
- >
23
- 连接
24
- </button>
25
- <button
26
- class="demo-btn demo-btn--success"
27
- :disabled="!connected"
28
- type="button"
29
- @click="send"
30
- >
31
- 发送消息
32
- </button>
33
- <button
34
- class="demo-btn demo-btn--ghost"
35
- :disabled="!connected"
36
- type="button"
37
- @click="disconnect"
38
- >
39
- 断开
40
- </button>
41
- </div>
42
- </div>
43
-
44
- <div class="demo-card">
45
- <DemoLogPanel
46
- :entries="entries"
47
- @clear="clear"
48
- />
49
- </div>
50
- </section>
51
- </template>
52
-
53
- <script setup lang="ts">
54
- import { onBeforeUnmount, shallowRef } from 'vue';
55
-
56
- import DemoLogPanel from '../components/DemoLogPanel.vue';
57
- import { useDemoLog } from '../composables/use-demo-log';
58
- import { websocketEndpoint } from '../mock';
59
-
60
- const { entries, push, clear } = useDemoLog();
61
- const socket = shallowRef<null | WebSocket>(null);
62
- const connected = shallowRef(false);
63
-
64
- const connect = () => {
65
- if (socket.value) {
66
- return;
67
- }
68
- const ws = new WebSocket(websocketEndpoint);
69
- socket.value = ws;
70
- push(`正在连接 ${websocketEndpoint}`);
71
-
72
- ws.addEventListener('open', () => {
73
- connected.value = true;
74
- push('WebSocket 已连接');
75
- });
76
- ws.addEventListener('message', event => {
77
- push(`收到消息:${typeof event.data === 'string' ? event.data : '[binary]'}`);
78
- });
79
- ws.addEventListener('close', event => {
80
- connected.value = false;
81
- socket.value = null;
82
- push(`已断开(code=${event.code})`, 'warn');
83
- });
84
- ws.addEventListener('error', () => {
85
- push('WebSocket 出错', 'error');
86
- });
87
- };
88
-
89
- const send = () => {
90
- socket.value?.send(`hello from playground @ ${Date.now()}`);
91
- };
92
-
93
- const disconnect = () => {
94
- socket.value?.close();
95
- };
96
-
97
- onBeforeUnmount(() => {
98
- socket.value?.close();
99
- });
100
- </script>
@@ -1,92 +0,0 @@
1
- /*
2
- * Tencent is pleased to support the open source community by making
3
- * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
4
- *
5
- * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
6
- *
7
- * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
8
- *
9
- * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
10
- *
11
- * ---------------------------------------------------
12
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
14
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15
- * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16
- *
17
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
18
- * the Software.
19
- *
20
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
21
- * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
- * IN THE SOFTWARE.
25
- */
26
-
27
- import { type RouteRecordRaw, createRouter, createWebHashHistory } from 'vue-router';
28
-
29
- // hash 路由便于单页静态部署,同时方便演示 hashchange / popstate 路由观察
30
- const routes: RouteRecordRaw[] = [
31
- {
32
- path: '/',
33
- name: 'home',
34
- component: () => import('../pages/Home.vue'),
35
- meta: { title: '总览' },
36
- },
37
- {
38
- path: '/http',
39
- name: 'http',
40
- component: () => import('../pages/HttpDemo.vue'),
41
- meta: { title: 'HTTP / http-body' },
42
- },
43
- {
44
- path: '/error',
45
- name: 'error',
46
- component: () => import('../pages/ErrorDemo.vue'),
47
- meta: { title: '错误捕获' },
48
- },
49
- {
50
- path: '/business',
51
- name: 'business',
52
- component: () => import('../pages/BusinessDemo.vue'),
53
- meta: { title: '业务事件' },
54
- },
55
- {
56
- path: '/long-task',
57
- name: 'long-task',
58
- component: () => import('../pages/LongTaskDemo.vue'),
59
- meta: { title: '长任务' },
60
- },
61
- {
62
- path: '/websocket',
63
- name: 'websocket',
64
- component: () => import('../pages/WebSocketDemo.vue'),
65
- meta: { title: 'WebSocket' },
66
- },
67
- {
68
- path: '/blank-screen',
69
- name: 'blank-screen',
70
- component: () => import('../pages/BlankScreenDemo.vue'),
71
- meta: { title: '白屏检测' },
72
- },
73
- {
74
- path: '/custom-plugin',
75
- name: 'custom-plugin',
76
- component: () => import('../pages/CustomPluginDemo.vue'),
77
- meta: { title: '自定义插件' },
78
- },
79
- ];
80
-
81
- export const router = createRouter({
82
- history: createWebHashHistory(),
83
- routes,
84
- });
85
-
86
- export const navItems = routes
87
- .filter(route => typeof route.name === 'string')
88
- .map(route => ({
89
- name: route.name as string,
90
- path: route.path,
91
- title: (route.meta?.title as string) ?? (route.name as string),
92
- }));