Skip to content
On this page

Prettier API使用

Prettier不仅提供命令行接口,还提供了编程API,允许您在JavaScript代码中直接使用Prettier进行代码格式化。本指南详细介绍Prettier API的使用方法。

基础API

安装和导入

bash
npm install prettier
javascript
// CommonJS
const prettier = require('prettier');

// ES Modules
import * as prettier from 'prettier';
// 或
import { format, check, resolveConfig } from 'prettier';

基本格式化

javascript
const code = `function helloWorld( ){ console.log("Hello, world!"); }`;

// 基本格式化
const formatted = prettier.format(code, {
  parser: 'babel', // 使用babel解析器
  semi: true,
  singleQuote: true,
  printWidth: 80,
  tabWidth: 2,
});

console.log(formatted);
// 输出:
// function helloWorld() {
//   console.log('Hello, world!');
// }

核心API方法

format方法

javascript
// format方法 - 格式化代码
const formattedCode = prettier.format(sourceCode, {
  parser: 'babel',           // 解析器
  semi: true,               // 分号
  singleQuote: true,        // 单引号
  trailingComma: 'es5',     // 尾随逗号
  printWidth: 80,           // 打印宽度
  tabWidth: 2,              // Tab宽度
  useTabs: false,           // 使用空格而非Tab
  bracketSpacing: true,     // 对象括号间距
  arrowParens: 'avoid',     // 箭头函数参数括号
});

// 格式化选项的完整示例
const options = {
  // 解析器选项
  parser: 'babel', // 'babel', 'flow', 'typescript', 'css', 'json', 等
  
  // 代码风格选项
  semi: true,               // 语句末尾加分号
  singleQuote: false,       // 使用单引号
  trailingComma: 'es5',     // 'none', 'es5', 'all'
  bracketSpacing: true,     // 对象大括号内的间距
  jsxBracketSameLine: false, // JSX标记的`>`是否另起一行
  arrowParens: 'avoid',     // 箭头函数只有一个参数时是否加括号
  
  // 行宽选项
  printWidth: 80,           // 每行最大字符数
  tabWidth: 2,              // Tab缩进宽度
  useTabs: false,           // 使用Tab而非空格进行缩进
};

const formatted = prettier.format(code, options);

check方法

javascript
// check方法 - 检查代码是否已格式化
const isFormatted = prettier.check(code, {
  parser: 'babel',
  semi: true,
  singleQuote: true,
});

if (!isFormatted) {
  console.log('代码需要格式化');
  const formattedCode = prettier.format(code, {
    parser: 'babel',
    semi: true,
    singleQuote: true,
  });
} else {
  console.log('代码已经格式化');
}

resolveConfig方法

javascript
// resolveConfig方法 - 解析配置
async function formatWithConfig(filePath) {
  // 异步获取配置
  const config = await prettier.resolveConfig(filePath);
  
  // 或者同步获取配置
  const syncConfig = prettier.resolveConfig.sync(filePath, {
    useCache: true, // 使用缓存
  });
  
  const formatted = prettier.format(code, {
    ...config,
    parser: 'babel', // 确保指定了parser
  });
  
  return formatted;
}

// 获取默认配置
const defaultConfig = await prettier.resolveConfig('./');

解析器和文件类型

JavaScript解析器

javascript
// Babel解析器(默认,支持最新JS特性)
const formatted = prettier.format(code, { parser: 'babel' });

// Flow解析器
const formatted = prettier.format(code, { parser: 'flow' });

// TypeScript解析器
const tsCode = `const greet = (name: string): string => { return name; }`;
const formatted = prettier.format(tsCode, { parser: 'typescript' });

其他文件类型解析器

javascript
// CSS
const cssCode = `.my-class{color:red}`;
const formatted = prettier.format(cssCode, { parser: 'css' });

// JSON
const jsonData = '{"name":"John","age":30}';
const formatted = prettier.format(jsonData, { parser: 'json' });

// Markdown
const mdCode = '# Title\n\nSome content';
const formatted = prettier.format(mdCode, { parser: 'markdown' });

// GraphQL
const gqlCode = `type Query{hello: String}`;
const formatted = prettier.format(gqlCode, { parser: 'graphql' });

// HTML
const htmlCode = `<div><p>Hello</p></div>`;
const formatted = prettier.format(htmlCode, { parser: 'html' });

