chrome-devtools-frontend
Version:
Chrome DevTools UI
138 lines (102 loc) • 8.14 kB
Markdown
---
name: ui-eng-vision-local-lit-renderer
description: Migrates legacy imperative DOM construction to local declarative Lit-html templates rendered inside existing containers.
allowed-tools: code_search open_urls
---
# Subskill: Local Lit-HTML Renderer (Pass 2)
This subskill converts consolidated imperative DOM construction helper methods
into reactive, declarative Lit-html templates, rendering them locally inside the
existing element containers.
--------------------------------------------------------------------------------
## 1. Declarative Technology Migration
1. **Conserve Abstraction Topology**:
* Maintain the existing class hierarchy, helper class boundaries, and
logical groups.
* Do not aggressively "flatten" classes or collapse helper abstractions
into the main view just to coerce a single master template. Pass 2
should only change the *implementation details* of rendering (imperative
-> declarative) within existing compartments, not the public API or
responsibilities of objects.
2. **Determine Render Lifecycle per Layer**:
* **For UI.Widget classes**: Define or update `performUpdate()` to execute
the main lit `render` call, and use `this.requestUpdate()` to queue
updates.
* **For Delegate/Helper classes**: Identify the custom update hook (e.g.,
`update()` or `scheduleUpdate()`) and invoke `render()` directly inside
that method. **Do not** introduce Widget lifecycle methods
(`performUpdate`) on classes that do not inherit them.
3. **Import Modern Templating**:
* Import the `Lit` rendering system inside the view module:
```typescript
import {html, render, nothing} from '../../ui/lit/lit.js';
```
4. **Modern Component Mapping**:
* **MANDATORY**: You **MUST** read and load [ui_engineering.md](../../../docs/ui_engineering.md) first to understand specific component mappings (e.g., Toolbar vs `devtools-toolbar`). Do not assume standard Lit defaults.
* If unsure, also consult the [automatic migration code](../../../scripts/eslint_rules/lib/no-imperative-dom-api.ts)
* **Prefer Component Built-Ins Over Legacy Boilerplate**: Before porting
legacy event handlers, comparators, or state variables, check if the
modern component handles them natively. Drop host-level workarounds in
favor of declarative component attributes.
5. **Local Modular Renders**:
* If the class contains multiple separate legacy container fields (e.g.,
fields generated by `appendField` or `createChild` on a parent layout),
prefer **local modular renders** (rendering templates individually into
each container) to preserve the legacy layout framework. Do not force a
monolithic template if doing so violates the existing topology.
6. **Resolve TypeScript Type Friction**:
* Legacy DevTools elements may be typed as `Element`. Lit's `render()`
function expects `HTMLElement | DocumentFragment`.
* When rendering into legacy containers, cast the container using `as
HTMLElement` or update its class property type definition from `Element`
to `HTMLElement` to satisfy the TypeScript compiler.
* Example: `render(this.template(), this.containerField as HTMLElement);`
7. **Delegate to Unmigrated Rendering Engines**:
* Do not attempt to rewrite complex historical subsystems (like Linkifiers
or specialized UI utilities) to be "pure Lit" during this pass.
* Capitalize on Lit's ability to interpolate standard `HTMLElement` or `Element` instances directly. Treat unmigrated utilities as "black boxes" that generate DOM, and embed their output in standard template expressions: `html`<div>${this.legacyElement}</div>``.
* **CRITICAL:** Before treating any component as "unmigrated," you MUST follow steps in Section 4. You are only allowed to use this escape hatch if no declarative migration instructions exist.
8. **Handle Asynchronous DOM Updates**:
* For asynchronous callback-driven updates (e.g., elements updated in a
`.then()` callback), render the parent container or a placeholder
template first. Once the data is retrieved, execute a local `render()`
inside the callback targeting the specific sub-container.
9. **Template Factorization Strategies**:
* **Prefer `nothing`**: Use Lit's `nothing` sentinel instead of empty
strings `''` or empty templates for conditional rendering.
* **Parameterized Fragment Factories**: For repeated UI patterns or
intermediate layout branches, extract them into parameterized helper
functions inside the class scope returning `LitTemplate`. This avoids
monoliths, preserves readability, and reuses template cache strategies.
10. **Visual Parity, CSS Adaptation, and Accessibility**:
* **Zero-Tolerance Regression**: Screenshot tests are the ground truth for this phase. Any visual diff (above 0%) in the generated screenshots is unacceptable and must be resolved before proceeding.
* **CSS Selector Migration**: When replacing legacy imperative components/widgets with modern web components (e.g., replacing legacy `DataGrid` with `<devtools-data-grid>`), inspect and update the associated `.css` file. Replace legacy class selectors (`.data-grid`) with tag selectors (`devtools-data-grid`).
* **Strict Tag/Class Parity**: Do not change tag types (e.g., `span` to
`div`) or drop class names during template translation, as CSS may
depend on them.
* **Explicit Component Variants**: Modern Custom Element (e.g.
`<devtools-button>`) defaults may not match legacy appearance.
Explicitly bind `.data=${{variant: Buttons.Button.Variant.OUTLINED}}`
(or appropriate variant) rather than relying on defaults.
* **Accessibility Preservation**: Convert custom accessibility
instrumentation (like `ARIAUtils.markAsAlert()`) to native ARIA
attributes in the template (e.g., `role="alert"`, `aria-live="polite"`).
11. **Render Templates Syntax & Code Movement**:
* Surround the expressions containing lit template literals with `//
clang-format off` and `// clang-format on` to prevent clang-format from
corrupting template indentation.
* **Minimize Code Movement**: Avoid moving existing code to a different location in the file. Put the function signature around the existing code to minimize the diff.
* The Gerrit Code Review UI cannot identify moved blocks of unchanged code.
* If blocks of code need to be reordered, create a "prefactoring" change that first extracts the code that needs to be reordered into a named helper functions and pause the migration, waiting user confirmation.
12. **Micro-Commit Strategy**:
* Do not attempt to convert every helper method and UI component in a single monolithic commit. Break the template extraction into **small, self-contained micro-commits** (e.g., migrating one helper method, toolbar button, or list item render at a time).
* Verify with build and run tests after each micro-commit to guarantee zero regressions and 100% visual parity before moving to the next compartment.
* Provide the exact list of files and commit message when presenting progress so the change history remains atomic and easy to review.
13. **Wait for confirmation**:
* Wait for an explicit confirmation from the user (or Parent Orchestrator Agent) before proceeding to the next step.
--------------------------------------------------------------------------------
## 🔍 Mental Audit (Internal Self-Correction)
*Before reporting back or committing, re-read the instructions and verify:*
1. ❓ **Tag Parity**: Did I accidentally change any `span` to `div` (or vice versa)?
2. ❓ **Attribute Drop**: Did I drop any `aria-*`, `role`, or custom data attributes?
3. ❓ **Clang-Off Boundary**: Is the template wrapped in `// clang-format off`?
4. ❓ **Build**: Does the code compile and do visual tests pass with 0% diff?