- 开发工具
- 格式化
- CLI
【免费下载链接】prettier
Prettier is an opinionated code formatter.
Prettier 3.8.0 的发布主题是紧跟 Angular v21.1(与该版本同日发布)带来的全新模板语法能力:连续@case语句、模板中数组/对象字面量与函数调用里的展开元素(spread elements),以及 Markdown 代码块内的 Angular 语法格式化。本篇文章以 官方 3.8.0 发布公告 为骨架,结合仓库源码逐条剖析这些能力的实现原理、行为变化与使用方式,帮助你快速理解升级到 Prettier 3.8 后 Angular 与 Markdown 格式化行为的变化。
导读
对使用 Angular 21 及更高版本的开发者来说,Prettier 3.8 是一次必须了解的升级:它修复了@switch块中连续@case语句直接报SyntaxError的问题,补齐了模板表达式内 spread 语法的规范化输出,同时把 Angular 的格式化能力延伸进了 Markdown 代码块(angular-ts、angular-html)。读完本文,你将掌握这些新特性的触发条件、格式化前后行为对比,以及对应的源码实现位置,方便在实际项目中验证与排查。
升级背景:Prettier 与 Angular v21.1 的同步节奏
官方公告明确指出,Prettier 3.8 的目标是“完全支持 Angular v21.1 中刚刚落地的全新特性”。Angular 的模板语法从 v17 引入基于@前缀的控制流块(@if、@for、@switch)以来一直在快速演进,v21.1 又新增了两类写法:
@switch块中连续堆叠的@case语句(fallthrough case,多个条件共享同一个分支体);- 模板表达式中数组字面量、对象字面量与函数调用参数里的展开元素(
...)。
在 Prettier 3.7 及更早版本中,前者会直接抛出解析错误,后者则会被“原样保留”而不做任何规范化。3.8 通过升级底层angular-html-parser并调整打印逻辑(打印实现),让这些写法既能被正确解析,也能输出为符合 Prettier 风格规范的格式。
亮点一:@switch 块中连续 @case 语句的支持
格式化前后对比
官方公告给出了完整的输入/输出示例(发布公告):
<!-- Input --> @switch (userRole) { @case ('admin') @case ('moderator') { <p>Welcome, boss! Full access.</p> } @case ('user') { <p>Standard access</p> } @default { <p>Guest view</p> } } <!-- Prettier 3.7 --> SyntaxError: Incomplete block "case". If you meant to write the @ character, you should use the "@" HTML entity instead. (2:3) <!-- Prettier 3.8 --> @switch (userRole) { @case ("admin") @case ("moderator") { <p>Welcome, boss! Full access.</p> } @case ("user") { <p>Standard access</p> } @default { <p>Guest view</p> } }这里有两个值得注意的行为变化:
- 解析层面:3.7 中连续两个
@case(第一个不带块体)被当作“未闭合的块”直接报错,错误信息还提示将@转义为@HTML 实体;3.8 起这样的连续 case 写法是合法的。 - 输出层面:单引号字符串被规范化为双引号(
'admin'→"admin"),@case ('user') { ... }这类单行写法会被展开成块级格式,@default同样获得统一的块状缩进。
源码实现:isSwitchFallthroughCase
连续@case支持的核心逻辑位于 angular-control-flow-block.js:
const isSwitchCaseBlock = (node) => node?.kind === "angularControlFlowBlock" && (node.name === "case" || node.name === "default"); function isSwitchFallthroughCase(node) { return ( isSwitchCaseBlock(node) && node.endSourceSpan && node.endSourceSpan.start.offset === node.endSourceSpan.end.offset ); }当一个@case/@default节点的endSourceSpan起始与结束偏移相同(即该 case 语句本身不携带块体)时,它就被判定为 fallthrough case。打印函数 printAngularControlFlowBlock 对这类节点不输出{块体,而是让后续同层 case 直接衔接;同时 isPreviousBlockUnClosed 负责判断前一个 case 是否“未闭合”(fallthrough),从而决定当前节点输出前是否补上}。相邻 case 最终会被合并到同一个group中输出,配合shouldBreak: true保证每个 case 独占一行。
亮点二:模板中展开元素(Spread)的规范化
格式化前后对比
官方公告提供了组件属性绑定的示例(发布公告):
<!-- Input --> <MyComponent [array]="[ ...foo, ...bar]" [object]="{...bar, ...extra }" [call]="call( ...baz)" /> <!-- Prettier 3.7 --> <MyComponent [array]="[ ...foo, ...bar]" [object]="{...bar, ...extra }" [call]="call( ...baz)" /> <!-- Prettier 3.8 --> <MyComponent [array]="[...foo, ...bar]" [object]="{ ...bar, ...extra }" [call]="call(...baz)" />3.7 中这些表达式中的多余空白被原样保留,3.8 则会输出规范格式:
- 数组字面量:
[ ...foo, ...bar]→[...foo, ...bar],去掉[后的多余空格; - 对象字面量:
{...bar, ...extra }→{ ...bar, ...extra },对象括号内侧保留一个空格; - 函数调用:
call( ...baz)→call(...baz),参数括号内不留空格。
源码实现:复用 JS 的 SpreadElement 打印
从源码结构看,Angular 模板表达式中的 spread 解析后会被映射为与 JavaScript AST 一致的SpreadElement节点,并复用语言 JS 的打印链路:
- estree.js 在
SpreadElement分支调用printSpreadElement; - rest-element.js 统一处理 rest/spread 元素的打印;
- needs-parentheses.js 在需要括号的场景下正确为
SpreadElement加括号。
也就是说,模板内 spread 的排版规则与普通 JavaScript 代码中的...完全一致,保证了跨语言的一致性体验。
其他变更一:属性值为单一模板/字符串字面量时不再换行
格式化前后对比
官方公告给出了模板字面量绑定属性的示例(发布公告):
<!-- Input --> <component [property]="` template literal `" /> <!-- Prettier 3.7 --> <component [property]=" ` template literal ` " /> <!-- Prettier 3.8 --> <component [property]="` template literal `" />3.7 会把属性值本身拆到新行,导致[property]="与反引号之间出现多余空行与缩进;3.8 起,当属性值是单个模板字面量或字符串字面量时,会保持值紧跟等号之后,模板字面量内部的换行与缩进原样保留。这对于在模板中书写多行字符串的场景(例如 SQL 片段、内联 CSS)非常友好。
其他变更二:Markdown 代码块内格式化 Angular 语法
格式化前后对比
官方公告给出了angular-ts与angular-html两种围栏语言的示例(发布公告):
<!-- Input --> ```angular-ts @Component({ selector: 'app-root', template: `<div >Welcome to {{ Angular}}! </div>`, }) export class App {}<div >Welcome to {{ Angular}}! </div>Same as input
@Component({ selector: "app-root", template: `<div>Welcome to {{ Angular }}!</div>`, }) export class App {}<div>Welcome to {{ Angular }}!</div>此前 Markdown 代码块遇到 `angular-ts` / `angular-html` 围栏时不做任何处理,3.8 起这两个语言标识会被识别并格式化:引号统一为双引号、模板字面量中的内插表达式(`{{ Angular }}`)被压缩为规范间距、多行标签结构被折叠为单行。 ### 源码实现:Markdown 嵌入解析 该能力由 Markdown 语言的嵌入式处理逻辑实现,见 [language-markdown/embed.js](https://link.gitcode.com/i/0b8ff006a52000e5c51b4d34aa5aa3df): ```js if (language === "angular-ts") { // 使用 TypeScript 解析器处理,同时开启 angular 相关嵌入 } else if (language === "angular-html") { parser = "angular"; }angular-ts走 TypeScript 解析路径(@Component装饰器、类定义按 TS 规则格式化),angular-html则复用 HTML 语言的 Angular 解析器。这也意味着你可以直接在项目文档、博客、注释示例中使用这两种围栏语言,让 Prettier 自动保持 Angular 示例代码的风格统一。
升级与验证
升级方式
在项目根目录执行(需 Node.js 环境与项目包管理器):
npm install --save-dev prettier@^3.8.0 # 或使用 yarn yarn add --dev prettier@^3.8.0快速验证
用官方公告中的最小示例验证格式化行为:
# 将上述 @switch 示例保存为 demo.html 后运行 npx prettier demo.html也可以在 playground 源码 对应的在线演示环境中选择 Angular 解析器直接比对 3.7/3.8 输出差异。对于 Markdown 场景,确认文件中的代码围栏使用了精确的angular-ts或angular-html语言标识(注意不是ts/html),否则不会触发嵌入格式化。
小结
Prettier 3.8 的三类核心变更——连续@case支持、模板内 spread 规范化、Markdown 中 Angular 语法格式化——分别解决了 Angular v21.1 新语法的“解析报错”“排版不规范”“文档示例无法格式化”三个问题。从源码看,这些能力并非独立实现,而是建立在既有架构之上:控制流块打印复用 angular-control-flow-block.js 的 span 判断逻辑,spread 打印复用语言 JS 的 rest-element.js,Markdown 嵌入则通过 embed.js 的语言分发完成。对 Angular 开发者而言,升级到 3.8 后即可放心使用 v21.1 的连续 case 与 spread 语法,并让 Markdown 文档中的 Angular 示例保持与代码库一致的风格。
- 开发工具
- 格式化
- CLI
【免费下载链接】prettier
Prettier is an opinionated code formatter.
相关推荐
WandEnhancer 使用指南:免费解锁 Wand 修改器隐藏功能,手机端也能远程操作
WandEnhancer 使用指南:免费解锁 Wand 修改器隐藏功能,手机端也能远程操作 如果你在用 Wand(前身 WeMod)的时候,被免费版的功能限制挡
开发工具格式化CLIPrettier Markdown 代码块格式化实战:angular-ts 语言标签如何触发 Angular 模板与 TypeScript 双重格式化
Prettier Markdown 代码块格式化实战:angular ts 语言标签如何触发 Angular 模板与 TypeScript 双重格式化 导读 在
开发工具格式化CLIPrettier 1.5 发布详解:GraphQL、CSS-in-JS 与 JSON 格式化支持
Prettier 1.5 发布详解:GraphQL、CSS in JS 与 JSON 格式化支持 本篇技术指南基于 Prettier 官方博客的 1.5.0 版
开发工具格式化CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考