We are having some annoying HTML formatting issues using Angular, ESLint and Prettier within VSCode. For example, the following HTML
Van<span *ngIf="someCondition">af</span>
is rewritten as
Van
<span *ngIf="someCondition">af</span>
This introduces unwanted whitespace in the output. I have tried many things but I cannot get all the pieces working nicely together. Running Prettier directly on the input file gives no error.
We have a monorepo with several projects underneath a single PROJECT_DIR
inside a container workbench.
VSCode settings.json
:
{
"editor.tabSize": 2,
"[html]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true
},
"eslint.format.enable": true,
"eslint.options": {
"extensions": [".ts", ".html"]
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"html"
],
"eslint.workingDirectories": ["PROJECT_DIR"],
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": false
},
"prettier.configPath": "PROJECT_DIR/.prettierrc.json"
}
ESLint configuration PROJECT_DIR/.eslint.json
:
{
"root": true,
"ignorePatterns": ["projects/**/*"],
"overrides": [
{
"files": ["*.ts"],
"parserOptions": {
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"plugin:prettier/recommended"
],
"rules": {
/**
* Any TypeScript source code (NOT TEMPLATE) related rules you wish to use/reconfigure over and above the
* recommended set provided by the @angular-eslint project would go here.
*/
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
/**
* Always require explicit accessibility keyword except for constructors.
*/
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit",
"overrides": {
"constructors": "no-public"
}
}
],
"@typescript-eslint/typedef": [
"error",
{
"arrayDestructuring": true,
"arrowParameter": true,
"memberVariableDeclaration": true,
"objectDestructuring": true,
"parameter": true,
"propertyDeclaration": true,
"variableDeclaration": true,
"variableDeclarationIgnoreFunction": true
}
],
/**
* Generate a warning on unused variables, except for a few known names
* and names starting with an underscore.
*/
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^(_hostClass)$",
"args": "all",
"argsIgnorePattern": "^_"
}
],
/**
* Do not allow the var keyword, use const or let instead.
*/
"no-var": "error",
/**
* Do not allow useless constructors. Disable the ESLint base rule
* as it can report incorrect errors.
*/
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": ["error"],
/**
* Do not allow empty functions. Disable the ESLint base rule
* as it can report incorrect errors.
*/
"no-empty-function": "off",
"@typescript-eslint/no-empty-function": ["error"],
/**
* Do not allow empty interfaces.
*/
"@typescript-eslint/no-empty-interface": "error"
}
},
// NOTE: WE ARE NOT APPLYING PRETTIER IN THIS OVERRIDE, ONLY @ANGULAR-ESLINT/TEMPLATE
{
"files": ["*.html"],
"extends": ["plugin:@angular-eslint/template/recommended"],
"rules": {}
},
// NOTE: WE ARE NOT APPLYING @ANGULAR-ESLINT/TEMPLATE IN THIS OVERRIDE, ONLY PRETTIER
{
"files": ["*.html"],
"excludedFiles": ["*inline-template-*.component.html"],
"extends": ["plugin:prettier/recommended"],
"rules": {
// NOTE: WE ARE OVERRIDING THE DEFAULT CONFIG TO ALWAYS SET THE PARSER TO ANGULAR (SEE BELOW)
"prettier/prettier": [
"error",
{
"parser": "angular"
}
]
}
}
]
}
Prettier configuration PROJECT_DIR/.prettierrc.json
:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"printWidth": 100,
"endOfLine": "auto",
"overrides": [
{
"files": ["*.component.html"],
"options": {
"parser": "angular",
"htmlWhitespaceSensitivity": "strict"
}
},
{
"files": ["*.html"],
"options": {
"singleQuote": false,
"htmlWhitespaceSensitivity": "ignore"
}
},
{
"files": ["*.scss", "*.css"],
"options": {
"singleQuote": false
}
}
]
}