[Plugin API] Multiple prettier plugins accessing the same language disables all but one
Environments:
- Prettier Version: 2.6.2
- Running Prettier via: Node.js API
- Runtime: 18.1.0
- Operating System: Linux (through WSL)
- Prettier plugins (if any):
prettier-plugin-tailwindcss,prettier-plugin-sort-imports(disclosure: I made this plugin, issue also happens with@trivago/prettier-plugin-sort-importsthough)
Steps to reproduce:
- Install two plugins that both register a preprocessor/parser for the same language
- One of them stops working
Expected behavior:
They both work
Actual behavior:
One of them stops working (probably dependent on alphabetical order)
The issue
I did some digging and the issue is actually pretty fundamental. It seems to be common practice to register prettier plugins that handle existing languages in this way:
module.exports = {
parsers: {
typescript: {
...require('prettier/parser-typescript'),
preprocess: (...args) => {
require('prettier/parser-typescript').parsers.typescript.preprocess(...args);
myCustomPreProcessFunction(...args);
}
}
}
}
However, when two prettier plugins add their own preprocessors (or handlers or whatever) for the same language, things break. Because parsers.typescript is re-assigned to a fresh object, and since require('prettier/parser-typescipt') is not modified in-place, the new object won't have the previous plugins' handlers attached. This means that any double (or more) registration of a language just disables all plugins except for one. In the case of prettier-plugin-tailwindcss this is particularly bad because it registers 18 parsers.
This could be fixed by requiring plugin authors to modify require('prettier/parser-typescript') in-place, for example:
const parserTypescript = require('prettier/parser-typescript');
parserTypescript.parsers.typescript.preprocess = (...args) => {
parserTypescript.parsers.typescript.preprocess(...args);
myCustomPreProcessFunction(...args);
}
module.exports = { parsers: {typescript: parserTypescript.parsers.typescript } };
But I'd say a plugin system that requires plugins to export a callback might be better here. That way they'll always have access to the "current" parser and don't need to import it themselves.
What are your thoughts on this? Has this been thought about before (I can't imagine nobody has ran into this issue before)? Or am I doing something wrong?
I have the same issue
plugins: [
require("prettier-plugin-tailwindcss"),
require("@trivago/prettier-plugin-sort-imports"),
],
only the second one works at a time
I have the same behavior using pnpm with this config:
// .prettierrc.cjs
/** @type {import('prettier').Config} */
module.exports = {
plugins: [
require('prettier-plugin-jsdoc'),
require('@trivago/prettier-plugin-sort-imports')
],
printWidth: 100,
proseWrap: 'always',
singleQuote: true,
semi: false,
importOrder: ['^node:', '<THIRD_PARTY_MODULES>', '^@mheob/(.*)$', '^[./]'],
importOrderSeparation: true,
importOrderSortSpecifiers: true,
overrides: [
{
files: '*.{yaml,yml}',
options: {
printWidth: 130,
singleQuote: false,
},
},
],
}
Environments:
Prettier Version: 2.7.1
Running Prettier via: Node.js 18.7.0 / PNPM 7.8.0
Operating System: MacOS
Prettier plugins (if any): prettier-plugin-jsdoc, @trivago/prettier-plugin-sort-imports
Same for me with plugins: ['@trivago/prettier-plugin-sort-imports', 'prettier-plugin-tailwindcss'] and only the second one works.
Just ran into this myself. There's a great workaround over in a related issue in the prettier-plugin-tailwindcss repo. Convert your .prettierrc to prettier.config.js, manually mash the two plugins together, and pass that to Prettier in the config:
https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/31#issuecomment-1195411734
@markerikson like I found out in comment https://github.com/tailwindlabs/prettier-plugin-tailwindcss/issues/31#issuecomment-1304815626, that solution breaks for pnpm for some reason. Probably module resolution?
Same for me for pnpm. Only the second one works
plugins: [
require('prettier-plugin-tailwindcss'),
require('@trivago/prettier-plugin-sort-imports'),
],
I am also experiencing this issue.
Setup: Vite, React, TypeScript+SWC
I have two plugins autoloading, @trivago/prettier-plugin-sort-imports was installed first, then prettier-plugin-tailwindcss.
As soon as I remove trivago, hit save in my file, prettier sorts my classes with the tailwindcss plugin. Reinstall trivago and my imports get sorted, but not my classes.
Autoloading appears to favour only one package based on name sorting.
EDIT: tried the workaround markerikson mentioned and was successful, had to call my config prettier.config.cjs for my particular setup.
I am seeing the same issue when using @trivago/prettier-plugin-sort-imports and prettier-plugin-tailwindcss with pnpm, however, it seems the first plugin in the plugins array is used instead of the second one as others have observed.
I am using Eslint 7.32.0.