Introduction
How many times have you gotten into arguments with your team about whether to use single or double quotes in your TypeScript code? Or about indentation in the HTML templates of your Angular components? Or whether the semicolon at the end of the line is really necessary? These “style wars”, although they may seem minor, consume time and energy in Angular application development, and can lead to inconsistencies in the codebase that hinder readability and maintenance.
In my previous articles, we explored how Husky helps us automate tasks in our Git commits and how ESLint (along with its specific plugins) monitors the quality and potential errors in our code, especially in the Angular TypeScript ecosystem. Today, we’re going to delve into the third key piece of this puzzle for modern and efficient Angular development: Prettier.
Although we’ve mentioned it before, in this article we’ll dive into what makes Prettier so special, how to configure it thoroughly, and most importantly, how to integrate it perfectly with Angular‘s linting tools (@angular-eslint) and Husky to create a workflow where code formatting is no longer a concern. Get ready to say goodbye to manual formatting and style debates in your Angular projects!
What Exactly is Prettier and Why Should You Use It? (Beyond the Basics)
Prettier defines itself as an opinionated code formatter. What does this mean?
- Code Formatter: Its sole mission is to take your source code (TypeScript, HTML, CSS/SCSS, JSON, etc.) and rewrite it following a set of consistent style rules. It handles line breaks, spacing, quotes, semicolons, parentheses, etc.
- Opinionated: Here’s the key. Prettier doesn’t try to be infinitely configurable. It implements a quite specific code style and offers only a limited number of options to modify it.
The “Opinionated” Philosophy: An Advantage?
Absolutely! In the context of Angular, where we work with complex TypeScript and HTML templates, Prettier‘s opinionated nature is a great strength:
- Eliminates Discussions: By adopting Prettier, the team accepts its style for both TS and HTML. No more debates about tabs vs. spaces or the placement of brackets in templates.
- Total Consistency: Ensures that all project code (components, services, modules, templates, styles) has exactly the same format. This drastically improves readability.
- Less Format Configuration: You don’t have to waste time defining hundreds of formatting rules in ESLint. You install Prettier, adjust a few key options, and let it handle how the code looks.
- Facilitates Adoption: It’s easier for new team members to adapt to the Angular project’s style: it’s automatic.
The Crucial Difference with @angular-eslint
It’s crucial to understand the division of responsibilities:
- @angular-eslint (and @typescript-eslint): Focuses on code quality, error detection, and adherence to specific best practices for Angular and TypeScript. It looks for problematic patterns (incorrect use of decorators, lifecycles, RxJS), unused variables, complex logic, etc. It can have formatting rules, but managing them is tedious and prone to conflicts with Prettier.
- Prettier: Focuses exclusively on code formatting (TS, HTML, CSS/SCSS, etc.). It doesn’t care about the logic, only the consistent visual presentation.
The conclusion is clear: They are not competitors; they are partners. The modern best practice in Angular is to use @angular-eslint for quality and framework-specific rules, and Prettier for formatting, configuring them to work together.
Installation and “In-Depth” Configuration
1. Installation:
Add Prettier as a development dependency. It’s highly recommended to use the --save-exact
option (or the Yarn equivalent) to prevent minor automatic updates from subtly changing the format and generating noise in commits.
# Using npm
npm install --save-dev --save-exact prettier
# Using yarn
yarn add --dev --exact prettier
2. Configuration File (.prettierrc
):
Prettier will look for a configuration file in your project root. You can use various formats, but .prettierrc.json
(or simply .prettierrc
with JSON inside) is common and easy to understand:
# Crea el archivo (ejemplo con JSON)
touch .prettierrc.json
Now, let’s explore some of the most important configuration options where you can ‘go deeper’:
printWidth
(default:80
): Maximum line length. Prettier will try to wrap lines that exceed this limit. A common value nowadays might be100
or120
.tabWidth
(default:2
): Number of spaces per indentation level.useTabs
(default:false
): Iftrue
, uses tabs instead of spaces for indentation.semi
(default:true
): Add semicolons at the end of statements. If set tofalse
, it will remove them where it’s safe to do so.singleQuote
(default:false
): Iftrue
, uses single quotes instead of double quotes for strings (except in JSX by default).quoteProps
(default:"as-needed"
): When to add quotes to object properties."consistent"
(if one property needs quotes, all will have them) or"preserve"
(respects the input) are other options.jsxSingleQuote
(default:false
): Iftrue
, uses single quotes in JSX.trailingComma
(default:"es5"
): Add trailing commas in multi-line arrays and objects where valid in ES5."all"
also does it in function parameters."none"
removes them. Using"es5"
or"all"
is great for Git diffs, as adding a new element only changes one line.bracketSpacing
(default:true
): Print spaces between braces in object literals:{ foo: bar }
vs{foo: bar}
.bracketSameLine
(default:false
): Iftrue
, places the closing>
of a multi-line HTML/JSX/Vue tag at the end of the last line, instead of on a new line. (is deprecated).jsxBracketSameLine
arrowParens
(default:"always"
): Add parentheses around a single arrow function parameter."avoid"
removes them:x => x
vs(x) => x
.endOfLine
(default:"lf"
): Controls line endings."lf"
(Linux/macOS),"crlf"
(Windows),"cr"
(rare),"auto"
(maintains existing line endings). This is important for teams working on different operating systems;"lf"
is usually the safest and standard option with Git.- Important for HTML: Prettier will also format your .html files. Options like printWidth, tabWidth, bracketSameLine directly affect how your templates look.
Example .prettierrc.json
:
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true, // Common preference in comunity TS/Angular
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false, // Put the ">" in the new line in HTML
"arrowParens": "always",
"endOfLine": "lf"
// Prettier detects automatically the TS and HTML parsers
Remember: Prettier’s idea is to minimize configuration. Start with the defaults and adjust only what your team strongly disagrees with or needs to change for a specific reason.
3. Ignoring Code (.prettierignore
):
Just like .gitignore
, you can create a .prettierignore
file to tell Prettier which files or folders it should not format. This is useful for node_modules
, build
folders (dist
, build
, coverage), automatically generated files, or perhaps very specific configuration files.
Example .prettierignore
:
# Ignoring dependencies and files in build
node_modules
dist
build
coverage
.angular/cache
# Ignore specific files
src/legacy/problematic-file.js
src/assets/generated-data.json
# Ignore all files with the specified extension from a certain folder
src/generated/**/*.svg
You can also ignore specific blocks of code within a file using a comment // prettier-ignore
in TypeScript or in HTML, right before the block. Use this sparingly, only when automatic formatting truly breaks something or makes a very specific case highly unreadable.
// prettier-ignore
matrix = [
1, 0, 0,
0, 1, 0,
0, 0, 1
];
Running Prettier Effectively
1. From the Command Line (CLI):
- Check formatting: Useful in CI (Continuous Integration) or to verify before a commit.
# Check all supported files in the project
npx prettier --check .
# Or specified TS y HTML in src/
npx prettier --check "src/**/*.{ts,html}"
- Format files: Rewrites files applying the format.
# Format all
npx prettier --write .
# or custom config: TS y HTML in src/
npx prettier --write "src/**/*.{ts,html}"
2. Scripts in package.json
:
It’s good practice to add scripts for easier execution:
// package.json
"scripts": {
// ... other scripts (ng serve, ng build...)
"format": "prettier --write \"./src/**/*.{ts,html,scss,json,md}\"", // Adjust patterns as you need
"check-format": "prettier --check \"./src/**/*.{ts,html,scss,json,md}\""
}
Now you can run npm run format
or npm run check-format
.
3. Editor Integration (The Magic Happens Here!)
This is the most convenient way to use Prettier day-to-day. Almost all modern editors (VS Code, WebStorm, Sublime Text, etc.) have extensions for Prettier.
- Install the Extension: Search for “Prettier” in your editor’s marketplace (e.g., “Prettier – Code formatter” for VS Code).
- Configure “Format on Save”: The most popular option is to configure your editor to automatically format the file every time you save it. In VS Code, this is done in the settings (JSON or UI):
// settings.json (VS Code)
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode", // ensure this is the default
// Apply Format on Save to Angular languages
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": { // For the Angular templates
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": { // If you use SCSS
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// etc. for json, md...
}
- Use the Project Version: Ensure your editor’s extension is configured to use the Prettier version installed in your project (
node_modules/prettier
) instead of a global version. This ensures the entire team uses the exact same version and rules. Most extensions do this by default nowadays.
With “Format on Save“, Prettier becomes almost invisible. You just write your code and upon saving… Poof! It’s automatically formatted.
The Perfect Integration: Prettier + ESLint + Husky (Putting It All Together)
This is where we connect everything for a robust workflow in Angular. The goal is to ensure that ESLint (configured with @angular-eslint) handles code quality and specific Angular/TypeScript rules, while Prettier takes care exclusively of formatting, and Husky automates verification before each commit.
1. Prettier with @angular-eslint:
We need ESLint not to interfere with Prettier‘s formatting rules.
- Install necessary dependencies (if you don’t have them): Ensure you have key packages installed like eslint, @typescript-eslint/parser, @typescript-eslint/eslint-plugin, @angular-eslint/eslint-plugin, @angular-eslint/template-parser, @angular-eslint/eslint-plugin-template. For Prettier integration, you’ll need eslint-config-prettier (to disable conflicting rules) and optionally eslint-plugin-prettier (to report formatting differences as ESLint errors).
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin @angular-eslint/eslint-plugin @angular-eslint/template-parser @angular-eslint/eslint-plugin-template eslint-config-prettier eslint-plugin-prettier
# Or use ng add @angular-eslint/schematics if your start from scratch and put prettier ones as you need
- Configure
.eslintrc.json
:
The key is to useeslint-config-prettier
to disable conflicting rules, and optionallyeslint-plugin-prettier
to integrate formatting checks. The typical structure in Angular usesoverrides
to separate the configuration for TypeScript and HTML files.
// .eslintrc.json
{
"root": true,
"ignorePatterns": ["projects/**/*"], // Adjust based on your project structure (e.g., mono-repo)
"plugins": [
// Add 'prettier' here if you're using eslint-plugin-prettier
"prettier"
],
"overrides": [
{
// Configuration for TypeScript files (*.ts)
"files": ["*.ts"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json"], // Make sure this points to your tsconfig
"createDefaultProgram": true
},
"plugins": [
"@typescript-eslint",
"@angular-eslint"
// 'prettier' is added globally if using the plugin
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended", // Base TypeScript rules
"plugin:@angular-eslint/recommended", // Angular-specific rules for TS
// VERY IMPORTANT: Put at the end to disable conflicting rules:
"prettier" // From eslint-config-prettier
],
"rules": {
// Customize Angular or TS rules as needed
"@angular-eslint/directive-selector": ["error", { "type": "attribute", "prefix": "app", "style": "camelCase" }],
"@angular-eslint/component-selector": ["error", { "type": "element", "prefix": "app", "style": "kebab-case" }],
// If using eslint-plugin-prettier, add this rule:
"prettier/prettier": "error" // Reports Prettier formatting issues as ESLint errors
}
},
{
// Configuration for Template files (*.html)
"files": ["*.html"],
"parser": "@angular-eslint/template-parser",
"plugins": [
"@angular-eslint/template"
],
"extends": [
"plugin:@angular-eslint/template/recommended", // Angular rules for HTML templates
"plugin:@angular-eslint/template/accessibility" // Optional: Accessibility rules
// Note: Prettier formats HTML directly. It's uncommon to add 'prettier' here
// in 'extends' because eslint-config-prettier mainly affects TS/JS conflicting rules.
],
"rules": {
// You can add or override specific template rules here
// If you want to report Prettier formatting for HTML via ESLint (less common):
// "prettier/prettier": ["error", { "parser": "angular" }]
}
}
]
}
- eslint-config-prettier (included when you put “prettier” in extends at the end of the TS section) disables ESLint/@angular-eslint rules that conflict with Prettier.
- eslint-plugin-prettier (if added to global plugins and you configure the “prettier/prettier”: “error” rule in the TS section) makes formatting differences in TypeScript files report as ESLint errors, visible in the editor and when running eslint.
2. Prettier with Husky (and lint-staged):
Ensures that only well-formatted code without lint errors reaches your Git repository.
- Install lint-staged:
npm install --save-dev lint-staged
content_copydownloadUse code with caution.Bash
npm install --save-dev lint-staged
- Configure lint-staged in package.json:
Define which commands to run on files that are in the Git staging area (.ts, .html, .scss, etc.).
// package.json
"lint-staged": {
// For TypeScript and HTML files
"*.{ts,html}": [
"eslint --fix", // First, let ESLint fix what it can (including formatting if using the plugin)
"prettier --write" // Ensure final formatting with Prettier (important if ESLint doesn’t cover everything)
],
// For other file types (SCSS, JSON, Markdown...) supported by Prettier
"*.{scss,css,json,md}": [
"prettier --write"
]
}
(The eslint –fix / prettier –write order might need adjustments based on your exact configuration. Running both is often a safe strategy to cover all cases. prettier –write ensures the final format is Prettier’s, even if ESLint didn’t fully apply it).
- Configure the Husky pre-commit Hook:
Make sure your script in .husky/pre-commit runs lint-staged.
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
(And make sure the file has execute permissions: chmod +x .husky/pre-commit).
The Complete Flow in Angular:
Now, when a developer on your team runs git add
- Husky intercepts the commit and runs the pre-commit script.
- The pre-commit script launches npx lint-staged.
- lint-staged identifies the modified files in the staging area that match the configured patterns (.ts, .html, .scss…).
- It runs the associated commands (eslint –fix, prettier –write) only on those modified files.
- If the commands succeed (format and/or fix errors without failing), lint-staged will finish successfully. Files potentially modified by the commands will be automatically included in the commit.
- If lint-staged succeeds, the commit will complete with the clean and formatted files.
- If any of the commands fail (e.g., ESLint finds a serious error it cannot fix automatically), lint-staged will fail, the pre-commit script will fail, and the commit will be aborted, showing the error to the developer so they can fix it before trying to commit again.
Magic! You have a robust and automatic system that ensures all code entering your Angular repository is correctly formatted according to Prettier and complies with the quality rules defined in @angular-eslint.
Conclusion
Prettier is much more than a simple formatter; it’s an essential tool in modern Angular development. It brings automatic consistency to the format of your TypeScript, HTML, and CSS/SCSS code, reduces team friction by eliminating style debates, and frees up mental bandwidth by removing the worry of manual formatting.
When combined with the powerful quality rules of @angular-eslint and the automation of Husky + lint-staged, you form an unbeatable trio that elevates the quality, readability, and maintainability of your Angular projects. It allows you and your team to focus on what really matters: building amazing features for your applications, knowing that the codebase stays clean and consistent automatically.
If you haven’t integrated Prettier into your Angular workflow yet, now is the perfect time to do it! The initial investment in configuration pays off handsomely in long-term peace of mind and efficiency.
Call to Action (CTA)
What about you? Do you already use Prettier in your Angular projects? What @angular-eslint and Prettier configuration works best for you? Have you faced any specific challenges integrating it with Husky or lint-staged? Share your experience and tips in the comments!
And if you missed the previous articles on the other key tools in this workflow:
- [Link to your article about Husky]
- Set up ESLint in Angular to achieve clean and maintainable code
Leave A Comment