简介:本文详细记录了开发者如何在一天内从零开始构建一个Prettier插件,涵盖需求分析、技术选型、核心功能实现及测试优化全流程,提供可复用的开发指南与实用技巧。
Prettier作为前端代码格式化工具,凭借其开箱即用的配置和强一致性规则,已成为开发者社区的标配。然而,当团队面临特殊代码风格需求(如自定义模板字符串格式、特定框架的语法糖处理)时,默认规则往往无法满足。此时,开发一个自定义插件成为高效解决方案。本文将以实际案例,拆解如何在一天内从零构建一个Prettier插件,覆盖从需求分析到上线的完整流程。
假设团队需要统一处理React组件中的JSX属性换行规则。默认Prettier会将多属性JSX强制换行,但团队希望根据属性数量动态决定是否换行。这一需求无法通过配置文件实现,必须通过插件扩展。
Prettier插件基于AST(抽象语法树)操作,通过解析、转换、重新生成代码实现格式化。其核心优势在于:
@prettier/plugin-*命名空间发布。
mkdir prettier-plugin-jsx-dynamic-wrap && cd $_npm init -ynpm install prettier @types/prettier --save-dev
prettier-plugin-jsx-dynamic-wrap/├── src/│ └── index.ts # 插件入口├── package.json└── tsconfig.json
{"compilerOptions": {"module": "CommonJS","target": "ES6","esModuleInterop": true}}
import type { Plugin } from "prettier";const plugin: Plugin = {languages: [{name: "JavaScript",parsers: ["jsx-dynamic-wrap"],},],parsers: {"jsx-dynamic-wrap": {parse: parseJSX,astFormat: "jsx-dynamic-wrap",},},printers: {"jsx-dynamic-wrap": {print: printJSX,},},};export default plugin;
使用@babel/parser解析JSX语法树,标记需要处理的节点:
import { parse as babelParse } from "@babel/parser";function parseJSX(text: string) {const ast = babelParse(text, {sourceType: "module",plugins: ["jsx"],});// 遍历AST,标记需要动态换行的JSX节点return transformAST(ast);}
核心算法根据属性数量决定是否换行:
function printJSX(path: any, options: any, print: any) {const node = path.node;if (node.type === "JSXOpeningElement") {const attributeCount = node.attributes.length;const shouldWrap = attributeCount > options.jsxMaxAttributesPerLine;if (shouldWrap) {return printAttributesWithNewlines(node.attributes, print);}}// 默认打印逻辑return defaultPrint(path, options, print);}
使用jest验证不同场景下的输出:
import plugin from "../src";import prettier from "prettier";test("JSX with 3 attributes should wrap", async () => {const code = `<div className="foo" id="bar" data-test="baz" />`;const formatted = await prettier.format(code, {parser: "jsx-dynamic-wrap",plugins: [plugin],jsxMaxAttributesPerLine: 2,});expect(formatted).toContain('\n ');});
{"main": "dist/index.js","scripts": {"build": "tsc","prepublish": "npm run build"}}
npm loginnpm publish --access public
在prettier.config.js中配置:
module.exports = {plugins: ["prettier-plugin-jsx-dynamic-wrap"],jsxMaxAttributesPerLine: 3,};
通过一天的高效开发,我们不仅解决了团队的格式化痛点,更验证了Prettier插件机制的灵活性。对于开发者而言,掌握此类工具开发能力,既能提升个人技术影响力,也能为团队创造长期价值。未来,随着前端生态的演进,自定义格式化规则将成为规模化团队的标配能力。