花一天时间开发:Prettier 插件快速实现指南

作者:JC2025.10.10 19:52浏览量:0

简介:本文记录了作者如何在一天内快速开发一个 Prettier 插件,涵盖需求分析、技术选型、实现过程及优化建议,适合想提升代码格式化效率的开发者。

引言:为什么需要自定义 Prettier 插件?

Prettier 作为前端代码格式化的标杆工具,凭借其“意见一致”的配置和跨语言支持,已成为开发者日常工作的标配。然而,当团队或项目存在特定规范(如自定义模板字符串规则、特殊注释格式等)时,原生 Prettier 的配置选项可能无法完全满足需求。此时,开发一个自定义插件成为高效解决方案。

本文将以实际案例展开,讲述如何在一天内从零开发一个 Prettier 插件,解决团队中“多行模板字符串缩进不一致”的痛点,同时提供可复用的技术路径和优化建议。

一、需求分析与技术选型

1. 痛点场景:多行模板字符串缩进混乱

在 React/Vue 组件中,JSX 或模板字符串常包含多行内容。例如:

  1. const query = `
  2. SELECT * FROM users
  3. WHERE id = ${userId}
  4. `;

原生 Prettier 默认按 printWidth 折行,但缩进可能不符合团队规范(如希望所有内容缩进 2 空格)。手动调整效率低,且易被后续格式化覆盖。

2. 插件目标

  • 自动调整多行模板字符串的缩进。
  • 支持配置缩进空格数。
  • 与现有 Prettier 配置无缝集成。

3. 技术选型

  • Prettier 插件机制:通过 parsersprinters 扩展原生功能。
  • 工具链:Node.js + TypeScript(类型安全)+ Jest(测试)。
  • 开发效率:利用 prettier-plugin-starter 模板快速初始化。

二、一天开发实战:分步实现

1. 环境搭建(1小时)

使用官方模板初始化项目:

  1. npx degit prettier/plugin-starter prettier-plugin-custom-indent
  2. cd prettier-plugin-custom-indent
  3. npm install

关键文件结构:

  1. src/
  2. index.ts # 插件入口
  3. printer.ts # 自定义打印逻辑
  4. options.ts # 配置解析
  5. package.json

2. 核心逻辑实现(3小时)

printer.ts 中覆盖模板字符串的打印逻辑:

  1. import { printDocument } from "prettier/doc-builders";
  2. import type { ParserOptions, PrintFn } from "prettier";
  3. const customPrint: PrintFn = (path, options, print) => {
  4. const node = path.getValue() as any;
  5. if (node.type === "template-literal") {
  6. const quasis = node.quasis;
  7. const indent = options.customIndent || 2; // 从配置读取缩进
  8. const lines = quasis.map((q: any) => q.value.raw.trim());
  9. const indentedLines = lines.map(line =>
  10. line ? " ".repeat(indent) + line : ""
  11. );
  12. return indentedLines.join("\n");
  13. }
  14. return print(path);
  15. };
  16. export default {
  17. print: customPrint,
  18. };

3. 配置集成(1小时)

options.ts 中定义插件配置:

  1. export const options = {
  2. customIndent: {
  3. type: "int",
  4. default: 2,
  5. description: "缩进空格数",
  6. },
  7. };

修改 index.ts 暴露配置:

  1. import { options } from "./options";
  2. import printer from "./printer";
  3. export default {
  4. languages: [{ name: "javascript", extensions: [".js", ".jsx"] }],
  5. parsers: { /* 复用原生 parser */ },
  6. printers: { "template-literal": printer.print },
  7. options,
  8. };

4. 测试与调试(2小时)

编写 Jest 测试用例:

  1. import { format } from "prettier";
  2. import plugin from "../src";
  3. test("缩进 2 空格", async () => {
  4. const code = `const query = \`\n SELECT *\n FROM users\n\`;`;
  5. const result = await format(code, {
  6. parser: "babel",
  7. plugins: [plugin],
  8. customIndent: 2,
  9. });
  10. expect(result).toContain(" SELECT *\n FROM users");
  11. });

通过 npm link 本地测试,验证实际项目中的效果。

三、优化与扩展建议

1. 性能优化

  • 缓存计算结果:对重复的模板字符串节点缓存缩进结果。
  • 避免深度遍历:优先处理顶层模板字符串,减少 AST 遍历开销。

2. 功能扩展

  • 多语言支持:通过 languages 配置扩展 TypeScript、HTML 等。
  • 动态缩进:根据上下文(如嵌套在对象中)动态调整缩进级别。

3. 团队协作

  • 文档化配置:在 README 中明确配置项和示例。
  • CI 集成:通过 prettier --check 确保代码一致性。

四、一天开发的启示

  1. 聚焦核心痛点:优先解决高频问题(如本例的缩进),避免过度设计。
  2. 复用现有生态:Prettier 的插件机制和社区模板大幅降低开发门槛。
  3. 快速验证:通过本地链接和简单测试用例快速迭代。

五、适用场景与扩展方向

  • 企业级规范:金融、医疗等行业对代码格式有严格合规要求。
  • 框架特定规则:如 Vue 单文件组件中的 <template> 格式化。
  • 与 ESLint 协同:通过 eslint-plugin-prettier 统一代码风格。

结语:从一天到持续迭代

本文展示的插件虽在一天内完成,但实际项目中需持续优化。建议后续:

  1. 收集团队反馈,调整默认配置。
  2. 监控 Prettier 版本更新,确保兼容性。
  3. 考虑开源,接受社区贡献。

开发 Prettier 插件不仅是技术实践,更是提升团队效率的投资。即使时间有限,通过合理规划和工具利用,也能快速交付价值。