nuxt-devtools-observatory 0.1.0

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 (33) hide show
  1. package/README.md +209 -0
  2. package/client/dist/assets/index-C76d764s.js +17 -0
  3. package/client/dist/assets/index-yIuOV1_N.css +1 -0
  4. package/client/dist/index.html +47 -0
  5. package/client/index.html +46 -0
  6. package/client/src/App.vue +114 -0
  7. package/client/src/main.ts +5 -0
  8. package/client/src/stores/observatory.ts +65 -0
  9. package/client/src/style.css +261 -0
  10. package/client/src/views/ComposableTracker.vue +347 -0
  11. package/client/src/views/FetchDashboard.vue +492 -0
  12. package/client/src/views/ProvideInjectGraph.vue +481 -0
  13. package/client/src/views/RenderHeatmap.vue +492 -0
  14. package/client/src/views/TransitionTimeline.vue +527 -0
  15. package/client/tsconfig.json +16 -0
  16. package/client/vite.config.ts +12 -0
  17. package/dist/module.d.mts +38 -0
  18. package/dist/module.json +12 -0
  19. package/dist/module.mjs +562 -0
  20. package/dist/runtime/composables/composable-registry.d.ts +40 -0
  21. package/dist/runtime/composables/composable-registry.js +135 -0
  22. package/dist/runtime/composables/fetch-registry.d.ts +63 -0
  23. package/dist/runtime/composables/fetch-registry.js +83 -0
  24. package/dist/runtime/composables/provide-inject-registry.d.ts +57 -0
  25. package/dist/runtime/composables/provide-inject-registry.js +96 -0
  26. package/dist/runtime/composables/render-registry.d.ts +36 -0
  27. package/dist/runtime/composables/render-registry.js +85 -0
  28. package/dist/runtime/composables/transition-registry.d.ts +21 -0
  29. package/dist/runtime/composables/transition-registry.js +125 -0
  30. package/dist/runtime/plugin.d.ts +2 -0
  31. package/dist/runtime/plugin.js +66 -0
  32. package/dist/types.d.mts +3 -0
  33. package/package.json +89 -0
