Lit 3.x 演进全解析:从 CHANGELOG 看 Lit 库的核心能力与破坏性变更
【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit
本篇技术指南以packages/lit/CHANGELOG.md为主体脉络,系统梳理 Lit 从 2.0 到 3.3 的完整演进历史。你将了解到:lit聚合包如何整合lit-html、lit-element与@lit/reactive-element三大底层库;3.x 系列引入的useDefault属性选项、mathml模板标签、ref/choose/when等指令的行为变化;以及 IE11 支持移除、SSR 能力增强等关键里程碑。阅读本文后,你能准确判断每个版本特性背后的实现原理,并据此规划升级路径与迁移策略。
说明:CHANGELOG 中的全部条目均可在 packages/lit/CHANGELOG.md 中核对原文;文中涉及的源码路径均来自本仓库,可作为深入阅读的起点。
一、lit 聚合包与版本发布机制
1.1 什么是 lit 包
lit包是整个 Lit 生态的统一入口,它在2.0.0版本(CHANGELOG 对应条目)正式发布,将原先分散使用的LitElement、ReactiveElement和lit-html整合到一个包中。从源码 packages/lit/src/index.ts 可以看到,它直接重导出了底层库的全部公开 API:
export * from 'lit-element/lit-element.js'; export * from 'lit-html/is-server.js';同时在模块顶部预导入@lit/reactive-element和lit-html,以便在未打包(unbundled)加载时避免额外的请求瀑布(waterfall,见源码注释 index.ts)。
当前仓库中 lit 包的版本为3.3.3(见 packages/lit/package.json),其依赖关系也印证了聚合包的定位:
| 依赖包 | 版本范围 | 说明 |
|---|---|---|
@lit/reactive-element | ^2.1.0 | 响应式属性、生命周期基座 |
lit-element | ^4.2.0 | 基于 ReactiveElement 的组件基类 |
lit-html | ^3.3.0 | 模板渲染引擎与指令体系 |
1.2 Changesets 自动化发布
CHANGELOG 末尾明确说明:3.0.0-rc.2之前的条目遵循 Keep a Changelog 格式人工维护,而此后(## 3.0.0-pre.0起的条目)全部由 Changesets 工具自动生成。这解释了为什么每个版本条目都带有 PR 编号、commit 哈希与贡献者致谢,格式高度统一。
二、Lit 3.x:现代化基线与大版本破坏性变更
3.0.0是 Lit 放弃旧浏览器支持、全面拥抱现代 Web 平台的里程碑。以下破坏性变更全部来自 CHANGELOG 3.0.0 小节:
2.1 放弃 IE11 支持
3.0.0正式移除了对 IE11 的支持(PR #3756)。这一决定使得 lit-html 可以简化属性处理逻辑:对符合标准的浏览器而言,属性按源码顺序迭代,因此 lit-html 简化了属性绑定处理(PR #3751);布尔属性部件改用toggleAttribute()实现(PR #3750);SVG 模板改用replaceWith()渲染(PR #3759)。这些简化意味着 Lit 3.x 的代码更精简、运行时开销更小,但也要求你的目标环境必须是现代浏览器。
2.2 响应式属性访问器自动请求更新
在 3.0.0 中,为响应式属性生成的访问器会自动包装用户自定义访问器,并在 setter 中自动调用this.requestUpdate()(PR #4146)。如果你仍需要完全掌控 setter 行为,可以设置noAccessor: true,此时必须自行在 setter 中调用this.requestUpdate()才能触发响应式更新。这是升级到 3.x 后最容易踩到的行为差异点之一。
2.3 移除实验性 hydrate 模块与废弃 API
- 实验性 hydrate 模块(
lit-html/experimental-hydrate.js、lit-element/experimental-hydrate-support.js)从主包移除,迁移至@lit-labs/ssr-client(PR #3765)。实际上早在 2.7.1 中这些模块就已被标记废弃并移动(见 CHANGELOG 2.7.1),3.0.0 只是完成最终清理。 - 删除
queryAssignedNodes的废弃行为与参数(PR #3850)。旧写法@queryAssignedNodes('list', true, '.item')应迁移为:
@queryAssignedElements({slot: '', flatten: false, selector: '.item'})ReactiveElement.renderRoot与createRenderRoot()的返回类型统一为HTMLElement | DocumentFragment,与 lit-html 的render()方法保持一致(PR #4254)。PropertyValues.get()的返回类型加入undefined(PR #3710);移除 Lit 1 → Lit 2 的迁移警告(PR #3762)。
2.4 异步 performUpdate 警告与类型系统升级
3.0.0 对异步覆盖performUpdate()的情况发出警告(PR #3896),避免开发者无意中破坏更新调度。同时将 TypeScript 升级至 ~5.2.0(PR #4141),并确保装饰器在experimentalDecorators: true时也能与accessor关键字协同工作(PR #4183)。随 3.0.0 一同发布的还有依赖包的大版本升级:@lit/reactive-element@2.0.0、lit-html@3.0.0、lit-element@4.0.0(见 CHANGELOG 依赖更新节)。
三、Lit 3.x 新增能力:useDefault 与 mathml
3.1useDefault属性选项(3.3.0)
3.3.0为响应式属性新增了useDefault选项(PR #4934),其行为在 reactive-element.ts 中有明确实现:
当设置
useDefault: true时,初始默认值不会被当作一次"变更",因此当同时设置reflect: true时,初始值不会反射到 DOM 属性;此外,当属性(attribute)被移除时,会恢复默认值。
源码层面,ReactiveElement 通过__defaultValuesMap 记录默认值(reactive-element.ts),并在属性变化判定中加入角力条件:当useDefault && reflect且新值等于默认值、而对应 attribute 尚未设置时,也视为一次变更(以触发反射)。useDefault的默认值为false(见 defaultPropertyDeclaration)。
@property({reflect: true, useDefault: true}) count = 0; // 初始 0 不会反射为 count="0";移除 count 属性后恢复为 0从源码注释(reactive-element.ts)可知:大多数需要反射到 attribute 的属性都建议使用useDefault: true,以避免初始值被意外反射。注意使用该选项时属性必须被初始化(字段初始化器或构造函数赋值均可)。
3.2mathml模板标签(3.2.0)
3.2.0新增了 MathML 支持,引入mathml模板标签(PR #4637)。在 lit-html.ts 中,html、svg、mathml三个标签函数并列定义,均基于各自的 result type(HTML_RESULT、SVG_RESULT、MATHML_RESULT)创建模板结果:
import {html, svg, mathml} from 'lit'; // 在 HTML 中嵌入 MathML 片段 render(mathml`<math><mi>x</mi></math>`, container);从源码结构看,mathml与svg定位类似,用于渲染独立命名空间下的标记片段。3.2.0 同时将 lit-html 升级至 3.2.0、lit-element 升级至 4.1.0(见 CHANGELOG 3.2.0)。
3.3 3.3.x 的其他修复
- 3.3.3:
ref指令在其内部 ref 为undefined时也能优雅断开(PR #5218)。 - 3.3.2:
ClassInfo变为可修改(PR #5044);修复带装饰器的标准私有访问器在变更检测中的 Bug(PR #4999)。 - 3.3.1:修复属性转换器回归——
fromAttribute现在可返回null或undefined(PR #4976);SSR 私有支持中避免指令类的重复 patch(PR #4988)。 - 3.3.0附带:修复初始 changed properties 值不一致(PR #4949);改为显式导入 barrels,兼容现代 Node 的 ESM 解析(PR #4956)。同步升级
@lit/reactive-element@2.1.0、lit-element@4.2.0、lit-html@3.3.0(见 CHANGELOG 依赖更新节)。
四、指令体系的演进与行为变更
CHANGELOG 中大量条目围绕指令(directive)展开,指令是 Lit 模板中处理动态值逻辑的核心机制。相关源码位于 packages/lit-html/src/directives/。
4.1ref指令:断开即清空(3.1.4 / 3.3.3)
ref指令用于在渲染期间获取元素引用。3.1.4起保证:当元素被断开(disconnected)时,ref()提供的值恒为undefined(PR #4646)。实现见 ref.ts:_updateRefValue在!this.isConnected时强制将元素置为undefined;disconnected()生命周期中会清空 ref 盒子(ref.ts),reconnected()时恢复。3.3.3进一步保证内部 ref 为undefined时也能优雅断开。
import {ref, createRef} from 'lit/directives/ref.js'; const inputRef = createRef(); render(html`<input ${ref(inputRef)}>`, container); // 元素断开后 inputRef.value 为 undefined配套能力:2.7.6允许向ref()传undefined(PR #3968),并将RefOrCallback泛型化(PR #3969);2.2.2修复了自动绑定的类方法作为回调时可能错误收到undefined的 Bug(PR #2691)。
4.2choose指令:类型推断收紧(3.0.1)
choose()是一个"无 fallthrough 的 switch 表达式"(choose.ts):按严格相等匹配value与 case,命中第一个即调用对应函数,否则执行可选默认分支:
${choose(this.section, [ ['home', () => html`<h1>Home</h1>`], ['about', () => html`<h1>About</h1>`], ], () => html`<h1>Error</h1>`)}3.0.1改进了类型推断,正确限制了从 value 推断出的 case 类型(PR #4240)。CHANGELOG 特别提示:如果升级后出现类型错误,说明存在不可达的 case 分支(应删除),或 value 的类型并集缺少某个合法 case。
4.3when指令:条件值作为回调参数(3.0.1)
when()是三元表达式的便捷包装(when.ts)。3.0.1起,when()会将提供的条件值作为参数传给 case 函数(PR #4310),从而基于真值性实现类型收窄:
${when(this.user, (u) => html`User: ${u.username}`, () => html`Sign In...`)}4.4 2.x 时代新增的指令
keyed(key, value)(2.1.0,PR #2337):key 变化时清空并重建 part。choose()(2.1.0,PR #2341):见上文。queryAssignedElements装饰器(2.1.0,PR #2327):声明式调用HTMLSlotElement.assignedElements(),selector选项支持 CSS 选择器过滤。asyncReplace修复(3.1.1,PR #4409):值未变化时正确重渲染。
4.5 指令相关的 Dev 模式警告
Lit 在开发构建(development build)中提供警告,帮助提前发现错误:
3.1.2:新增 DEV_MODE 错误,捕获重复的属性绑定,避免静默错误(PR #4523)。3.0.2:若在非静态html标签函数中检测到literal/unsafeStatic等静态值,发出警告——这些值只能用于从lit/static-html.js导入的静态html(PR #4345)。3.1.1:在 dev 模式警告直接将this.requestUpdate作为事件监听器绑定的写法(PR #4473)。3.3.0:dev 模式警告改为在包导入后的下一个微任务发出,为使用者提供更充分的抑制时机(PR #4901)。
五、SSR 能力的渐进增强
CHANGELOG 中 SSR 相关条目集中在 2.x 阶段,为 3.x 的稳定运行奠定了基础:
- 2.3.0(PR #3156):Lit 及其底层库可以在 Node 中直接导入而不崩溃,无需再加载
@lit-labs/ssr的 dom-shim。 - 2.6.0(PR #3522):Node 环境下 Lit 自动引入最小 DOM shims(来自新包
@lit-labs/ssr-dom-shim,导出HTMLElement、CustomElementRegistry与默认customElements单例),覆盖大多数 SSR 场景。仓库对应实现位于 packages/labs/ssr-dom-shim/src/。 - 2.7.0:SSR 渲染带内部(internals)的 Lit 元素时会反射 ARIA 属性,并在水合时移除(PR #3677);改进带绑定节点的 SSR 渲染,避免在
<textarea>等"原始文本元素"内插入注释(PR #3667,需@lit-labs/ssr与lit-html同步升级)。 isServer导出(2.4.0,PR #3318):lit包导出isServer变量,在 Node 中为true、浏览器中为false(实现见 is-server.ts)。可用于按环境编写组件逻辑;注意其生效前提是工具链支持"node"export condition。- 2.4.0同时为
lit包补充"types"export condition,使 TypeScript 的moduleResolution: "nodenext"可用(PR #3320)。
六、开发体验与包工程化改进
6.1 双构建产物:prod 与 development
2.5.0起(PR #3507),lit-html与reactive-element提供未压缩、带 dev 警告的 development 构建,用于浏览器开发调试。这在 packages/lit/package.json 的exports映射中清晰可见:每个导出入口的types均指向./development/index.d.ts,构建脚本build:ts通过 tsc 产出development/目录,build:ts:types用 treemirror 将.d.ts镜像到包根(见 package.json wireit 配置)。
6.2 导出映射与模块解析的持续修正
2.0.0-rc.4:将package.json的exports字段从已废弃的"子路径文件夹映射"语法(/后缀)改为显式逐文件列表,要求用户按扩展名导入(PR #2103)。2.2.8:为各模块补充"types"导出条目(PR #3132)。2.2.3:强制在导入中使用文件扩展名,兼容旧版 TypeScript 编译器(PR #2732)。3.1.2:为带"node"export condition 的包补充"browser"条件入口,修复 Node 测试运行器模拟浏览器环境时错误加载"node"入口的问题(PR #4485)。3.2.1:将 Rollup 压缩插件回退为rollup-plugin-terser,因为@rollup/plugin-terser的 Bug 破坏了压缩名称前缀机制(PR #4782)。2.2.3起 npm 发布不再包含src/目录与测试文件(PR #1964、PR #3871),减小包体积。
6.3 安全加固
2.7.6(PR #3987):CompiledTemplate的h字段改为TemplateStringsArray类型,防止通过 JSON 注入伪造CompiledTemplate。2.2.2(PR #2642):为StaticValues增加额外的安全品牌检查;2.2.2(PR #2646)同时警告:绕过模板字符串数组品牌检查的行为可能引入安全漏洞。
七、装饰器与生命周期修复汇总
CHANGELOG 中与装饰器、生命周期相关的修复值得关注:
@query缓存 Bug(3.1.0,PR #4282):带cache标志的@query字段在首次更新前访问时,不再永久缓存null,且 DEV_MODE 下会发出警告。@query类型放宽(3.0.1,PR #4284):允许null出现在@query()装饰字段的类型中。- 控制器生命周期隔离(3.1.0,PR #4388):在响应式控制器生命周期中新增/移除控制器,不再影响其他控制器的执行。
renderRoot保障(3.1.0,PR #4387):确保首次更新前renderRoot已存在。- 属性转换器回归修复(3.3.1,PR #4976):
fromAttribute可返回null或undefined。 - 自定义转换器
this绑定(2.3.0,PR #3120):为自定义属性转换器方法绑定this。 - 子类初始化器隔离(2.4.1,PR #3374):子类新增的初始化器不再被错误添加到父类。
requestUpdate()内部参数清理(3.1.1,PR #4413):移除未使用的内部参数。- 标准私有访问器变更检测(3.3.2,PR #4999):修复带装饰器的标准私有访问器的变更检测。
八、升级路线与迁移建议
综合 CHANGELOG 的版本脉络,给出以下可操作的升级建议:
- 从 2.x 升级到 3.x 前,先确认目标环境不含 IE11;检查是否仍在导入
experimental-hydrate模块(应改用@lit-labs/ssr-client);将@queryAssignedNodes('list', true, '.item')迁移为@queryAssignedElements({slot: '', flatten: false, selector: '.item'});若自定义了属性访问器,确认是否需要noAccessor: true并自行调用requestUpdate()。 - 升级后开启 dev 模式,借助 duplicate attribute binding、静态值误用、异步
performUpdate、requestUpdate作事件监听器等新警告快速定位潜在问题。 - 新代码优先采用 3.3.x 能力:为需要反射的属性启用
useDefault: true;渲染数学公式时使用mathml模板标签;使用when/choose的窄化回调参数获得更好的类型安全。 - SSR 场景:确认工具链支持
"node"/"types"export condition,以便isServer与nodenext模块解析正确工作。
参考路径
- 变更日志原文:packages/lit/CHANGELOG.md
- 聚合包入口:packages/lit/src/index.ts、packages/lit/package.json
- 响应式属性与生命周期:packages/reactive-element/src/reactive-element.ts
- 模板标签(html/svg/mathml):packages/lit-html/src/lit-html.ts
- 指令实现:packages/lit-html/src/directives/
- SSR DOM shim:packages/labs/ssr-dom-shim/src/
【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考