This article chronicles a small part of my journey towards creating a full website that can be rendered in three parallel frameworks and three parallel design systems (React + Material UI; Angular + Clarity; “Vanilla” JS + Carbon).
I am a huge fan of clean, readable, well-formatted code. Just as spaghetti code creates headaches in the best developers, there is a beauty and joy to reading clean code that has clearly been crafted with care, written with the sanity of “future developer” in mind.
But, developers are only human and, try as we might to adhere to best practices, inconsistencies and errors will inevitably creep in. This is especially true in formatting and syntax, two areas that will never be high prioirity focuses compared to feature delivery; but they deserve attention, nonetheless.
Thankfully, frontend developers have two tools that enforce almost all the code formatting and quality rules you could think of. Prettier maintains code formatting — use an IDE plugin like VSCode Prettier Plugin and it will format your files on save. And ESLint enforces a wide range of syntax rules and coding best practices that might otherwise sneak under the radar. Both packages are heavily customizable and extendable, but also come with very sensible defaults; as you’ll see in this article, I made very few modifications from the defaults, at this stage of the project.
The setup processes for both Prettier and ESLint are similar, so they can be described in parallel. In practice, I recommend configuring one and then the other, especially on a larger project, because they will make many small changes across your codebase. If you are working on a larger project, you may also find it useful to disable many or all of the rules first, and incrementally re-introduce them over a series of commits. This will help confirm that the changes are exactly as you expect, and prevent infuriating syntactical bugs from sneaking into your code.
To start, I installed Prettier and ESLint, along with ESLint Typescript support:
npm i -D prettier eslint
npm i -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
Next, I created the configuration files for each:
touch .prettierrc.js .eslintrc.js
You’ll find a lot of packages offer choices when it comes to your configuration file format. The standard set seems to be:
___config.json | .____rc | .___rc.js
When I can, I always choose the
development environments, etc.). My
.eslintrc.js file will include a simple example of how this feature can be leveraged.
Both Prettier and ESLint come with extensive rulesets, which include sensible defaults. While it takes a bit of time, it’s well worth reading through the rules and deciding which ones you want to implement in your codebase — every time I go through this process, I find I pick up a new idea about quality coding along the way.
Having gone through the rulesets, I included in my configuration files only those rules where I differed from the established defaults. As it happened, I only made one customization for Prettier, and only a handlful for ESLint.
Again, I’m illustarting these settings in parallel, but actually implemented them in sequence, and would recommend other developers do the same, especially on larger projects:
The only change I made to Prettier’s default configuration was to opt for single quotes instead of double quotes. Purely personal preference, I just think they made the code look less cluttered.
My ESLint configuration is slightly more complex, but not much. I added a few non-default rules, such as
no-console, which prevents
console.log() commands (usually created during debugging) from sneaking into your code. This is also where I took advantage of the
.js file format to increase my configurations readability.
ESLint allows you to set a rule to
Error, depending how strict you want your enforcement to be; you do this by setting their values to 0, 1, or 2, respectively. This is fine, translating between numbers and meaning increases the cognitive load of reading this file. By simply assigning constants at the top of the file (and commenting out the currently unused ones), my configuraiton file is now more clearly readable, and I know exactly what’s going to happen when each rule is broken.
The other line of note in the ESLint configuration is
extends, which enables the composition of configuration files. In this case, I built on top of both ESLint’s default and Typescript recommendations.
Two final pieces of preparation, and we’re ready to implement these code quality tools! The first is to create
.eslintignore files, so that the tools don’t try to fix code that isn’t ours (e.g.,
node_modules), or aren’t of concern to the project (e.g., Mac’s
The second is to enable the tools. For Prettier, I’ll do my first run manually:
// First run CHECKS my source code, tells me what it WOULD change
npx prettier -c ./src// Once I'm happy with its changes, I let it WRITE them to disk
npm prettier -w ./src
Going forward, I’ll use VSCode’s Prettier Plugin, which will automatically format files every time I save them. A key tool for improved DX!
Whereas Prettier focuses on formatting, ESLint actually catches potential errors and oversights; therefore, I want to make sure my code is properly “linted” as part of my build process. I made the following changes to my
"build": "run-s build:clean lint type webpack",
"lint": "eslint ./src",
I can now lint my code with
npm run lint, and that step is automatically included in my
npm build command chain.
As it happens, all the errors ESLint picked up in my code were two types of Typescript errors:
- It considered the typing
makeView(): Functionto be too generic; I agree with this, and it had been on my to-do list to clean up.
- It did not infer some types I thought it would — namely
makeView()'s HTMLElementreturn types. Ah well, easy enough to fix!
This commit shows the changes made by Prettier and ESLint. As you’ll see, a lot of little changes that result in much cleaner code, overall.