@@ -0,0 +1,125 @@
1
+ import { ref, h, defineComponent, getCurrentInstance, onUnmounted, Transition as VueTransition } from "vue";
2
+ export function setupTransitionRegistry() {
3
+ const entries = ref(/* @__PURE__ */ new Map());
4
+ function register(entry) {
5
+ entries.value.set(entry.id, entry);
6
+ emit("transition:register", entry);
7
+ }
8
+ function update(id, patch) {
9
+ const existing = entries.value.get(id);
10
+ if (!existing) {
11
+ return;
12
+ }
13
+ const updated = { ...existing, ...patch };
14
+ if (patch.endTime !== void 0) {
15
+ updated.durationMs = Math.round((patch.endTime - existing.startTime) * 10) / 10;
16
+ }
17
+ entries.value.set(id, updated);
18
+ emit("transition:update", updated);
19
+ }
20
+ function getAll() {
21
+ return [...entries.value.values()].map((e) => ({ ...e }));
22
+ }
23
+ function emit(event, data) {
24
+ if (!import.meta.client) {
25
+ return;
26
+ }
27
+ const channel = window.__nuxt_devtools__?.channel;
28
+ channel?.send(event, data);
29
+ }
30
+ return { register, update, getAll };
31
+ }
32
+ function mergeHook(original, ours) {
33
+ return (el) => {
34
+ ours(el);
35
+ original?.(el);
36
+ };
37
+ }
38
+ export function createTrackedTransition(registry) {
39
+ return defineComponent({
40
+ name: "Transition",
41
+ inheritAttrs: false,
42
+ setup(_, { attrs, slots }) {
43
+ const instance = getCurrentInstance();
44
+ const parent = instance?.parent;
45
+ const parentComponent = parent?.type?.__name ?? parent?.type?.name ?? "unknown";
46
+ let enterEntryId = null;
47
+ let leaveEntryId = null;
48
+ onUnmounted(() => {
49
+ if (enterEntryId) {
50
+ registry.update(enterEntryId, { phase: "interrupted", endTime: performance.now() });
51
+ enterEntryId = null;
52
+ }
53
+ if (leaveEntryId) {
54
+ registry.update(leaveEntryId, { phase: "interrupted", endTime: performance.now() });
55
+ leaveEntryId = null;
56
+ }
57
+ });
58
+ return () => {
59
+ const transitionName = String(attrs.name ?? "default");
60
+ const isAppear = Boolean(attrs.appear);
61
+ const mode = typeof attrs.mode === "string" ? attrs.mode : void 0;
62
+ const hookedAttrs = {
63
+ ...attrs,
64
+ onBeforeEnter: mergeHook(attrs.onBeforeEnter, () => {
65
+ const now = performance.now();
66
+ const id = `${transitionName}::enter::${now}`;
67
+ enterEntryId = id;
68
+ registry.register({
69
+ id,
70
+ transitionName,
71
+ parentComponent,
72
+ direction: "enter",
73
+ phase: "entering",
74
+ startTime: now,
75
+ cancelled: false,
76
+ appear: isAppear,
77
+ mode
78
+ });
79
+ }),
80
+ onAfterEnter: mergeHook(attrs.onAfterEnter, () => {
81
+ if (enterEntryId) {
82
+ registry.update(enterEntryId, { phase: "entered", endTime: performance.now() });
83
+ enterEntryId = null;
84
+ }
85
+ }),
86
+ onEnterCancelled: mergeHook(attrs.onEnterCancelled, () => {
87
+ if (enterEntryId) {
88
+ registry.update(enterEntryId, { phase: "enter-cancelled", cancelled: true, endTime: performance.now() });
89
+ enterEntryId = null;
90
+ }
91
+ }),
92
+ onBeforeLeave: mergeHook(attrs.onBeforeLeave, () => {
93
+ const now = performance.now();
94
+ const id = `${transitionName}::leave::${now}`;
95
+ leaveEntryId = id;
96
+ registry.register({
97
+ id,
98
+ transitionName,
99
+ parentComponent,
100
+ direction: "leave",
101
+ phase: "leaving",
102
+ startTime: now,
103
+ cancelled: false,
104
+ appear: false,
105
+ mode
106
+ });
107
+ }),
108
+ onAfterLeave: mergeHook(attrs.onAfterLeave, () => {
109
+ if (leaveEntryId) {
110
+ registry.update(leaveEntryId, { phase: "left", endTime: performance.now() });
111
+ leaveEntryId = null;
112
+ }
113
+ }),
114
+ onLeaveCancelled: mergeHook(attrs.onLeaveCancelled, () => {
115
+ if (leaveEntryId) {
116
+ registry.update(leaveEntryId, { phase: "leave-cancelled", cancelled: true, endTime: performance.now() });
117
+ leaveEntryId = null;
118
+ }
119
+ })
120
+ };
121
+ return h(VueTransition, hookedAttrs, slots);
122
+ };
123
+ }
124
+ });
125
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,66 @@
1
+ import { defineNuxtPlugin, useNuxtApp, useRuntimeConfig } from "#app";
2
+ import { setupFetchRegistry } from "./composables/fetch-registry.js";
3
+ import { setupProvideInjectRegistry } from "./composables/provide-inject-registry.js";
4
+ import { setupComposableRegistry } from "./composables/composable-registry.js";
5
+ import { setupRenderRegistry } from "./composables/render-registry.js";
6
+ import { setupTransitionRegistry } from "./composables/transition-registry.js";
7
+ export default defineNuxtPlugin(() => {
8
+ if (!import.meta.dev) {
9
+ return;
10
+ }
11
+ const nuxtApp = useNuxtApp();
12
+ const config = useRuntimeConfig().public.observatory;
13
+ nuxtApp.vueApp.config.performance = true;
14
+ const fetchRegistry = setupFetchRegistry();
15
+ const provideInjectRegistry = setupProvideInjectRegistry();
16
+ const composableRegistry = setupComposableRegistry();
17
+ const renderRegistry = setupRenderRegistry(nuxtApp, config.heatmapThreshold);
18
+ const transitionRegistry = setupTransitionRegistry();
19
+ if (import.meta.client) {
20
+ ;
21
+ window.__observatory__ = {
22
+ fetch: fetchRegistry,
23
+ provideInject: provideInjectRegistry,
24
+ composable: composableRegistry,
25
+ render: renderRegistry,
26
+ transition: transitionRegistry
27
+ };
28
+ window.addEventListener("message", (event) => {
29
+ if (event.data?.type !== "observatory:request") {
30
+ return;
31
+ }
32
+ const source = event.source;
33
+ source?.postMessage(
34
+ {
35
+ type: "observatory:snapshot",
36
+ data: {
37
+ transitions: transitionRegistry.getAll()
38
+ }
39
+ },
40
+ "*"
41
+ );
42
+ });
43
+ }
44
+ nuxtApp.hook("app:mounted", () => {
45
+ broadcastAll();
46
+ });
47
+ function broadcastAll() {
48
+ if (!import.meta.client) {
49
+ return;
50
+ }
51
+ const channel = getDevtoolsChannel();
52
+ if (!channel) {
53
+ return;
54
+ }
55
+ channel.send("observatory:snapshot", {
56
+ fetch: fetchRegistry.getAll(),
57
+ provideInject: provideInjectRegistry.getAll(),
58
+ composables: composableRegistry.getAll(),
59
+ renders: renderRegistry.getAll(),
60
+ transitions: transitionRegistry.getAll()
61
+ });
62
+ }
63
+ function getDevtoolsChannel() {
64
+ return window.__nuxt_devtools__?.channel ?? null;
65
+ }
66
+ });
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type ModuleOptions } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "nuxt-devtools-observatory",
3
+ "version": "0.1.0",
4
+ "description": "Vue/Nuxt DevTools: useFetch Dashboard, provide/inject Graph, Composable Tracker, Render Heatmap",
5
+ "type": "module",
6
+ "main": "./dist/module.mjs",
7
+ "module": "./dist/module.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/module.mjs"
11
+ },
12
+ "./runtime/composable-registry": {
13
+ "import": "./dist/runtime/composables/composable-registry.js"
14
+ },
15
+ "./runtime/provide-inject-registry": {
16
+ "import": "./dist/runtime/composables/provide-inject-registry.js"
17
+ },
18
+ "./runtime/fetch-registry": {
19
+ "import": "./dist/runtime/composables/fetch-registry.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "client"
25
+ ],
26
+ "scripts": {
27
+ "dev": "nuxi dev playground",
28
+ "build:client": "vite build --config client/vite.config.ts",
29
+ "build": "npm run build:client && nuxt-module-build build",
30
+ "lint": "eslint .",
31
+ "format": "prettier --write '**/*.{ts,vue,js,json}' --ignore-path .gitignore && stylelint '**/*.{css,vue}' --ignore-pattern '.nuxt/**' --ignore-pattern '.output/**' --ignore-pattern 'coverage/**' --fix && eslint --fix '**/*.{ts,vue,js}' --ignore-pattern 'coverage/**'",
32
+ "typecheck": "vue-tsc --noEmit",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "test:coverage": "vitest run --coverage"
36
+ },
37
+ "dependencies": {
38
+ "@babel/generator": "^7.29.1",
39
+ "@babel/parser": "^7.29.0",
40
+ "@babel/traverse": "^7.29.0",
41
+ "@babel/types": "^7.29.0",
42
+ "@nuxt/kit": "^3.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.39.2",
46
+ "@nuxt/eslint": "^1.13.0",
47
+ "@nuxt/kit": "^4.0.0",
48
+ "@nuxt/module-builder": "^1.0.2",
49
+ "@nuxt/schema": "^4.0.0",
50
+ "@types/babel__generator": "^7.27.0",
51
+ "@types/babel__traverse": "^7.28.0",
52
+ "@types/node": "^25.5.0",
53
+ "@vitejs/plugin-vue": "^6.0.0",
54
+ "@vitest/coverage-v8": "^4.1.0",
55
+ "eslint": "^9.39.2",
56
+ "eslint-config-prettier": "^10.1.8",
57
+ "eslint-plugin-jsdoc": "^62.5.0",
58
+ "eslint-plugin-jsonc": "^2.21.0",
59
+ "eslint-plugin-regexp": "^3.0.0",
60
+ "eslint-plugin-vue": "^10.7.0",
61
+ "globals": "^17.3.0",
62
+ "happy-dom": "^20.8.4",
63
+ "nuxt": "^3.0.0",
64
+ "postcss-html": "^1.8.1",
65
+ "prettier": "^3.8.1",
66
+ "stylelint": "^17.4.0",
67
+ "stylelint-config-standard": "^40.0.0",
68
+ "stylelint-config-standard-vue": "^1.0.0",
69
+ "typescript": "^5.9.3",
70
+ "typescript-eslint": "^8.54.0",
71
+ "unbuild": "^3.6.1",
72
+ "vite": "^6.4.1",
73
+ "vitest": "^4.1.0",
74
+ "vue": "^3.5.30",
75
+ "vue-eslint-parser": "^10.2.0"
76
+ },
77
+ "keywords": [
78
+ "nuxt",
79
+ "devtools",
80
+ "vue",
81
+ "performance",
82
+ "debugging"
83
+ ],
84
+ "pnpm": {
85
+ "patchedDependencies": {
86
+ "unimport@6.0.1": "patches/unimport@6.0.1.patch"
87
+ }
88
+ }
89
+ }