@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 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, '&amp;')
233
+ .replace(/</g, '&lt;')
234
+ .replace(/>/g, '&gt;');
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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"}