ui-eng-vision-local-lit-renderer
GitHub将遗留的指令式DOM构建迁移为本地声明式Lit-html模板,在现有容器内渲染。
Trigger Scenarios
Install
npx skills add ChromeDevTools/devtools-frontend --skill ui-eng-vision-local-lit-renderer -g -y
SKILL.md
Frontmatter
{
"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
-
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.
-
Determine Render Lifecycle per Layer:
- For UI.Widget classes: Define or update
performUpdate()to execute the main litrendercall, and usethis.requestUpdate()to queue updates. - For Delegate/Helper classes: Identify the custom update hook (e.g.,
update()orscheduleUpdate()) and invokerender()directly inside that method. Do not introduce Widget lifecycle methods (performUpdate) on classes that do not inherit them.
- For UI.Widget classes: Define or update
-
Import Modern Templating:
-
Import the
Litrendering system inside the view module:import {html, render, nothing} from '../../ui/lit/lit.js';
-
-
Modern Component Mapping:
- MANDATORY: You MUST read and load 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
- 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.
- MANDATORY: You MUST read and load ui_engineering.md first to understand specific component mappings (e.g., Toolbar vs
-
Local Modular Renders:
- If the class contains multiple separate legacy container fields (e.g.,
fields generated by
appendFieldorcreateChildon 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.
- If the class contains multiple separate legacy container fields (e.g.,
fields generated by
-
Resolve TypeScript Type Friction:
- Legacy DevTools elements may be typed as
Element. Lit'srender()function expectsHTMLElement | DocumentFragment. - When rendering into legacy containers, cast the container using
as HTMLElementor update its class property type definition fromElementtoHTMLElementto satisfy the TypeScript compiler. - Example:
render(this.template(), this.containerField as HTMLElement);
- Legacy DevTools elements may be typed as
-
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
HTMLElementorElementinstances directly. Treat unmigrated utilities as "black boxes" that generate DOM, and embed their output in standard template expressions:html${this.legacyElement}``. - 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.
-
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 localrender()inside the callback targeting the specific sub-container.
- For asynchronous callback-driven updates (e.g., elements updated in a
-
Template Factorization Strategies:
- Prefer
nothing: Use Lit'snothingsentinel 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.
- Prefer
-
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
DataGridwith<devtools-data-grid>), inspect and update the associated.cssfile. Replace legacy class selectors (.data-grid) with tag selectors (devtools-data-grid). - Strict Tag/Class Parity: Do not change tag types (e.g.,
spantodiv) 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").
-
Render Templates Syntax & Code Movement:
- Surround the expressions containing lit template literals with
// clang-format offand// clang-format onto 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.
- Surround the expressions containing lit template literals with
-
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.
-
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:
- ❓ Tag Parity: Did I accidentally change any
spantodiv(or vice versa)? - ❓ Attribute Drop: Did I drop any
aria-*,role, or custom data attributes? - ❓ Clang-Off Boundary: Is the template wrapped in
// clang-format off? - ❓ Build: Does the code compile and do visual tests pass with 0% diff?
Version History
- 678d19c Current 2026-08-20 15:20


