Prettier
Ahora añadimos Prettier encima de la configuración de ESLint que ya tenemos.
La idea es mantener esta separación:
1ESLint → detecta errores y problemas de calidad 2Prettier → da formato al código
Es precisamente el enfoque recomendado por Prettier: usar el linter para calidad de código y Prettier para formato. ([Prettier][1])
1. Instalar Prettier #
Desde la raíz del proyecto:
1npm install --save-dev --save-exact prettier@3.9.8
Actualmente la documentación oficial recomienda instalar Prettier localmente en el proyecto y fijar la versión exacta para que todo el equipo use el mismo formato. ([Prettier][2])
Podemos comprobarlo con:
1npx prettier --version
Deberías obtener:
13.9.8
2. Crear .prettierrc #
En la raíz del proyecto creamos:
1.prettierrc
Nuestro proyecto quedaría:
1mi-proyecto/ 2├── node_modules/ 3├── src/ 4│ └── main.js 5├── .prettierrc 6├── eslint.config.js 7├── index.html 8├── package.json 9└── package-lock.json
Prettier admite .prettierrc como archivo de configuración oficial. ([Prettier][3])
Para nuestro proyecto podemos usar:
1{ 2 "semi": false, 3 "singleQuote": false, 4 "tabWidth": 2, 5 "printWidth": 100 6}
¿Qué significa? #
1"semi": false
No añade ; al final:
1const nombre = "Ana"
en lugar de:
1const nombre = "Ana";
1"singleQuote": false
Utiliza comillas dobles:
1const nombre = "Ana"
en lugar de:
1const nombre = 'Ana'
Esto coincide con el estilo que ya estás usando.
1"tabWidth": 2
La indentación será de 2 espacios:
1function guardarPlan() { 2 const fechaHoy = dayjs().format("DD/MM/YYYY HH:mm") 3 4 if (input.value !== "") { 5 console.log(input.value) 6 } 7}
1"printWidth": 100
Prettier intentará dividir las líneas cuando sean demasiado largas.
Por ejemplo:
1const mensaje = "Este es un texto extremadamente largo que podría superar el ancho configurado"
podría ser reorganizado si fuese necesario.
3. Probar Prettier #
Ahora podemos hacer que Prettier revise nuestro proyecto:
1npx prettier . --check
El . significa:
revisa todos los archivos compatibles del proyecto.
Prettier puede trabajar directamente con JavaScript, HTML, CSS, JSON, Markdown, YAML, etc. ([Prettier][4])
Si encuentra archivos mal formateados, te avisará.
Por ejemplo:
1Checking formatting... 2src/main.js 3index.html 4 5Code style issues found in 2 files.
Pero todavía no los modifica.
4. Formatear automáticamente #
Para que Prettier corrija los archivos:
1npx prettier . --write
--write hace que Prettier reescriba directamente los archivos con el formato configurado. ([Prettier][5])
Por ejemplo, si tenemos esto:
1function guardarPlan(){ 2 const fechaHoy = dayjs().format("DD/MM/YYYY HH:mm") 3 const li = document.createElement("li") 4 li.textContent = input.value + " - " + fechaHoy 5 lista.appendChild(li) 6 input.value = "" 7}
al ejecutar:
1npx prettier . --write
se convierte en:
1function guardarPlan() { 2 const fechaHoy = dayjs().format("DD/MM/YYYY HH:mm") 3 const li = document.createElement("li") 4 li.textContent = input.value + " - " + fechaHoy 5 lista.appendChild(li) 6 input.value = "" 7}
Observa que Prettier:
1✓ corrige la indentación 2✓ añade espacios 3✓ mantiene las comillas 4✓ mantiene el estilo sin ; 5✓ organiza el formato
Pero no cambia la lógica del programa.
5. Prettier también formatea el HTML #
Nuestro HTML original tiene:
1<input id="texto" type="text" placeholder="Escribe lo que has hecho hoy"/>
Prettier lo convertirá en:
1<input 2 id="texto" 3 type="text" 4 placeholder="Escribe lo que has hecho hoy" 5/>
Y también arreglará la indentación general del documento.
Por ejemplo:
1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>Document</title> 7 </head> 8 9 <body> 10 <h1>Planificación del curso 2</h1> 11 12 <input 13 id="texto" 14 type="text" 15 placeholder="Escribe lo que has hecho hoy" 16 /> 17 18 <button id="añadir">Añadir</button> 19 20 <ul id="lista"> 21 <li>xxxxxxx</li> 22 </ul> 23 24 <script type="module" src="/src/main.js"></script> 25 </body> 26</html>
Además, aquí Prettier te deja visible un pequeño error que tenías en:
1<meta name="viewport" content="width= 2 , initial-scale=1.0">
Lo correcto sería:
1<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6. Añadir scripts a package.json #
Ahora podemos evitar tener que escribir:
1npx prettier . --write
Añadimos scripts:
1{ 2 "scripts": { 3 "dev": "vite", 4 "build": "vite build", 5 "preview": "vite preview", 6 "lint": "eslint src", 7 "format": "prettier . --write", 8 "format:check": "prettier . --check" 9 } 10}
Ahora tenemos:
1npm run lint
para ESLint.
1npm run format
para formatear.
Y:
1npm run format:check
para comprobar si el código está correctamente formateado sin modificarlo.
Este último comando será especialmente útil cuando más adelante añadamos CI/CD con GitHub Actions.
7. Crear .prettierignore #
También es recomendable crear:
1.prettierignore
Prettier recomienda este archivo para indicar qué carpetas o archivos no debería formatear. ([Prettier][2])
Ponemos:
1node_modules 2dist 3coverage
Aunque node_modules ya recibe un tratamiento especial por parte de Prettier, dejar claros los artefactos del proyecto hace la configuración más comprensible.
La estructura queda:
1mi-proyecto/ 2├── node_modules/ 3├── src/ 4│ └── main.js 5├── .prettierignore 6├── .prettierrc 7├── eslint.config.js 8├── index.html 9├── package.json 10└── package-lock.json
8. Hacer que ESLint y Prettier no se peleen #
Aunque nuestra configuración actual de ESLint es muy sencilla y no contiene reglas de formato, es buena práctica instalar:
1npm install --save-dev eslint-config-prettier
Su función es muy concreta:
desactivar reglas de ESLint que puedan entrar en conflicto con Prettier.
Esto es justamente lo que recomienda la documentación de Prettier cuando usamos ambas herramientas. ([Prettier][2])
Modificamos eslint.config.js.
Antes teníamos:
1import js from "@eslint/js" 2import globals from "globals" 3 4export default [ 5 { 6 files: ["src/**/*.js"], 7 8 languageOptions: { 9 ecmaVersion: "latest", 10 sourceType: "module", 11 globals: globals.browser, 12 }, 13 14 rules: { 15 ...js.configs.recommended.rules, 16 }, 17 }, 18]
Ahora añadimos:
1import js from "@eslint/js" 2import globals from "globals" 3import eslintConfigPrettier from "eslint-config-prettier/flat" 4 5export default [ 6 { 7 files: ["src/**/*.js"], 8 9 languageOptions: { 10 ecmaVersion: "latest", 11 sourceType: "module", 12 globals: globals.browser, 13 }, 14 15 rules: { 16 ...js.configs.recommended.rules, 17 }, 18 }, 19 20 eslintConfigPrettier, 21]
Es importante que:
1eslintConfigPrettier
esté al final, porque así puede desactivar cualquier regla anterior que pueda entrar en conflicto con Prettier. ([GitHub][6])
9. No necesitamos eslint-plugin-prettier #
Puedes encontrar tutoriales que instalan:
1npm install eslint-plugin-prettier
y hacen que Prettier funcione como una regla de ESLint.
Para este proyecto no lo haría.
Es más claro mantener:
1ESLint 2 │ 3 └── analiza calidad 4 5Prettier 6 │ 7 └── formatea
en lugar de:
1ESLint 2 └── ejecuta Prettier
Así además es más fácil explicar al alumnado qué hace cada herramienta.
10. Configurar VS Code #
Aquí es donde Prettier empieza a resultar realmente cómodo.
En VS Code instala la extensión:
Prettier - Code formatter
La documentación oficial recomienda utilizar Prettier desde el editor además de tenerlo instalado localmente en el proyecto. ([Prettier][7])
Después podemos hacer que formatee automáticamente al guardar.
Crea:
1.vscode/settings.json
con:
1{ 2 "editor.formatOnSave": true, 3 "editor.defaultFormatter": "esbenp.prettier-vscode" 4}
La estructura completa empieza a quedar:
1mi-proyecto/ 2├── .vscode/ 3│ └── settings.json 4├── node_modules/ 5├── src/ 6│ └── main.js 7├── .prettierignore 8├── .prettierrc 9├── eslint.config.js 10├── index.html 11├── package.json 12└── package-lock.json
Ahora puedes escribir algo deliberadamente feo:
1function guardarPlan(){ 2const fechaHoy=dayjs().format("DD/MM/YYYY HH:mm") 3const li=document.createElement("li") 4li.textContent=input.value+" - "+fechaHoy 5lista.appendChild(li) 6input.value="" 7}
Pulsas:
1Ctrl + S
o en Mac:
1⌘ + S
y automáticamente queda:
1function guardarPlan() { 2 const fechaHoy = dayjs().format("DD/MM/YYYY HH:mm") 3 const li = document.createElement("li") 4 li.textContent = input.value + " - " + fechaHoy 5 lista.appendChild(li) 6 input.value = "" 7}
11. Flujo de trabajo final #
Ahora el proyecto tiene dos comprobaciones claramente separadas:
1 PROYECTO 2 │ 3 ┌────────┴────────┐ 4 │ │ 5 ▼ ▼ 6 ESLint Prettier 7 │ │ 8 busca errores da formato 9 │ │ 10 ▼ ▼ 11 npm run lint npm run format
En el día a día:
1npm run dev
para desarrollar.
1npm run lint
para buscar problemas.
1npm run format
para formatear todo.
Y:
1npm run format:check
para verificar que todo está formateado correctamente.
Resultado #
Tu package.json tendría aproximadamente estos scripts:
1{ 2 "scripts": { 3 "dev": "vite", 4 "build": "vite build", 5 "preview": "vite preview", 6 "lint": "eslint src", 7 "format": "prettier . --write", 8 "format:check": "prettier . --check" 9 } 10}
Y conceptualmente el alumnado debería quedarse con esta diferencia:
1ESLint 2"Este código puede tener un problema." 3 4Prettier 5"Este código está mal colocado; te lo ordeno."