@flight-framework/devtools 0.0.21 → 1.0.1
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.
- package/README.md +220 -0
- package/dist/bundle-panel.d.ts +88 -0
- package/dist/bundle-panel.d.ts.map +1 -0
- package/dist/bundle-panel.js +371 -0
- package/dist/bundle-panel.js.map +1 -0
- package/dist/cache-panel.d.ts +104 -0
- package/dist/cache-panel.d.ts.map +1 -0
- package/dist/cache-panel.js +372 -0
- package/dist/cache-panel.js.map +1 -0
- package/dist/hydration-panel.d.ts +100 -0
- package/dist/hydration-panel.d.ts.map +1 -0
- package/dist/hydration-panel.js +329 -0
- package/dist/hydration-panel.js.map +1 -0
- package/dist/panel.js +717 -717
- package/package.json +54 -42
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @flight-framework/devtools
|
|
2
|
+
|
|
3
|
+
Developer tools for Flight Framework. Inspect routes, debug server actions, and monitor performance.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Configuration](#configuration)
|
|
11
|
+
- [Browser Extension](#browser-extension)
|
|
12
|
+
- [API](#api)
|
|
13
|
+
- [License](#license)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -D @flight-framework/devtools
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// flight.config.ts
|
|
29
|
+
import { defineConfig } from '@flight-framework/core';
|
|
30
|
+
import { devtools } from '@flight-framework/devtools';
|
|
31
|
+
|
|
32
|
+
export default defineConfig({
|
|
33
|
+
plugins: [
|
|
34
|
+
devtools(),
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Access the devtools panel at `/__devtools` in development mode.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
### Route Inspector
|
|
46
|
+
- View all registered routes
|
|
47
|
+
- See route parameters and patterns
|
|
48
|
+
- Test route matching
|
|
49
|
+
|
|
50
|
+
### Component Tree
|
|
51
|
+
- Visualize component hierarchy
|
|
52
|
+
- Inspect props and state
|
|
53
|
+
- Highlight rendering
|
|
54
|
+
|
|
55
|
+
### Server Actions
|
|
56
|
+
- Log all server action calls
|
|
57
|
+
- View request/response payloads
|
|
58
|
+
- Measure execution time
|
|
59
|
+
|
|
60
|
+
### Cache Inspector
|
|
61
|
+
- View cached entries
|
|
62
|
+
- Inspect TTL and hit rates
|
|
63
|
+
- Manually invalidate entries
|
|
64
|
+
|
|
65
|
+
### Network Monitor
|
|
66
|
+
- Track API requests
|
|
67
|
+
- View request/response headers
|
|
68
|
+
- Measure response times
|
|
69
|
+
|
|
70
|
+
### Performance
|
|
71
|
+
- Core Web Vitals (LCP, FID, CLS)
|
|
72
|
+
- Hydration timing
|
|
73
|
+
- Bundle size analysis
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
See the main [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## New in V2: Enhanced Panels
|
|
84
|
+
|
|
85
|
+
### Hydration Panel
|
|
86
|
+
|
|
87
|
+
Track island hydration timing and status:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { subscribeToHydration, setupHydrationTracking } from '@flight-framework/devtools/hydration';
|
|
91
|
+
|
|
92
|
+
// Auto-track hydration events
|
|
93
|
+
setupHydrationTracking();
|
|
94
|
+
|
|
95
|
+
// Subscribe to updates
|
|
96
|
+
subscribeToHydration((islands, metrics) => {
|
|
97
|
+
console.log(`Hydrated: ${metrics.hydratedCount}/${metrics.totalIslands}`);
|
|
98
|
+
console.log(`Avg time: ${metrics.averageHydrationTime}ms`);
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Bundle Panel
|
|
103
|
+
|
|
104
|
+
Monitor chunk loading and sizes:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { subscribeToBundles, setupBundleTracking } from '@flight-framework/devtools/bundle';
|
|
108
|
+
|
|
109
|
+
// Auto-track via Performance API
|
|
110
|
+
setupBundleTracking();
|
|
111
|
+
|
|
112
|
+
// Subscribe to updates
|
|
113
|
+
subscribeToBundles((chunks, metrics) => {
|
|
114
|
+
console.log(`Total size: ${metrics.totalSize} bytes`);
|
|
115
|
+
console.log(`Loaded: ${metrics.loadedChunks} chunks`);
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Enhanced Cache Panel
|
|
120
|
+
|
|
121
|
+
Advanced cache inspection with tag support:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { subscribeToCache, invalidateByTag } from '@flight-framework/devtools/cache';
|
|
125
|
+
|
|
126
|
+
// Subscribe to cache updates
|
|
127
|
+
subscribeToCache((entries, metrics) => {
|
|
128
|
+
console.log(`Hit rate: ${metrics.hitRate}%`);
|
|
129
|
+
console.log(`Tags: ${metrics.uniqueTags.join(', ')}`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Invalidate by tag
|
|
133
|
+
invalidateByTag('user-data');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
devtools({
|
|
142
|
+
// Enable in development only (default)
|
|
143
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
144
|
+
|
|
145
|
+
// Devtools server port
|
|
146
|
+
port: 9229,
|
|
147
|
+
|
|
148
|
+
// Open devtools automatically
|
|
149
|
+
open: false,
|
|
150
|
+
|
|
151
|
+
// Features to enable
|
|
152
|
+
features: {
|
|
153
|
+
routes: true,
|
|
154
|
+
components: true,
|
|
155
|
+
actions: true,
|
|
156
|
+
cache: true,
|
|
157
|
+
network: true,
|
|
158
|
+
performance: true,
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
// Overlay position
|
|
162
|
+
position: 'bottom-right',
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Browser Extension
|
|
169
|
+
|
|
170
|
+
Install the Flight DevTools browser extension for an integrated debugging experience:
|
|
171
|
+
|
|
172
|
+
- **Chrome**: [Flight DevTools](https://chrome.google.com/webstore/...)
|
|
173
|
+
- **Firefox**: [Flight DevTools](https://addons.mozilla.org/...)
|
|
174
|
+
|
|
175
|
+
The extension adds a "Flight" panel to your browser's developer tools.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## API
|
|
180
|
+
|
|
181
|
+
### Programmatic Access
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { getDevtools } from '@flight-framework/devtools';
|
|
185
|
+
|
|
186
|
+
const devtools = getDevtools();
|
|
187
|
+
|
|
188
|
+
// Log custom event
|
|
189
|
+
devtools.log('custom', { message: 'Hello' });
|
|
190
|
+
|
|
191
|
+
// Add custom panel
|
|
192
|
+
devtools.addPanel('my-panel', {
|
|
193
|
+
title: 'My Panel',
|
|
194
|
+
render: () => '<div>Custom content</div>',
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### React Hook
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { useDevtools } from '@flight-framework/devtools/react';
|
|
202
|
+
|
|
203
|
+
function MyComponent() {
|
|
204
|
+
const { log, measure } = useDevtools();
|
|
205
|
+
|
|
206
|
+
const handleClick = () => {
|
|
207
|
+
const end = measure('click-handler');
|
|
208
|
+
// ... do work
|
|
209
|
+
end();
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
return <button onClick={handleClick}>Click</button>;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flight-framework/devtools - Bundle Panel
|
|
3
|
+
*
|
|
4
|
+
* Visualizes bundle composition within DevTools.
|
|
5
|
+
* Shows chunk breakdown, sizes, and loading status.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Information about a loaded chunk
|
|
9
|
+
*/
|
|
10
|
+
export interface ChunkInfo {
|
|
11
|
+
/** Chunk name/identifier */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Chunk URL */
|
|
14
|
+
url: string;
|
|
15
|
+
/** Size in bytes (uncompressed) */
|
|
16
|
+
size: number;
|
|
17
|
+
/** Gzip size if available */
|
|
18
|
+
gzipSize?: number;
|
|
19
|
+
/** Loading status */
|
|
20
|
+
status: 'pending' | 'loading' | 'loaded' | 'error';
|
|
21
|
+
/** Load time in ms */
|
|
22
|
+
loadTime?: number;
|
|
23
|
+
/** Whether this is an entry chunk */
|
|
24
|
+
isEntry: boolean;
|
|
25
|
+
/** Whether this is a dynamic import */
|
|
26
|
+
isDynamic: boolean;
|
|
27
|
+
/** Parse time if available */
|
|
28
|
+
parseTime?: number;
|
|
29
|
+
/** Modules in this chunk */
|
|
30
|
+
modules?: string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Bundle metrics
|
|
34
|
+
*/
|
|
35
|
+
export interface BundleMetrics {
|
|
36
|
+
/** Total number of chunks */
|
|
37
|
+
totalChunks: number;
|
|
38
|
+
/** Number of loaded chunks */
|
|
39
|
+
loadedChunks: number;
|
|
40
|
+
/** Total size of all chunks */
|
|
41
|
+
totalSize: number;
|
|
42
|
+
/** Total gzip size */
|
|
43
|
+
totalGzipSize: number;
|
|
44
|
+
/** Entry chunks size */
|
|
45
|
+
entrySize: number;
|
|
46
|
+
/** Dynamic chunks size (lazy loaded) */
|
|
47
|
+
dynamicSize: number;
|
|
48
|
+
/** Total load time for all chunks */
|
|
49
|
+
totalLoadTime: number;
|
|
50
|
+
/** Largest chunk */
|
|
51
|
+
largestChunk?: ChunkInfo;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Register a chunk
|
|
55
|
+
*/
|
|
56
|
+
export declare function registerChunk(info: ChunkInfo): void;
|
|
57
|
+
/**
|
|
58
|
+
* Update chunk status
|
|
59
|
+
*/
|
|
60
|
+
export declare function updateChunkStatus(name: string, status: ChunkInfo['status'], loadTime?: number): void;
|
|
61
|
+
/**
|
|
62
|
+
* Subscribe to bundle updates
|
|
63
|
+
*/
|
|
64
|
+
export declare function subscribeToBundles(callback: (chunks: ChunkInfo[], metrics: BundleMetrics) => void): () => void;
|
|
65
|
+
/**
|
|
66
|
+
* Get current bundle state
|
|
67
|
+
*/
|
|
68
|
+
export declare function getBundleState(): {
|
|
69
|
+
chunks: ChunkInfo[];
|
|
70
|
+
metrics: BundleMetrics;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Clear all tracked chunks
|
|
74
|
+
*/
|
|
75
|
+
export declare function clearBundleState(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Setup automatic chunk tracking via Performance API
|
|
78
|
+
*/
|
|
79
|
+
export declare function setupBundleTracking(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Generate HTML for the bundle panel
|
|
82
|
+
*/
|
|
83
|
+
export declare function renderBundlePanel(chunksList: ChunkInfo[], metrics: BundleMetrics): string;
|
|
84
|
+
/**
|
|
85
|
+
* CSS styles for the bundle panel
|
|
86
|
+
*/
|
|
87
|
+
export declare const bundlePanelStyles = "\n.flight-dt-bundle-panel {\n padding: 8px;\n}\n\n.flight-dt-bundle-summary {\n display: flex;\n gap: 16px;\n padding: 8px;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 6px;\n margin-bottom: 12px;\n}\n\n.flight-dt-bundle-breakdown {\n margin-bottom: 12px;\n}\n\n.flight-dt-breakdown-row {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n}\n\n.flight-dt-breakdown-label {\n width: 60px;\n font-size: 11px;\n color: #888;\n}\n\n.flight-dt-breakdown-bar {\n flex: 1;\n height: 8px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.flight-dt-breakdown-fill {\n height: 100%;\n border-radius: 4px;\n}\n\n.flight-dt-breakdown-fill--entry {\n background: #3b82f6;\n}\n\n.flight-dt-breakdown-fill--dynamic {\n background: #8b5cf6;\n}\n\n.flight-dt-breakdown-value {\n width: 70px;\n text-align: right;\n font-size: 11px;\n color: #888;\n font-family: monospace;\n}\n\n.flight-dt-chunks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.flight-dt-chunk {\n padding: 6px 8px;\n background: rgba(255, 255, 255, 0.03);\n border-radius: 4px;\n border-left: 2px solid #666;\n}\n\n.flight-dt-chunk--entry {\n border-left-color: #3b82f6;\n}\n\n.flight-dt-chunk--dynamic {\n border-left-color: #8b5cf6;\n}\n\n.flight-dt-chunk-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.flight-dt-chunk-name {\n font-family: monospace;\n font-size: 11px;\n color: #e0e0e0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 200px;\n}\n\n.flight-dt-chunk-size {\n font-family: monospace;\n font-size: 11px;\n color: #888;\n}\n\n.flight-dt-chunk-bar {\n height: 4px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.flight-dt-chunk-bar-fill {\n height: 100%;\n background: #22c55e;\n border-radius: 2px;\n}\n\n.flight-dt-chunk-time {\n font-size: 10px;\n color: #666;\n font-family: monospace;\n}\n\n.flight-dt-chunks-more {\n text-align: center;\n font-size: 11px;\n color: #666;\n padding: 8px;\n}\n";
|
|
88
|
+
//# sourceMappingURL=bundle-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle-panel.d.ts","sourceRoot":"","sources":["../src/bundle-panel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IAEb,gBAAgB;IAChB,GAAG,EAAE,MAAM,CAAC;IAEZ,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qBAAqB;IACrB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAEnD,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IAEjB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IAEnB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IAEpB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IAErB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAElB,sBAAsB;IACtB,aAAa,EAAE,MAAM,CAAC;IAEtB,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAElB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IAEpB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IAEtB,oBAAoB;IACpB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC5B;AAsCD;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAClB,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,GAChE,MAAM,IAAI,CAOZ;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI;IAC9B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;CAC1B,CAMA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CA8C1C;AAmCD;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,EAAE,aAAa,GACvB,MAAM,CAiER;AASD;;GAEG;AACH,eAAO,MAAM,iBAAiB,kzEAmI7B,CAAC"}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flight-framework/devtools - Bundle Panel
|
|
3
|
+
*
|
|
4
|
+
* Visualizes bundle composition within DevTools.
|
|
5
|
+
* Shows chunk breakdown, sizes, and loading status.
|
|
6
|
+
*/
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// State Management
|
|
9
|
+
// ============================================================================
|
|
10
|
+
const chunks = new Map();
|
|
11
|
+
const subscribers = new Set();
|
|
12
|
+
function notify() {
|
|
13
|
+
const chunksList = Array.from(chunks.values());
|
|
14
|
+
const metrics = calculateMetrics(chunksList);
|
|
15
|
+
for (const callback of subscribers) {
|
|
16
|
+
callback(chunksList, metrics);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function calculateMetrics(chunksList) {
|
|
20
|
+
const loaded = chunksList.filter(c => c.status === 'loaded');
|
|
21
|
+
const sorted = [...loaded].sort((a, b) => b.size - a.size);
|
|
22
|
+
return {
|
|
23
|
+
totalChunks: chunksList.length,
|
|
24
|
+
loadedChunks: loaded.length,
|
|
25
|
+
totalSize: chunksList.reduce((sum, c) => sum + c.size, 0),
|
|
26
|
+
totalGzipSize: chunksList.reduce((sum, c) => sum + (c.gzipSize || c.size * 0.3), 0),
|
|
27
|
+
entrySize: chunksList.filter(c => c.isEntry).reduce((sum, c) => sum + c.size, 0),
|
|
28
|
+
dynamicSize: chunksList.filter(c => c.isDynamic).reduce((sum, c) => sum + c.size, 0),
|
|
29
|
+
totalLoadTime: loaded.reduce((sum, c) => sum + (c.loadTime || 0), 0),
|
|
30
|
+
largestChunk: sorted[0],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Public API
|
|
35
|
+
// ============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* Register a chunk
|
|
38
|
+
*/
|
|
39
|
+
export function registerChunk(info) {
|
|
40
|
+
chunks.set(info.name, info);
|
|
41
|
+
notify();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Update chunk status
|
|
45
|
+
*/
|
|
46
|
+
export function updateChunkStatus(name, status, loadTime) {
|
|
47
|
+
const chunk = chunks.get(name);
|
|
48
|
+
if (!chunk)
|
|
49
|
+
return;
|
|
50
|
+
chunk.status = status;
|
|
51
|
+
if (loadTime !== undefined) {
|
|
52
|
+
chunk.loadTime = loadTime;
|
|
53
|
+
}
|
|
54
|
+
chunks.set(name, chunk);
|
|
55
|
+
notify();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to bundle updates
|
|
59
|
+
*/
|
|
60
|
+
export function subscribeToBundles(callback) {
|
|
61
|
+
subscribers.add(callback);
|
|
62
|
+
const chunksList = Array.from(chunks.values());
|
|
63
|
+
callback(chunksList, calculateMetrics(chunksList));
|
|
64
|
+
return () => subscribers.delete(callback);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get current bundle state
|
|
68
|
+
*/
|
|
69
|
+
export function getBundleState() {
|
|
70
|
+
const chunksList = Array.from(chunks.values());
|
|
71
|
+
return {
|
|
72
|
+
chunks: chunksList,
|
|
73
|
+
metrics: calculateMetrics(chunksList),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Clear all tracked chunks
|
|
78
|
+
*/
|
|
79
|
+
export function clearBundleState() {
|
|
80
|
+
chunks.clear();
|
|
81
|
+
notify();
|
|
82
|
+
}
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Auto-instrumentation
|
|
85
|
+
// ============================================================================
|
|
86
|
+
/**
|
|
87
|
+
* Setup automatic chunk tracking via Performance API
|
|
88
|
+
*/
|
|
89
|
+
export function setupBundleTracking() {
|
|
90
|
+
if (typeof window === 'undefined')
|
|
91
|
+
return;
|
|
92
|
+
// Track dynamically loaded scripts
|
|
93
|
+
const observer = new PerformanceObserver((list) => {
|
|
94
|
+
for (const perfEntry of list.getEntries()) {
|
|
95
|
+
const entry = perfEntry;
|
|
96
|
+
if (perfEntry.entryType === 'resource' && entry.initiatorType === 'script') {
|
|
97
|
+
const name = extractChunkName(perfEntry.name);
|
|
98
|
+
registerChunk({
|
|
99
|
+
name,
|
|
100
|
+
url: perfEntry.name,
|
|
101
|
+
size: entry.transferSize || entry.encodedBodySize || 0,
|
|
102
|
+
gzipSize: entry.encodedBodySize || undefined,
|
|
103
|
+
status: 'loaded',
|
|
104
|
+
loadTime: perfEntry.duration,
|
|
105
|
+
isEntry: isEntryChunk(perfEntry.name),
|
|
106
|
+
isDynamic: isDynamicChunk(perfEntry.name),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
observer.observe({ entryTypes: ['resource'] });
|
|
112
|
+
// Track already-loaded scripts
|
|
113
|
+
if (performance.getEntriesByType) {
|
|
114
|
+
const resources = performance.getEntriesByType('resource');
|
|
115
|
+
for (const entry of resources) {
|
|
116
|
+
if (entry.initiatorType === 'script') {
|
|
117
|
+
const name = extractChunkName(entry.name);
|
|
118
|
+
registerChunk({
|
|
119
|
+
name,
|
|
120
|
+
url: entry.name,
|
|
121
|
+
size: entry.transferSize || entry.encodedBodySize || 0,
|
|
122
|
+
gzipSize: entry.encodedBodySize || undefined,
|
|
123
|
+
status: 'loaded',
|
|
124
|
+
loadTime: entry.duration,
|
|
125
|
+
isEntry: isEntryChunk(entry.name),
|
|
126
|
+
isDynamic: isDynamicChunk(entry.name),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function extractChunkName(url) {
|
|
133
|
+
try {
|
|
134
|
+
const pathname = new URL(url).pathname;
|
|
135
|
+
const segments = pathname.split('/');
|
|
136
|
+
return segments[segments.length - 1] || pathname;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return url;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function isEntryChunk(url) {
|
|
143
|
+
const name = extractChunkName(url).toLowerCase();
|
|
144
|
+
return name.includes('index') || name.includes('entry') || name.includes('main');
|
|
145
|
+
}
|
|
146
|
+
function isDynamicChunk(url) {
|
|
147
|
+
const name = extractChunkName(url).toLowerCase();
|
|
148
|
+
return name.includes('chunk') || name.includes('async') || /[a-f0-9]{8}/.test(name);
|
|
149
|
+
}
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Panel Rendering
|
|
152
|
+
// ============================================================================
|
|
153
|
+
/**
|
|
154
|
+
* Format bytes for display
|
|
155
|
+
*/
|
|
156
|
+
function formatBytes(bytes) {
|
|
157
|
+
if (bytes < 1024)
|
|
158
|
+
return `${bytes} B`;
|
|
159
|
+
if (bytes < 1024 * 1024)
|
|
160
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
161
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generate HTML for the bundle panel
|
|
165
|
+
*/
|
|
166
|
+
export function renderBundlePanel(chunksList, metrics) {
|
|
167
|
+
const sortedChunks = [...chunksList].sort((a, b) => b.size - a.size);
|
|
168
|
+
// Calculate bar widths relative to largest chunk
|
|
169
|
+
const maxSize = metrics.largestChunk?.size || 1;
|
|
170
|
+
return `
|
|
171
|
+
<div class="flight-dt-bundle-panel">
|
|
172
|
+
<div class="flight-dt-bundle-summary">
|
|
173
|
+
<div class="flight-dt-metric">
|
|
174
|
+
<span class="flight-dt-metric-value">${formatBytes(metrics.totalSize)}</span>
|
|
175
|
+
<span class="flight-dt-metric-label">Total Size</span>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="flight-dt-metric">
|
|
178
|
+
<span class="flight-dt-metric-value">${formatBytes(metrics.totalGzipSize)}</span>
|
|
179
|
+
<span class="flight-dt-metric-label">Gzip Size</span>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="flight-dt-metric">
|
|
182
|
+
<span class="flight-dt-metric-value">${metrics.totalChunks}</span>
|
|
183
|
+
<span class="flight-dt-metric-label">Chunks</span>
|
|
184
|
+
</div>
|
|
185
|
+
<div class="flight-dt-metric">
|
|
186
|
+
<span class="flight-dt-metric-value">${metrics.totalLoadTime.toFixed(0)}ms</span>
|
|
187
|
+
<span class="flight-dt-metric-label">Load Time</span>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div class="flight-dt-bundle-breakdown">
|
|
192
|
+
<div class="flight-dt-breakdown-row">
|
|
193
|
+
<span class="flight-dt-breakdown-label">Entry</span>
|
|
194
|
+
<div class="flight-dt-breakdown-bar">
|
|
195
|
+
<div class="flight-dt-breakdown-fill flight-dt-breakdown-fill--entry"
|
|
196
|
+
style="width: ${(metrics.entrySize / metrics.totalSize) * 100}%"></div>
|
|
197
|
+
</div>
|
|
198
|
+
<span class="flight-dt-breakdown-value">${formatBytes(metrics.entrySize)}</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="flight-dt-breakdown-row">
|
|
201
|
+
<span class="flight-dt-breakdown-label">Dynamic</span>
|
|
202
|
+
<div class="flight-dt-breakdown-bar">
|
|
203
|
+
<div class="flight-dt-breakdown-fill flight-dt-breakdown-fill--dynamic"
|
|
204
|
+
style="width: ${(metrics.dynamicSize / metrics.totalSize) * 100}%"></div>
|
|
205
|
+
</div>
|
|
206
|
+
<span class="flight-dt-breakdown-value">${formatBytes(metrics.dynamicSize)}</span>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div class="flight-dt-chunks-list">
|
|
211
|
+
${sortedChunks.slice(0, 10).map(chunk => `
|
|
212
|
+
<div class="flight-dt-chunk ${chunk.isEntry ? 'flight-dt-chunk--entry' : ''} ${chunk.isDynamic ? 'flight-dt-chunk--dynamic' : ''}">
|
|
213
|
+
<div class="flight-dt-chunk-header">
|
|
214
|
+
<span class="flight-dt-chunk-name" title="${escapeHtml(chunk.url)}">${escapeHtml(chunk.name)}</span>
|
|
215
|
+
<span class="flight-dt-chunk-size">${formatBytes(chunk.size)}</span>
|
|
216
|
+
</div>
|
|
217
|
+
<div class="flight-dt-chunk-bar">
|
|
218
|
+
<div class="flight-dt-chunk-bar-fill" style="width: ${(chunk.size / maxSize) * 100}%"></div>
|
|
219
|
+
</div>
|
|
220
|
+
${chunk.loadTime ? `<span class="flight-dt-chunk-time">${chunk.loadTime.toFixed(0)}ms</span>` : ''}
|
|
221
|
+
</div>
|
|
222
|
+
`).join('')}
|
|
223
|
+
${sortedChunks.length > 10 ? `<div class="flight-dt-chunks-more">+ ${sortedChunks.length - 10} more chunks</div>` : ''}
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
${sortedChunks.length === 0 ? '<div class="flight-dt-empty">No chunks detected</div>' : ''}
|
|
227
|
+
</div>
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
function escapeHtml(str) {
|
|
231
|
+
return str
|
|
232
|
+
.replace(/&/g, '&')
|
|
233
|
+
.replace(/</g, '<')
|
|
234
|
+
.replace(/>/g, '>');
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* CSS styles for the bundle panel
|
|
238
|
+
*/
|
|
239
|
+
export const bundlePanelStyles = `
|
|
240
|
+
.flight-dt-bundle-panel {
|
|
241
|
+
padding: 8px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.flight-dt-bundle-summary {
|
|
245
|
+
display: flex;
|
|
246
|
+
gap: 16px;
|
|
247
|
+
padding: 8px;
|
|
248
|
+
background: rgba(255, 255, 255, 0.05);
|
|
249
|
+
border-radius: 6px;
|
|
250
|
+
margin-bottom: 12px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.flight-dt-bundle-breakdown {
|
|
254
|
+
margin-bottom: 12px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.flight-dt-breakdown-row {
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: center;
|
|
260
|
+
gap: 8px;
|
|
261
|
+
margin-bottom: 6px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.flight-dt-breakdown-label {
|
|
265
|
+
width: 60px;
|
|
266
|
+
font-size: 11px;
|
|
267
|
+
color: #888;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.flight-dt-breakdown-bar {
|
|
271
|
+
flex: 1;
|
|
272
|
+
height: 8px;
|
|
273
|
+
background: rgba(255, 255, 255, 0.1);
|
|
274
|
+
border-radius: 4px;
|
|
275
|
+
overflow: hidden;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.flight-dt-breakdown-fill {
|
|
279
|
+
height: 100%;
|
|
280
|
+
border-radius: 4px;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.flight-dt-breakdown-fill--entry {
|
|
284
|
+
background: #3b82f6;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.flight-dt-breakdown-fill--dynamic {
|
|
288
|
+
background: #8b5cf6;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.flight-dt-breakdown-value {
|
|
292
|
+
width: 70px;
|
|
293
|
+
text-align: right;
|
|
294
|
+
font-size: 11px;
|
|
295
|
+
color: #888;
|
|
296
|
+
font-family: monospace;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.flight-dt-chunks-list {
|
|
300
|
+
display: flex;
|
|
301
|
+
flex-direction: column;
|
|
302
|
+
gap: 6px;
|
|
303
|
+
max-height: 200px;
|
|
304
|
+
overflow-y: auto;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.flight-dt-chunk {
|
|
308
|
+
padding: 6px 8px;
|
|
309
|
+
background: rgba(255, 255, 255, 0.03);
|
|
310
|
+
border-radius: 4px;
|
|
311
|
+
border-left: 2px solid #666;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.flight-dt-chunk--entry {
|
|
315
|
+
border-left-color: #3b82f6;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.flight-dt-chunk--dynamic {
|
|
319
|
+
border-left-color: #8b5cf6;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.flight-dt-chunk-header {
|
|
323
|
+
display: flex;
|
|
324
|
+
justify-content: space-between;
|
|
325
|
+
align-items: center;
|
|
326
|
+
margin-bottom: 4px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.flight-dt-chunk-name {
|
|
330
|
+
font-family: monospace;
|
|
331
|
+
font-size: 11px;
|
|
332
|
+
color: #e0e0e0;
|
|
333
|
+
overflow: hidden;
|
|
334
|
+
text-overflow: ellipsis;
|
|
335
|
+
white-space: nowrap;
|
|
336
|
+
max-width: 200px;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.flight-dt-chunk-size {
|
|
340
|
+
font-family: monospace;
|
|
341
|
+
font-size: 11px;
|
|
342
|
+
color: #888;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.flight-dt-chunk-bar {
|
|
346
|
+
height: 4px;
|
|
347
|
+
background: rgba(255, 255, 255, 0.1);
|
|
348
|
+
border-radius: 2px;
|
|
349
|
+
overflow: hidden;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.flight-dt-chunk-bar-fill {
|
|
353
|
+
height: 100%;
|
|
354
|
+
background: #22c55e;
|
|
355
|
+
border-radius: 2px;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.flight-dt-chunk-time {
|
|
359
|
+
font-size: 10px;
|
|
360
|
+
color: #666;
|
|
361
|
+
font-family: monospace;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.flight-dt-chunks-more {
|
|
365
|
+
text-align: center;
|
|
366
|
+
font-size: 11px;
|
|
367
|
+
color: #666;
|
|
368
|
+
padding: 8px;
|
|
369
|
+
}
|
|
370
|
+
`;
|
|
371
|
+
//# sourceMappingURL=bundle-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle-panel.js","sourceRoot":"","sources":["../src/bundle-panel.ts"],"names":[],"mappings":"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"}
|