// Vue
const vueCode = `<template><div>{{msg}}</div></template>`;
const formatted = prettier.format(vueCode, { parser: 'vue' });

配置解析

解析配置选项

javascript
// 异步解析配置
async function formatWithProjectConfig(code, filePath) {
  const options = await prettier.resolveConfig(filePath, {
    useCache: true,        // 使用缓存
    editorconfig: true,    // 考虑.editorconfig文件
  });
  
  return prettier.format(code, {
    ...options,
    parser: 'babel', // 确保有parser
  });
}

// 同步解析配置
function formatSync(code, filePath) {
  const options = prettier.resolveConfig.sync(filePath, {
    useCache: true,
  });
  
  return prettier.format(code, {
    ...options,
    parser: 'babel',
  });
}

手动指定配置

javascript
const customConfig = {
  semi: false,
  singleQuote: true,
  trailingComma: 'all',
  printWidth: 100,
  tabWidth: 4,
  parser: 'babel',
};

const formatted = prettier.format(code, customConfig);

高级API功能

getFileInfo方法

javascript
// getFileInfo方法 - 获取文件信息
async function processFile(filePath) {
  const fileInfo = await prettier.getFileInfo(filePath, {
    withNodeModules: false, // 忽略node_modules
    ignorePath: '.prettierignore', // 使用忽略文件
  });
  
  console.log('是否被Prettier支持:', fileInfo.inferredParser);
  console.log('使用的解析器:', fileInfo.inferredParser);
  console.log('是否被忽略:', fileInfo.ignored);
  
  if (fileInfo.inferredParser && !fileInfo.ignored) {
    // 格式化文件
    const code = require('fs').readFileSync(filePath, 'utf8');
    const formatted = prettier.format(code, {
      parser: fileInfo.inferredParser,
    });
    
    // 写入文件
    require('fs').writeFileSync(filePath, formatted);
  }
}

getSupportInfo方法

javascript
// getSupportInfo方法 - 获取支持信息
const supportInfo = prettier.getSupportInfo();

console.log('支持的解析器:', supportInfo.parsers.map(p => p.name));
console.log('支持的选项:', supportInfo.options);

// 检查特定解析器是否支持
const supportsTypeScript = supportInfo.languages.some(
  lang => lang.name === 'TypeScript'
);

实际应用示例

文件格式化工具

javascript
const fs = require('fs');
const path = require('path');

async function formatFile(filePath) {
  try {
    // 读取文件
    const code = fs.readFileSync(filePath, 'utf8');
    
    // 获取配置
    const config = await prettier.resolveConfig(filePath);
    
    // 获取文件信息
    const fileInfo = await prettier.getFileInfo(filePath);
    
    if (fileInfo.ignored) {
      console.log(`文件被忽略: ${filePath}`);
      return false;
    }
    
    if (!fileInfo.inferredParser) {
      console.log(`不支持的文件类型: ${filePath}`);
      return false;
    }
    
    // 格式化代码
    const formatted = prettier.format(code, {
      ...config,
      parser: fileInfo.inferredParser,
    });
    
    // 写入文件(如果代码已改变)
    if (formatted !== code) {
      fs.writeFileSync(filePath, formatted);
      console.log(`格式化完成: ${filePath}`);
      return true;
    } else {
      console.log(`无需格式化: ${filePath}`);
      return false;
    }
  } catch (error) {
    console.error(`格式化错误 ${filePath}:`, error.message);
    return false;
  }
}

// 批量格式化文件
async function formatFiles(filePaths) {
  const results = await Promise.all(
    filePaths.map(filePath => formatFile(filePath))
  );
  
  const formattedCount = results.filter(Boolean).length;
  console.log(`完成格式化 ${formattedCount}/${filePaths.length} 个文件`);
}

代码检查工具

javascript
async function checkCodeStyle(code, filePath) {
  const fileInfo = await prettier.getFileInfo(filePath);
  
  if (fileInfo.ignored || !fileInfo.inferredParser) {
    return { ok: true, message: '文件被忽略或不支持' };
  }
  
  const config = await prettier.resolveConfig(filePath);
  const isFormatted = prettier.check(code, {
    ...config,
    parser: fileInfo.inferredParser,
  });
  
  if (isFormatted) {
    return { ok: true, message: '代码格式正确' };
  } else {
    const formatted = prettier.format(code, {
      ...config,
      parser: fileInfo.inferredParser,
    });
    
    return {
      ok: false,
      message: '代码需要格式化',
      original: code,
      formatted: formatted,
    };
  }
}

