Appearance
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,您可以将代码格式化功能集成到自己的工具和工作流程中,实现更灵活和自动化的代码管理。