TECHNOLOGIES / ESLint et Prettier
ESLint : la validation de notre code front
ESLint vérifie le fond de notre code JavaScript et Vue.js : erreurs, mauvais usages des directives, conventions d'écriture des composants. La forme est confiée à Prettier, et les types à vue-tsc. Un outil par responsabilité.
Cette fiche documente nos choix de configuration et leur motif, la frontière entre les deux outils, et l'adoption sur un projet existant. Elle est le pendant front de PHP CS Fixer dans notre chaîne de conventions de code.
PRÉSENTATION
Qu'est-ce qu'ESLint ?
ESLint est le linter de référence du monde JavaScript : il lit le code sans l'exécuter et signale ce qui est faux, dangereux ou contraire aux conventions retenues. Chaque règle est activable, configurable, et souvent capable de corriger seule ce qu'elle signale.
Des plugins l'étendent à un langage ou un framework : eslint-plugin-vue comprend les fichiers .vue, leur template et leur script, et porte les règles du style guide officiel.
Chez SmartBooster, ESLint vérifie le fond. La forme, indentation, guillemets, retours à la ligne, ordre des classes Tailwind, est décidée par Prettier, et ESLint a interdiction d'y toucher.
POURQUOI ESLINT
Ce qui en fait notre outil de fond côté front
ESLint tourne sur tout notre code front, projets Symfony avec Vue.js comme projets Vue seuls. C'est une brique de notre démarche qualité, au même titre que PHPStan côté PHP.
Les outils de l'écosystème Vue
ESLint et Prettier sont ceux du dépôt Vue core, ceux que la documentation Vue recommande, et ceux que create-vue, l'outil officiel de création de projet, installe. Suivre create-vue nous aligne sur l'écosystème sans arbitrage de notre part.
Le plugin Vue, au bon niveau
eslint-plugin-vue détecte les mauvais usages des directives et les écarts au style guide. Le preset strongly-recommended ajoute les règles de cohérence que essential laisse de côté : nommage des props et des événements, valeur par défaut des props optionnelles.
Une frontière nette avec Prettier
ESLint sait formater, nous le lui interdisons. eslint-config-prettier, placé en dernier, désactive chaque règle qui touche à la forme, et une commande vérifie qu'il n'en reste aucune. Deux outils qui se contredisent sur un espace, c'est une boucle de correction sans fin.
Une baseline pour l'existant
Les suppressions en masse d'ESLint comptent les violations existantes par fichier et par règle. Seules les nouvelles font échouer le contrôle, et une violation corrigée rend son entrée obsolète. Même principe que la baseline de PHPStan.
TypeScript sans rien reconfigurer
Sur un projet TypeScript, @vue/eslint-config-typescript branche typescript-eslint sur les fichiers .vue, et vue-tsc vérifie les types, hors ESLint. Le typage est une troisième case, il ne déplace pas les deux premières.
Un contrôle mesuré, pas maximal
Le preset recommended, au-dessus du nôtre, a été mesuré sur deux de nos bases de code : 752 violations, dont 84 % sur l'ordre des attributs dans une balise, priorité C du style guide Vue. Réécrire tous les templates pour cela n'apporte rien. Nous l'avons écarté, chiffres à l'appui.
NOTRE USAGE
Comment nous configurons ESLint
Le standard-bundle documente la configuration en couches, sans en copier aucune : chaque projet applique celles qui le concernent. Les extraits ci-dessous en donnent les choix, la documentation du bundle le détail.
Une configuration en couches
Un socle agnostique (@eslint/js recommandé, Prettier, la frontière), puis ce que le contexte ajoute : le plugin Vue, le périmètre assets/ et les globals sur Symfony, deux règles levées sur les pages Inertia, le tri des classes Tailwind, TypeScript. Chaque couche est documentée dans le standard-bundle.
Un verbe corrige, :check rapporte
yarn lint et yarn format corrigent. yarn lint:check et yarn format:check ne font que rapporter. yarn validation enchaîne les deux contrôles, affiche les deux rapports et échoue si l'un des deux échoue : c'est la commande que la CI appelle.
Sur Symfony, le périmètre se restreint
Les commandes ciblent assets/ et les fichiers JS de la racine, jamais vendor/ : un bundle valide son propre code front depuis son propre dépôt. Les globals injectés par Twig, comme route pour FOSJsRouting, sont déclarés pour que no-undef ne les signale pas.
Deux règles levées sur les pages Inertia
Une page Inertia reçoit ses props du contrôleur Symfony et n'est jamais écrite comme une balise. vue/multi-word-component-names et vue/require-default-prop n'y ont pas d'objet, et sont désactivées sur scripts/pages/ et scripts/layout/. Les composants y restent soumis.
PRETTIER
Prettier : la forme, décidée une fois
Prettier formate notre code JavaScript, Vue.js et CSS. Il a peu d'options, nous en touchons quatre, et chacune a son motif. ESLint pourrait formater aussi : nous lui avons retiré ce droit.
Pourquoi Prettier et pas ESLint seul
ESLint peut formater, mais l'écosystème Vue ne le fait pas : Vue core, create-vue, et au-delà React, Tailwind CSS et GitLab confient la forme à Prettier. Il a peu d'options, donc peu à débattre, et le même résultat partout. Sa forme n'est pas la plus belle, elle est la moins discutée.
L'outil écarté : @antfu/eslint-config
Il réunit règles et formatage dans un seul outil, sans Prettier. Nous l'avons écarté : c'est une configuration personnelle, utilisée par aucun dépôt officiel Vue, qui impose ses propres opinions de style et coupe des plugins dédiés, à commencer par le tri des classes Tailwind.
Quatre options, un seul écart
semi: false et printWidth: 100 viennent du template create-vue. singleAttributePerLine applique le style guide Vue. singleQuote: false est notre écart : Prettier choisit le guillemet qui demande le moins d'échappements, et des chaînes françaises pleines d'apostrophes finiraient mélangées.
Le tri des classes Tailwind
prettier-plugin-tailwindcss, le plugin officiel, range les classes utilitaires dans un ordre canonique. Plus aucun débat sur l'endroit où va une classe. Sur Tailwind 4, tailwindStylesheet lui indique le CSS d'entrée, sans quoi il ne connaît pas les utilitaires du design system.
La frontière, vérifiée par une commande
eslint-config-prettier/flat, importé en dernier dans la configuration ESLint, désactive toute règle qui formate, y compris les règles de mise en page du plugin Vue. npx eslint-config-prettier sur un fichier de chaque extension confirme qu'aucune règle en conflit ne subsiste.
Le pragma pour l'existant
Prettier n'a pas de baseline. requirePragma: true le restreint aux fichiers qui commencent par @format : on y passe fichier par fichier, au fil des tickets qui les touchent, et l'option se retire quand tout est formaté.
BONNES PRATIQUES & DOCUMENTATION
Nos conventions ESLint et Prettier
Documentation de référence pour l'équipe SmartBooster.
Le socle
Ce que tout projet front installe, quel que soit son contexte
Le socle
Ce que tout projet front installe, quel que soit son contexte
La configuration est décrite en couches dans docs/front_code_validation.md du standard-bundle. Le socle est agnostique, chaque section suivante ajoute ce qu'un contexte exige.
yarn add --dev eslint @eslint/js eslint-config-prettier prettier
Les scripts du package.json :
"scripts": {
"lint": "eslint . --fix --cache",
"lint:check": "eslint .",
"lint:baseline": "rm -f eslint-suppressions.json && eslint . --suppress-all",
"format": "prettier --write .",
"format:check": "prettier --check .",
"validation": "yarn lint:check; s=$?; yarn format:check && exit $s"
}
- Un verbe nu corrige,
:checkne fait que rapporter. La CI appelle les:check. validationenchaîne les deux contrôles, affiche les deux rapports, et échoue si l'un des deux échoue.--cacheécrit un.eslintcache, à ajouter au.gitignore.
prettier.config.mjs :
export default {
semi: false,
singleQuote: false,
printWidth: 100,
singleAttributePerLine: true,
}
Toute option absente est un défaut de Prettier (tabWidth: 2, trailingComma: "all", ...). Le motif de chacune des quatre est sur cette page, section Prettier.
eslint.config.mjs :
import js from "@eslint/js"
import { defineConfig } from "eslint/config"
import skipFormatting from "eslint-config-prettier/flat"
export default defineConfig([
{ name: "app/files-to-lint", files: ["**/*.{js,mjs}"] },
js.configs.recommended,
skipFormatting,
])
filesdéclare les extensions qu'ESLint prend quand on lui passe un répertoire : sans lui, seul.jsest analysé. Les couches suivantes y ajoutent.vueet.ts.skipFormattingreste en dernier : sur une règle partagée, la dernière configuration gagne.
La frontière avec Prettier
Comment nous vérifions qu'aucune règle ESLint ne formate
La frontière avec Prettier
Comment nous vérifions qu'aucune règle ESLint ne formate
eslint-config-prettier désactive chaque règle ESLint qui doublonne ou contredit Prettier, règles de base et règles de mise en page du plugin Vue comprises. Son CLI vérifie qu'il n'en reste aucune :
npx eslint-config-prettier <fichier.js> <fichier.vue>
Il affiche No rules that are unnecessary or conflict with Prettier were found. quand tout est en ordre. Passer un fichier de chaque extension gérée par la configuration (.js, .vue, .ts) pour que toutes les règles soient comparées.
Nous importons eslint-config-prettier/flat directement, et non @vue/eslint-config-prettier/skip-formatting : le paquet Vue était un paquet de transition, sans maintenance prévue, et create-vue a fait le même changement début 2026 (PR #897).
La couche Vue
Le plugin et le niveau de preset retenu
La couche Vue
Le plugin et le niveau de preset retenu
yarn add --dev eslint-plugin-vue vue-eslint-parser
vue-eslint-parser, qui découpe un fichier .vue pour exposer son template et son script à ESLint, est une dépendance pair de eslint-plugin-vue : avec yarn, elle doit être déclarée explicitement.
import pluginVue from "eslint-plugin-vue"
{ name: "app/files-to-lint", files: ["**/*.{js,mjs,vue}"] },
// ...
...pluginVue.configs["flat/strongly-recommended-error"],
Pourquoi strongly-recommended-error. essential, le défaut de create-vue, n'attrape que les erreurs. strongly-recommended ajoute les règles de cohérence dont l'absence laisse l'écriture des composants dériver :
vue/prop-name-casing: props en camelCase ;vue/v-on-event-hyphenation: événements avec tirets dans les templates ;vue/require-default-prop: une valeur par défaut pour chaque prop optionnelle (default: undefinedquand aucune n'a de sens).
La variante -error est nécessaire : le preset déclare ces règles en warn, qu'aucune baseline ne retient et qui ne font jamais échouer lint:check.
Ses 12 règles de mise en page ne gênent pas Prettier : 11 sont désactivées par skipFormatting, et vue/first-attribute-linebreak exige ce que Prettier produit déjà.
Pourquoi pas recommended. Il ajoute 8 règles, qui remontent 752 violations mesurées sur deux de nos bases de code. 84 % viennent de vue/attributes-order, une convention d'ordre dans la balise qui obligerait à réécrire tous les templates sans gain fonctionnel, et que le style guide Vue lui-même classe en priorité C. L'essentiel du reste est vue/no-v-html, alors que nos v-html affichent du contenu back-end que nous maîtrisons.
Les couches Symfony, Inertia, Tailwind et TypeScript
Ce que chaque contexte ajoute
Les couches Symfony, Inertia, Tailwind et TypeScript
Ce que chaque contexte ajoute
Symfony. Les commandes ciblent assets/ et les fichiers JS de la racine, jamais vendor/ : un bundle valide son propre code front depuis son propre dépôt. Le code front tourne dans le navigateur, les fichiers de configuration sous Node, et Twig injecte des globals qu'il faut déclarer :
import globals from "globals"
{
name: "app/globals-browser",
languageOptions: {
globals: {
...globals.browser,
// Adapter of Ziggy's `route` function to FOSJsRoutingBundle, set on `window` by the Twig layout.
route: "readonly",
},
},
},
{
name: "app/globals-node",
files: ["**/*.config.{js,mjs}"],
languageOptions: { globals: { ...globals.node } },
},
Inertia. Une page et son layout ne sont pas des composants réutilisables : résolus par leur chemin, ils reçoivent leurs props du contrôleur Symfony. Deux règles n'y ont pas d'objet, les composants y restent soumis :
{
name: "app/inertia-pages-and-layouts",
files: ["**/scripts/pages/**/*.vue", "**/scripts/layout/**/*.vue"],
rules: {
"vue/multi-word-component-names": "off",
"vue/require-default-prop": "off",
},
},
Tailwind CSS. prettier-plugin-tailwindcss, toujours en dernier dans la liste des plugins Prettier. Sur Tailwind 4, le thème vit dans le CSS : tailwindStylesheet donne au trieur le fichier d'entrée, sans quoi les utilitaires du design system (bg-primary, text-danger) sont rangés parmi les classes inconnues. Une entrée CSS par interface se déclare via overrides.
plugins: ["prettier-plugin-tailwindcss"],
tailwindStylesheet: "./assets/styles/app.css",
TypeScript. @vue/eslint-config-typescript branche typescript-eslint sur les fichiers .vue ; defineConfigWithVueTs remplace defineConfig pour propager le parser aux blocs <script>. La vérification des types reste hors ESLint : vue-tsc --build.
import { defineConfigWithVueTs, vueTsConfigs } from "@vue/eslint-config-typescript"
export default defineConfigWithVueTs(
{ name: "app/files-to-lint", files: ["**/*.{ts,mts,vue}"] },
// ...
vueTsConfigs.recommended,
// ...
)
Sur un projet existant
Baseline ESLint, pragma ou commit unique pour Prettier
Sur un projet existant
Baseline ESLint, pragma ou commit unique pour Prettier
Les deux outils remontent beaucoup sur une base de code qui ne les a jamais eus. Plutôt qu'un big bang, chacun a sa façon de n'échouer que sur le code nouveau.
ESLint : la baseline. Les suppressions en masse : eslint-suppressions.json compte les violations existantes par fichier et par règle, seules les nouvelles font échouer.
yarn lint:baselinerégénère le fichier de zéro (--suppress-allne retire jamais d'entrée). Relire son diff avant de commiter.- Violation corrigée → entrée obsolète →
lint:checksort en code 2 → régénérer. - Seules les règles en
errorsont enregistrées.
Prettier : le pragma. Pas de baseline, mais requirePragma: true restreint Prettier aux fichiers qui commencent par @format :
- Faire entrer un fichier :
yarn prettier --write --no-require-pragma --insert-pragma <fichiers>(--insert-pragmaseul ne fait rien,requirePragmal'emporte). - Marqueur :
<!-- @format -->dans un.vue,/** @format */dans un.jsou un.css. - Puis
yarn lint:baseline: le formatage corrigevue/first-attribute-linebreak, ses entrées deviennent obsolètes. - Retirer l'option quand tout est formaté.
Prettier : le commit unique. Formater tout d'un coup est l'autre voie, la seule qui supprime le pragma tout de suite. Elle convient à un projet avec peu de fichiers front, peu de personnes et peu de branches ouvertes : chacune devra être rebasée sur les fichiers reformatés.
- Commiter la configuration, fusionner les branches ouvertes.
- Un commit avec
yarn format, rien d'autre. - Filet :
prettier --debug-checksur le même périmètre signale tout fichier dont le sens pourrait changer. - Une fois fusionné (squash ou rebase change le hash), inscrire le hash dans
.git-blame-ignore-revs. Chaque développeur configuregit config blame.ignoreRevsFile .git-blame-ignore-revs(PhpStorm le suit). GitLab : Blame preferences › Ignore specific revisions.
Pièges : fichiers entiers seulement, aucun outil maintenu ne formate les lignes modifiées ; un texte déplacé sur sa propre ligne dans un template devient un espace de bord une fois compilé par Vue, invisible dans un bloc, visible sous whitespace-pre-wrap ou <pre> ; blame.ignoreRevsFile configuré et fichier absent sur une branche → git blame échoue.
Ensuite. La résorption des suppressions et des fichiers sans pragma entre dans le flux non prioritaire de la maintenance technique, entre deux demandes. Un projet neuf n'a ni baseline ni pragma : les deux contrôles passent dès le premier commit.
FAQ
Les réponses à vos questions
Et si vous ne trouvez pas ce que vous cherchez, nous serons ravis de vous répondre en direct lors d'un rendez-vous entre humains !
Parce que deux outils qui décident de la même chose finissent par se contredire, et qu'un développeur corrige alors l'un pour faire échouer l'autre. Un outil, une responsabilité : un échec nomme son responsable, la forme à Prettier, le fond à ESLint, les types à vue-tsc. Chacun se configure et se met à jour seul. C'est aussi ce que fait l'écosystème Vue, dont nous suivons l'outillage.
create-vue est l'outil officiel de création de projet, maintenu par l'équipe Vue. Ses choix d'outillage sont ceux de l'écosystème, et ils évoluent avec lui : quand create-vue est passé de @vue/eslint-config-prettier à eslint-config-prettier/flat début 2026, nous avons suivi. Nos seuls écarts sont documentés avec leur motif : le niveau du preset Vue, et un guillemet.
essential, le défaut de create-vue, n'attrape que les erreurs. strongly-recommended ajoute les règles de cohérence dont l'absence laisse l'écriture des composants dériver d'un développeur à l'autre : props en camelCase, événements avec tirets, valeur par défaut de chaque prop optionnelle. recommended, au-dessus, a été mesuré : 752 violations sur deux de nos bases de code, 84 % sur l'ordre des attributs, une réécriture de tous les templates sans gain. La variante -error est nécessaire : le preset déclare ses règles en warn, qu'aucune baseline ne retient et qui ne font jamais échouer le contrôle.
ESLint d'abord : yarn lint:baseline génère un fichier de suppressions qui fige les violations existantes, et seules les nouvelles font échouer lint:check. Prettier ensuite, au choix : le pragma @format pour y aller fichier par fichier ou un commit unique qui formate tout, dont le hash est inscrit dans .git-blame-ignore-revs. Le commit unique convient à un projet avec peu de fichiers front et peu de branches ouvertes, parce que chacune devra être rebasée. La résorption des suppressions entre ensuite dans le flux de la maintenance technique.
@vue/eslint-config-typescript, la configuration du template TypeScript de create-vue, branche typescript-eslint sur les fichiers .vue. defineConfigWithVueTs remplace defineConfig pour propager le parser aux blocs script. La vérification des types reste hors ESLint : vue-tsc --build s'en charge. Rien ne change pour Prettier ni pour la frontière entre les deux.
Non. Le bundle documente le standard front, mais sa recette Symfony Flex ne copie aucun fichier JavaScript : les contextes sont trop différents d'un projet à l'autre (Symfony avec Inertia, Vue seul, TypeScript ou non). Chaque projet applique la couche qui le concerne, extraits à l'appui, depuis la documentation du bundle.
Pour aller plus loin
Approfondir votre réflexion
La chaîne complète, PHP et front, le principe d'un outil par responsabilité et la commande make qa qui les enchaîne.
Le même partage des rôles côté PHP : la forme à PHP CS Fixer, le fond à PHPStan, et pourquoi PHP_CodeSniffer n'est plus là.
Le framework front de nos interfaces, dont l'outillage officiel dicte les deux outils de cette page.
Vous avez un projet ?
Contactez-nous pour savoir comment nous pouvons vous aider.