自定义格式化器

javascript
class CodeFormatter {
  constructor(options = {}) {
    this.defaultOptions = {
      parser: 'babel',
      semi: true,
      singleQuote: true,
      trailingComma: 'es5',
      printWidth: 80,
      tabWidth: 2,
      ...options,
    };
  }
  
  async format(code, filePath, additionalOptions = {}) {
    let options = { ...this.defaultOptions, ...additionalOptions };
    
    // 如果提供了文件路径,尝试获取项目配置
    if (filePath) {
      const projectConfig = await prettier.resolveConfig(filePath);
      options = { ...projectConfig, ...options };
    }
    
    // 确保有解析器
    if (!options.parser) {
      const fileInfo = await prettier.getFileInfo(filePath || '');
      options.parser = fileInfo.inferredParser || 'babel';
    }
    
    return prettier.format(code, options);
  }
  
  async check(code, filePath, additionalOptions = {}) {
    const formattedCode = await this.format(code, filePath, additionalOptions);
    return formattedCode === code;
  }
  
  async formatFile(filePath) {
    const code = fs.readFileSync(filePath, 'utf8');
    const formatted = await this.format(code, filePath);
    
    if (formatted !== code) {
      fs.writeFileSync(filePath, formatted);
      return { changed: true, filePath };
    }
    
    return { changed: false, filePath };
  }
}

// 使用示例
const formatter = new CodeFormatter({
  singleQuote: true,
  trailingComma: 'all',
});

// 格式化代码
const formatted = await formatter.format('const x=1;', 'test.js');

// 格式化文件
const result = await formatter.formatFile('src/index.js');

与构建工具集成

Webpack插件示例

javascript
// prettier-webpack-plugin.js
class PrettierWebpackPlugin {
  constructor(options = {}) {
    this.options = options;
  }
  
  apply(compiler) {
    compiler.hooks.emit.tapPromise(
      'PrettierWebpackPlugin',
      async (compilation) => {
        const changedFiles = Object.keys(compilation.assets)
          .filter(filePath => {
            return /\.(js|jsx|ts|tsx|json|css|md)$/.test(filePath);
          });
        
        for (const filePath of changedFiles) {
          const source = compilation.assets[filePath].source();
          const formatted = prettier.format(source, {
            parser: this.getParserForFile(filePath),
          });
          
          compilation.assets[filePath] = {
            source: () => formatted,
            size: () => formatted.length,
          };
        }
      }
    );
  }
  
  getParserForFile(filePath) {
    if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
      return 'typescript';
    } else if (filePath.endsWith('.json')) {
      return 'json';
    } else if (filePath.endsWith('.css')) {
      return 'css';
    }
    return 'babel';
  }
}

错误处理

API错误处理

javascript
async function safeFormat(code, options) {
  try {
    return await prettier.format(code, options);
  } catch (error) {
    if (error.code === 'BABEL_PARSE_ERROR') {
      console.error('解析错误:', error.message);
    } else if (error.code === 'UNKNOWN_NODE_TYPE') {
      console.error('未知节点类型:', error.message);
    } else {
      console.error('格式化错误:', error.message);
    }
    throw error;
  }
}

// 配置解析错误处理
async function getConfigSafely(filePath) {
  try {
    return await prettier.resolveConfig(filePath);
  } catch (error) {
    console.warn('无法解析配置,使用默认配置:', error.message);
    return {}; // 返回默认配置
  }
}

性能优化

批量处理优化

javascript
// 批量格式化优化
async function batchFormat(codes, options) {
  // 使用相同配置批量处理
  return codes.map(code => prettier.format(code, options));
}

// 缓存配置以提高性能
const configCache = new Map();

async function getCachedConfig(filePath) {
  const dir = path.dirname(filePath);
  if (configCache.has(dir)) {
    return configCache.get(dir);
  }
  
  const config = await prettier.resolveConfig(filePath);
  configCache.set(dir, config);
  return config;
}

通过使用Prettier API,您可以将代码格式化功能集成到自己的工具和工作流程中,实现更灵活和自动化的代码管理。