| name | webui-lit-migration |
| description | Guide for migrating Chromium WebUI components from Polymer to Lit. Activate this skill if the user asks to migrate a file or component to Lit. |
Chromium WebUI Lit Migration
Step 1: Run scripts/run_codemod_script.sh
IMPORTANT: Always do this first, as it automates trivial migration steps.
Run the script in this skill's scripts directory. Pass the path to the Polymer
based element's TS class definition file as the parameter. Example:
./webui-lit-migration/scripts/run_codemod_script.sh
chrome/browser/resources/certificate_manager/certificate_entry.ts
Step 2: .ts file cleanup
-
Replace PolymerElement import The script replaces this import except in cases
where multiple things are imported from Polymer. If an import from
polymer_bundled.min.js is still present after running the script, remove it
and add: import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js';
-
Update 'extends PolymerElement' The script will update this in the case that
no mixins are used. If there is still a reference to PolymerElement: replace
SomeMixin(PolymerElement) with SomeMixinLit(CrLitElement)
-
Address any "TODO: Port this observer to Lit" comments left by the migration
script as follows: a. Examine the observer (e.g. 'onFooChanged_') method. If
it does not reference the DOM, add the following in a willUpdate callback. If
it does reference the DOM (e.g., this.shadowRoot or this.$), add this in a
updated() lifecycle callback instead.
if (changedProperties.has('foo')) {
this.onFooChanged_();
}
b. If the property being observed is protected or private, the
changedProperties lifecycle method parameter will require a cast:
const changedPrivateProperties = changedProperties as Map<PropertyKey, unknown>;
if (changedPrivateProperties.has('myProperty_')) { ... }
c. Remove the added TODO and the commented out observer line.
- Address any complex observers in a similar way. Look for an "observers: "
line:
observers: ['onFooOrBarChanged_(foo, bar)']
Remove the line and for each observer listed, add to a lifecycle method as
described for single property observers, but check changedProperties for any of
the properties listed in the observer:
if (changedProperties.has('foo') || changedProperties.has('bar')) {
this.onFooOrBarChanged_();
}
- Move value initialization out of 'properties' to the declaration.
Replace
foo: {
type: String,
value: 'foo',
},
...
value: string;
with
foo: {
type: String,
},
...
accessor value: string = 'foo';
For uninitialized properties, if a TS compiler error is thrown on build,
initialize to a dummy or default value rather than using a non-null assertion
operator or changing the type definition.
Step 3: Check for any missing shared CSS styles.
If any imported style file does not exist, check if the Polymer version (same
file path, but without _lit suffix) exists. If so, generate the Lit version as
follows:
- Create Lit Version: Create
[shared_style]_style_lit.css.
- Copy Content: Copy the CSS rules to the new
*_lit.css file.
- Update Metadata: Use
#type=style-lit in the metadata. Update any
imported and included styles to the lit version (e.g. cr_shared_style.css.js
import --> cr_shared_style_lit.css.js import, include="cr-shared-style"
becomes include="cr-shared-style-lit").
- Empty Original: Clear the original
*_style.css file, leaving only its]
metadata header and a comment:
- Import in Component: Component CSS should import the new
*_lit.css.js
and include it.
- BUILD.gn: Add the new
*_lit.css to css_files.
Step 4: Update .html.ts template file
- Replace any