Whether you work in a team or by yourself, having consistently formatted code is important for readability and maintainability.

Tl;dr

Use Prettier to automatically format your JavaScript and use husky and lint-staged to add a precommit script that runs Prettier and your tests when you commit.

Check out the full code:

ESLint vs JavaScript Standard Style vs Prettier

For JavaScript there are solutions like ESLint that can check if your code is consistent. But ESLint requires a lot of configuration and while it can fix some things by itself, it often requires manual intervention when you screw up.

Then there is JavaScript Standard Style. This module is the complete opposite of ESLint. It requires no configuration and can also fix some of your code by itself. But having no configuration, it’s very opinionated.

And now there is also Prettier. The difference between Prettier and other lint tools is that Prettier doesn’t check your code. It just takes your code as input and spits out formatted code as output. Like JavaScript Standard Style, Prettier is opinionated but you have some options to customize the format. Because Prettier doesn’t check your code but parses it, everything will be fixed automatically. Sounds like the best of both worlds.

Hello Prettier

The best way to see the greatness of Prettier is to try it out.

Fire up your terminal and start typing:

mkdir pretty_husky

cd pretty_husky

npm init -y

npm install --save-dev prettier

mkdir src

touch ./src/foo.test.js

code .

Now you can write some poorly formatted code in foo.test.js:

test('this needs to be prettier.', () => {

expect(4).toBe(4)

})

And add a script package.json to run Prettier:

"scripts": {

"pretty": "prettier --write --tab-width 4 \"src/**/*.js\""

}

Now you can run Prettier from your terminal:

npm run pretty

And you can see that the contents of foo.test.js have changed to:

test("this needs to be prettier.", () => {

expect(4).toBe(4);

});



What about that husky?

Prettier makes your code look pretty but what if you forget to run it before you check in?

You could run Prettier as a step during continuous integration but then you have to check your code in again if there are changes. It would be much easier if you made sure that no “ugly” files can be pushed or committed.

This is where husky comes in. Husky makes creating git hooks easy. Git hooks are scripts that git executes before or after and event. If husky runs Prettier for us then “ugly” files can never be committed. But it’s not that easy. Husky can run Prettier but the changed files won’t be added to our commit.

This problem can be solved by lint-staged. Lint-staged can run a lint tool, like Prettier, and immediately add them to the staged files.

Hook me up!

If you haven’t created a git repository yet now is the time, your hooks won’t work without a repository:

git init

touch .gitignore

Add “node_modules” to the .gitignore file to avoid checking in too much:

node_modules

Go back to your terminal and install husky for the hooks, lint-staged for adding the formatted files to the staged files and Jest to run some tests:

npm install --save-dev husky lint-staged jest

Create some scripts to hook everything up in your package.json file:

"scripts": {

"test": "jest",

"pretty": "prettier --write --tab-width 4 \"src/**/*.js\"",

"precommit": "lint-staged && npm test" <-- Don't do this anymore

},

"lint-staged": {

"*.js": [

"npm run pretty",

"git add"

]

}

This story was written ages ago and in the meantime Husky has had quite some updates.The “precommit” script in the above code snippet won’t work anymore.

Create the correct scripts to hook everything up in your package.json file:

"scripts": {

"test": "jest",

"pretty": "prettier --write --tab-width 4 \"src/**/*.js\""

},

"lint-staged": {

"*.js": [

"npm run pretty",

"git add"

]

},

"husky": {

"hooks": {

"pre-commit": "lint-staged"

}

}

If you have an existing project that needs updating you can also run npx --no-install husky-upgrade from your console as described here.

Make some ugly and failing tests in foo.test.js:

test('ugly', () => {

expect(4).toBe(4)

}) test('failing', () => {

expect(4).toBe(5);

});

Now try to commit:

git add .

git commit -m"will this work?"

The script ran and the test failed, foo.test.js got updated:

test("ugly", () => {

expect(4).toBe(4);

}); test("failing", () => {

expect(4).toBe(5);

});

And husky stopped the commit:

husky > pre-commit hook failed (add --no-verify to bypass)

If you fix the test and try again the commit should work.

Conclusion

Prettier, husky and lint-staged can improve your workflow by formatting your JavaScript files and running some scripts before every commit.

Check out the full code on GitHub.