今回は、Conform 導入済みの前提で、Biome / Prettier を条件付きで共存させる設定をまとめます。
1. 前提(Conform導入済み)
stevearc/conform.nvim はすでに入っている前提。
ここでは formatter の「条件」と「実行順」だけを調整します。
2. Biome側の設定(nvim/lua/plugins/biome.lua)
---@alias ConformCtx {buf: number, filename: string, dirname: string}
local supported = {
"css",
"graphql",
"javascript",
"javascriptreact",
"json",
"jsonc",
"typescript",
"typescriptreact",
}
local function has_biome_config(ctx)
return vim.fs.find("biome.json", { path = ctx.dirname, upward = true })[1] ~= nil
end
return {
{
"stevearc/conform.nvim",
optional = true,
opts = function(_, opts)
opts.formatters_by_ft = opts.formatters_by_ft or {}
for _, ft in ipairs(supported) do
opts.formatters_by_ft[ft] = opts.formatters_by_ft[ft] or {}
table.insert(opts.formatters_by_ft[ft], 1, "biome")
end
opts.formatters = opts.formatters or {}
opts.formatters.biome = {
condition = function(_, ctx)
return has_biome_config(ctx)
end,
}
end,
},
}
ポイントは、biome を先頭に入れつつ、biome.json がある時だけ有効化している点。
3. Prettier側の設定(nvim/lua/plugins/prettier.lua)
---@alias ConformCtx {buf: number, filename: string, dirname: string}
local M = {}
local supported = {
"css","graphql","handlebars","html","javascript","javascriptreact","json","jsonc",
"less","markdown","markdown.mdx","scss","typescript","typescriptreact","vue","yaml",
}
local config_names = {
".prettierrc",".prettierrc.json",".prettierrc.json5",".prettierrc.yml",".prettierrc.yaml",
".prettierrc.js",".prettierrc.cjs",".prettierrc.mjs",".prettierrc.toml",
"prettier.config.js","prettier.config.cjs","prettier.config.mjs",
"prettier.config.ts","prettier.config.cts","prettier.config.mts",
}
local function memoize(fn)
local cache = {}
return function(ctx)
local key = ctx.filename
if cache[key] == nil then
cache[key] = fn(ctx)
end
return cache[key]
end
end
function M.has_local_prettier(ctx)
return vim.fs.find("node_modules/.bin/prettier", { path = ctx.dirname, upward = true })[1] ~= nil
end
function M.has_config(ctx)
return vim.fs.find(config_names, { path = ctx.dirname, upward = true })[1] ~= nil
end
function M.has_parser(ctx)
local ft = vim.bo[ctx.buf].filetype
return vim.tbl_contains(supported, ft)
end
M.has_local_prettier = memoize(M.has_local_prettier)
M.has_config = memoize(M.has_config)
M.has_parser = memoize(M.has_parser)
return {
{
"stevearc/conform.nvim",
optional = true,
opts = function(_, opts)
opts.formatters_by_ft = opts.formatters_by_ft or {}
for _, ft in ipairs(supported) do
opts.formatters_by_ft[ft] = opts.formatters_by_ft[ft] or {}
table.insert(opts.formatters_by_ft[ft], "prettier")
end
opts.formatters = opts.formatters or {}
opts.formatters.prettier = {
condition = function(_, ctx)
return M.has_local_prettier(ctx) and M.has_config(ctx) and M.has_parser(ctx)
end,
}
end,
},
}
こちらは「ローカル Prettier がある」「Prettier 設定がある」「対象 filetype」の3条件を満たす時だけ動きます。
4. どう動くか(4パターン)
-
biome.jsonあり / Prettier条件なし → Biomeのみ -
biome.jsonなし / Prettier条件あり → Prettierのみ - 両方条件あり → Biome → Prettier の順で実行され得る
- 両方条件なし → どちらも実行されない
5. 注意点(monorepoで両方走る可能性)
vim.fs.find(..., { upward = true }) なので、workspace ルートに biome.json と Prettier 設定が共存していると、配下の複数パッケージで 両方 true になりやすいです。
その場合、意図せず両方走ることがあります。
6. まとめ(必要なら排他に寄せる)
共存は移行期に便利ですが、定常運用では排他的にした方が事故は減ります。
「共存させるか、どちらかに寄せるか」を先に決めると、Conform 設計がかなり楽になります。