You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
chore: Store all macro data on the client (adobe#9771)
* Store all macro debug data in the app
* encode the data for css storage
* fix encodings
* fix memory leak, streamline look up, disable globals in tests
@@ -61,26 +61,21 @@ This extension uses Chrome's standard extension architecture with three main com
61
61
-**Location**: Runs in the actual page's JavaScript context
62
62
-**Responsibility**:
63
63
- Generates macro metadata (hash, location, styles) when style macro is evaluated
64
-
- Hosts MutationObserver that watches selected element for className changes
65
-
-**Storage**: None - static macros embed data in CSS, dynamic macros send messages
66
-
-**Communication**:
67
-
- For static macros: Embeds data in CSS custom property `--macro-data-{hash}` (unique per macro)
68
-
- For dynamic macros: Sends `window.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to content script
69
-
- For className changes: Sends `window.postMessage({ action: 'stylemacro-class-changed', elementId })` to content script
64
+
- Hosts MutationObserver (created by dev tool panel) that watches selected element for className changes
65
+
-**Storage**:
66
+
- Static macros: Data embedded in CSS rules with custom property `--macro-data-{hash}`
67
+
- Dynamic macros: Data stored in global `window.__styleMacroDynamic__` (object with `map` of class name → `{ style, loc }` and an internal interval timer for cleanup)
70
68
71
69
#### 2. **Content Script** (`content-script.js`)
72
70
-**Location**: Isolated sandboxed environment injected into the page
73
71
-**Scope**: Acts as a message forwarder between page and extension
74
72
-**Responsibility**:
75
-
- Listens for `window.postMessage({ action: 'stylemacro-update-macros' })` from the page and forwards to background script
76
-
- Forwards `window.postMessage({ action: 'stylemacro-class-changed' })` from page to background script
77
-
-**Storage**: None - all macro data is stored in DevTools
73
+
- Forwards `window.postMessage({ action: 'stylemacro-class-changed' })` from Mutation Observer on page to background script
74
+
-**Storage**: None - all macro data is stored in the DOM via CSS custom properties
78
75
-**Communication**:
79
76
- Receives:
80
-
-`window.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from page
81
77
-`window.postMessage({ action: 'stylemacro-class-changed', elementId })` from page
82
78
- Sends:
83
-
-`chrome.runtime.sendMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to background
84
79
-`chrome.runtime.sendMessage({ action: 'stylemacro-class-changed', elementId })` to background
85
80
86
81
#### 3. **Background Script** (`background.js`)
@@ -91,23 +86,19 @@ This extension uses Chrome's standard extension architecture with three main com
91
86
- Receives:
92
87
-`chrome.runtime.onConnect({ name: 'devtools-page' })` from DevTools
93
88
-`port.onMessage({ type: 'stylemacro-init' })` from DevTools
94
-
-`chrome.runtime.onMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from content script
95
89
-`chrome.runtime.onMessage({ action: 'stylemacro-class-changed', elementId })` from content script
96
90
- Sends:
97
-
-`port.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to DevTools
98
91
-`port.postMessage({ action: 'stylemacro-class-changed', elementId })` to DevTools
99
92
100
93
#### 4. **DevTools Panel** (`devtool.js`)
101
94
-**Location**: DevTools sidebar panel context
102
95
-**Responsibility**:
103
-
- Stores all dynamic macro data in a local Map: `macroData[hash] = { loc, style }`
104
96
- Extracts macro class names from selected element:
- Dynamic macros: `-macro-dynamic-{hash}` → looks up data from local storage
97
+
- Static macros: `-macro-static-{hash}` → reads `--macro-data-{hash}` custom property via `getComputedStyle()` on the element
98
+
- Dynamic macros: `-macro-dynamic-{hash}` → reads from `window.__styleMacroDynamic__.map["-macro-dynamic-{hash}"]` (plain JSON)
107
99
- Displays style information in sidebar
108
100
-**Automatic Updates**: Sets up a MutationObserver on the selected element to detect className changes and automatically refreshes the panel
109
-
-**Cleanup**: Every 5 minutes, checks the DOM for each stored hash and removes data for macros that no longer exist
110
-
-**Storage**: `Map<hash, {loc: string, style: object}>` - stores all dynamic macro data
101
+
-**Storage**: None - all data is read from CSS custom properties on demand
111
102
-**Mutation Observer**:
112
103
- Created when an element is selected via `chrome.devtools.panels.elements.onSelectionChanged`
113
104
- Watches the selected element's `class` attribute for changes
@@ -117,7 +108,6 @@ This extension uses Chrome's standard extension architecture with three main com
117
108
- Triggers automatic panel refresh when className changes
118
109
-**Communication**:
119
110
- Receives:
120
-
-`port.onMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from background (stores data and refreshes)
121
111
-`port.onMessage({ action: 'stylemacro-class-changed', elementId })` from background (triggers refresh)
122
112
- Sends:
123
113
-`chrome.runtime.connect({ name: 'devtools-page' })` to establish connection
@@ -149,156 +139,51 @@ Static macros are generated when style macro conditions don't change at runtime.
149
139
150
140
**Key Design**: Each static macro has its own uniquely-named custom property (`--macro-data-{hash}`), which avoids CSS cascade issues when reading multiple macro data from the same element.
#### Flow 1b: Dynamic Macro Updates (Page → Global Variable)
153
143
154
-
Dynamic macros are generated when style macro conditions can change at runtime. Updates are sent via message passing and stored directly in DevTools.
144
+
Dynamic macros are generated when style macro conditions can change at runtime. Data is written to a global JavaScript variable; a timer on the same object cleans up entries whose class is no longer present in the DOM.
│ │ Dynamic: window.__styleMacroDynamic__.map["-macro-dynamic-{hash}"] → already { style, loc }
191
173
└────────┬────────┘
192
-
│ { loc: "...", style: {...} } or null
174
+
│
193
175
↓
194
176
┌─────────────────┐
195
-
│ DevTools Panel │ Display in sidebar (or show nothing if null)
177
+
│ DevTools Panel │ Parses and displays in sidebar
196
178
└─────────────────┘
197
179
```
198
180
199
-
**Note**: If macro data hasn't been received yet for a hash, it will appear empty until the next `stylemacro-update-macros` message arrives and triggers a refresh.
181
+
**Note**: Static macros are read from CSS custom properties on the inspected element. Dynamic macros are read from the page’s global `window.__styleMacroDynamic__.map` (no CSS involved).
200
182
201
-
#### Flow 3: Macro Data Cleanup (Automated)
202
-
203
-
Every 5 minutes, DevTools checks if stored macro hashes are still in use on the page and removes stale data.
│ DevTools Panel │ Verifies elementId matches currently selected element
276
-
│ │ Triggers full panel refresh (re-reads classes, re-queries macros)
277
-
└─────────────────┘
278
-
279
-
When selection changes or panel closes:
280
-
↓
281
-
┌─────────────────┐
282
-
│ DevTools Panel │ Calls disconnectObserver()
283
-
└────────┬────────┘
284
-
│ chrome.devtools.inspectedWindow.eval(`
285
-
│ if (window.__styleMacroObserver) {
286
-
│ window.__styleMacroObserver.disconnect();
287
-
│ window.__styleMacroObserver = null;
288
-
│ }
289
-
│ `)
290
-
↓
291
-
┌─────────────────┐
292
-
│ Page DOM │ Old observer disconnected, new observer created for new selection
293
-
└─────────────────┘
294
-
```
295
-
296
-
**Key Benefits:**
297
-
- Panel automatically refreshes when element classes change (e.g., hover states, conditional styles)
298
-
- No manual refresh needed
299
-
- Observer is cleaned up properly to prevent memory leaks
300
-
- Each element has its own unique tracking ID to prevent cross-contamination
301
-
302
187
### Key Technical Details
303
188
304
189
#### Why Background Script is Needed
@@ -310,64 +195,47 @@ The style macro generates different class name patterns based on whether the sty
310
195
311
196
**Static Macros** (`-macro-static-{hash}`):
312
197
- Used when all style conditions are static (e.g., `style({ color: 'red' })`)
313
-
- Macro data is embedded in CSS as a uniquely-named custom property: `--macro-data-{hash}: '{...JSON...}'`
198
+
- Macro data is embedded in CSS rules as a uniquely-named custom property: `--macro-data-{hash}: '{...JSON...}'`
314
199
- DevTools reads the specific custom property via `getComputedStyle($0).getPropertyValue('--macro-data-{hash}')`
315
-
- Unique naming avoids CSS cascade issues when multiple macros are applied to the same element
316
200
317
201
**Dynamic Macros** (`-macro-dynamic-{hash}`):
318
202
- Used when style conditions can change (e.g., `style({color: {default: 'blue', isActive: 'red'}})`)
319
-
- Macro data is sent via `window.postMessage({ action: 'stylemacro-update-macros', ... })` whenever conditions change
320
-
- Content script forwards data to DevTools, which stores it in a local Map
203
+
- Macro data is stored in `window.__styleMacroDynamic__.map["-macro-dynamic-{hash}"]` as plain JSON `{ style, loc }`
204
+
- A timer on `window.__styleMacroDynamic__` periodically removes map entries whose class is no longer used in the DOM
205
+
- DevTools reads via `window.__styleMacroDynamic__.map["-macro-dynamic-{hash}"]`
321
206
- Enables real-time updates when props/state change
322
207
323
-
#### Data Storage
324
-
-**Static Macros**: Data embedded in CSS as uniquely-named custom properties `--macro-data-{hash}`, read via `getComputedStyle($0).getPropertyValue('--macro-data-{hash}')`
325
-
- Each macro has its own custom property name to prevent cascade conflicts
0 commit comments