Unifying Code Style with ESLint and Prettier

Unifying Code Style with ESLint and Prettier

1. Background

In the previous article, we discussed the physical structure design based on Monorepo, and this time we will talk about how to unify code writing rules among developers who write code on top of it.

As the project scale increases, it has become common for multiple developers to modify the same file, leading to unnecessary Git diffs due to differences in indentation or quote styles. These style differences have caused repetitive discussions during the code review process, which have ultimately contributed to review fatigue.

Relying solely on organizing guidelines in the company wiki had limitations in resolving these issues, and an automated system was needed to enforce rules regardless of developer mistakes before the code is reflected in the remote repository.

In this article, we will share the process of establishing code conventions using ESLint and Prettier based on the Vue 3 and TypeScript environment, as well as how to apply the same rules in VS Code and IntelliJ environments.

2. Separation of Roles for ESLint and Prettier

To address these issues, it was first necessary to clearly distinguish the roles of ESLint and Prettier.

ESLint is a tool that validates code quality by detecting unused variables, potential bug patterns, incorrect code structures, etc.
On the other hand, Prettier is a tool that maintains consistent code formatting by automatically aligning visual rules such as indentation, line breaks, and quote styles.

The most common issue that arises when using both tools together is rule conflicts. Since ESLint also includes some style rules, it can assess the same areas differently from Prettier.

To resolve this, in this project, we configured it to use plugin:prettier/recommended so that the results of Prettier can be checked during the ESLint execution process. This allows us to check both code quality and formatting issues with just the ESLint execution.

An example of the ESLint settings applied in the project is as follows.

// .eslintrc
{
  "root": true,
  "env": {
    "node": true,
    "browser": true,
    "es2021": true
  },
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "parser": "@typescript-eslint/parser",
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:vue/vue3-recommended", // Vue 3 환경에서 권장되는 규칙 적용
    "plugin:prettier/recommended"
  ],
  "rules": {
    "vue/multi-word-component-names": "off", // 단일 단어 컴포넌트명 허용
    "no-console": "warn",
    "@typescript-eslint/no-explicit-any": "off"
  }
}

For reference, this example was written based on the .eslintrc based Legacy Config environment. Depending on the version of eslint-plugin-vue used in the project, either plugin:vue/vue3-recommended or plugin:vue/recommended can be used.

In addition, it is recommended to use Flat Config (eslint.config.js) in ESLint version 9 or higher, so for new projects, it is advisable to also refer to the official documentation.

3. Establishing Common Rules for the Project

Added .editorconfig to ensure that editors supporting EditorConfig follow the same basic rules within the project.

In particular, the end_of_line = lf setting helps reduce unnecessary Git diffs caused by differences in line ending styles (CRLF/LF) between Windows and macOS.

The meaning of each setting is as follows:

  • indent_style = space: Uniform indentation

  • indent_size = 2: Maintain default style for Vue/TS projects

  • end_of_line = lf: Prevent line ending conflicts between OSs

  • insert_final_newline = true: Ensure newline at the end of the file

  • trim_trailing_whitespace = true: Remove unnecessary whitespace

The EditorConfig settings are as follows:

# .editorconfig
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

4. IDE Environment Synchronization

Even if rules are defined, they lose their meaning if not applied consistently in the IDE. In practice, there have been recurring Git diffs due to formatting differences in an environment mixing VS Code and IntelliJ (including WebStorm).

4.1 Cause of the Problem

VS Code can easily apply Prettier based on extensions, but IntelliJ uses its own formatter by default, meaning that depending on the settings, an IDE formatter may run instead of Prettier. This has resulted in differing formatting outcomes for the same code depending on the IDE used.

4.2 Solution

4.2.1 VS Code Settings

In VS Code, I have set it up to automatically format on save and run ESLint fixes.

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

Note that the configuration for source.fixAll.eslint may vary depending on the versions of VS Code and the ESLint extension, and in the latest environments, using "explicit" is sometimes recommended.

4.2.2 IntelliJ Configuration

In the IntelliJ environment, I have unified the settings as follows.

  • Specify the Prettier path based on the project's node_modules

  • Enforce the use of Prettier during code reformatting

  • Delegate formatting on save to Prettier instead of the IDE formatter

This setting helped to minimize formatting differences between IDEs.

5. Causes and Solutions for Vue SFC Parsing Errors

During the initial implementation, ESLint parsing errors occurred inside Vue 3 Single File Components (SFC, .vue). Specifically, the <script setup lang="ts"> section was not interpreted correctly, causing abnormal TypeScript-related errors. This can occur when only using @typescript-eslint/parser without vue-eslint-parser, which understands the Vue SFC structure, or when the parser configuration is not correctly linked.

To resolve this, I separated the Vue structure and script section parser.

// .eslintrc
{
// ...생략
  "parser": "vue-eslint-parser", // 최상단 파서로 Vue 파일의 기본 구조 해석
  "parserOptions": {
    "parser": "@typescript-eslint/parser", // 스크립트 내부 영역만 TS 파서가 담당
    "ecmaVersion": "latest",
    "sourceType": "module"
},
// ...생략
}

After this setting, linting works properly on .vue files, and parsing errors have been resolved.

6. Operational Experience and Limitations

During the initial adoption, more than 200 lint errors occurred in the existing codebase. The main causes were the use of any, console.log, and violations of Vue component naming conventions. Enforcing all rules as errors could impact development speed, so initially, I used a strategy of setting some rules to warn or off and applying them gradually. Additionally, since console.log is frequently used during debugging, I initially operated no-console at the Warning level.

Also, in this phase, I did not apply Husky-based commit verification. Initially, I considered enforcing commit stages through lint-staged and Husky, but prioritized unifying the local development environment and stabilizing development experiences within the team. In the future, I am considering expanding the structure to validate code quality by adding ESLint checks at the commit stage or CI stage to avoid being affected by differences in development environments.

7. Conclusion

The most significant change felt after applying ESLint and Prettier was in the code review process. With a significant reduction in style modifications that are not directly related to functionality, developers were able to create an environment where they could focus more on business logic rather than code format. As a result, it helped reduce code review time and unnecessary change history, establishing a foundation for maintaining code quality above a certain level.

An automated code convention environment can serve as an important foundation for maintaining consistency in large-scale collaboration.

References

- ESLint Official Documentation: https://eslint.org/

- Prettier Official Documentation: https://prettier.io/

- EditorConfig Official Documentation: https://editorconfig.org/

- Vue ESLint Plugin Official Documentation: https://eslint.vuejs.org/

Code_Latte

Site footer