To be honest, "The best…" for anything is hard to argue and in most cases not true. Nevertheless, I chose this title because I'm documenting what I currently consider to be "the best" setup for my JavaScript projects.
This is not my first shot, but the result of my experiences over the last few years. I would also like to take this opportunity to thank my colleague Jay Watts for the many suggestions that have led to the current state of this setup.
The setup is quite simple and most of the time default configs are used.
🤓 Whilst there is a link to a GitHub template (React/Typescript) at the end of this article, following the steps below doesn't take long and I think it's worth doing it manually, especially the first time. If you feel like this is already to much effort, you probably don't need any of this and can just scaffold a default Vite project. You can always add these features later if you miss them.
Here is my take on "the best" setup in a few bullet points:
- GitHub
- Vite
- Prettier
- Import sorting (eslint plugin)
- lint-staged
- husky (pre-commit/pre-push hooks)
1. Create a new Vite project
Vite made my life so much easier by providing a simple way to setup a new bundler project with very good default configurations. It is just so powerful that you can easily bootstrap a setup that works out of the box in seconds. For many just creating a new Vite project might be good enough already.
To create a new Vite project all you need to do is run this command and follow the instructions:
npm create vite@latest
? Project name: › my-project
? Select a framework: › React
? Select a variant: › TypeScript
cd my-project
npm i
2. Init Git and create a .nvmrc
This are the two things I do every time I setup a new node project.
Early first commit
git init
git add --all
git commit -m "blank vite react/typescript project"
Create a .nvmrc
This file contains the version of node that is recommended for the project. If nvm
is installed on your system, you can run nvm use
in the project folder and nvm will automatically switch to the specified version.
node --version > .nvmrc
git add .nvmrc
git commit -m "create .nvmrc file"
💡Pro Tip You can set up a script that will automatically call nvm use whenever you enter a directory that contains an
.nvmrc
3. Prettier
Since I started using Prettier, there's no going back for me. Every time I save, my code is automatically formatted according to a uniform standard. I decided to just follow their default rules and got used to it quickly. This is a big time saver.
You can read my in depth article on how to install and configure Prettier (including configuring your editor) or follow the official installation guide
Here are the steps in a nutshell:
Install Prettier
npm install --save-dev --save-exact prettier
node --eval "fs.writeFileSync('.prettierrc','{}\n')"
git add --all
git commit -m "install prettier"
Format all files
npx prettier . --write
git add --all
git commit -m "format files with prettier"
4. Import sorting
This is another feature I don't want to miss anymore. Especially when your editor automatically adds imports it is cumbersome to sort them manually.
I have already written a separate article on this topic, which also contains my custom sorting configuration: Automatic import sorting with ESLint.
Here are the basic steps to set up automatic import sorting for your project:
Install ESLint plugin
I currently use ESLint for sorting imports. My plugin of choice is eslint-plugin-simple-import-sort
https://github.com/lydell/eslint-plugin-simple-import-sort
npm install --save-dev eslint-plugin-simple-import-sort
git add --all
git commit -m "install eslint-plugin-simple-import-sort"
Configuration
Enable the plugin and rule in your eslint config:
// .eslintrc.cjs
-- plugins: ["react-refresh"],
++ plugins: ["react-refresh", "eslint-plugin-simple-import-sort"],
// .eslintrc.cjs
rules: {
++ "simple-import-sort/imports": ["error"],
If you have set up the plugin in this way, you will receive ESLint errors if the imports are not sorted according to the rules. You can now run fix for all files to automatically fix these issues and sort your imports.
npx eslint --fix .
I highly recommended you setup your editor to "fix" automatically every time you save a file. You can find detailed instructions to set this up for VSCode in my automatic import sorting article.
git add --all
git commit -m "configure eslint-plugin-simple-import-sort"
5. Import sorting
I've never been a fan of sorting CSS properties alphabetically. Why should text-related styles, for example, be scattered? At the same time I do like sorting and have had my own (admittedly inconsistent) way of organizing properties.
Recently I stumbled upon prettier-plugin-css-order
which uses concentric-css (per default) to sort CSS properties. I just started using this, and I do have a very good feeling about it.
There is also the option to sort alphabetically (🙂↔️) and SMACSS (another opinionated sorting approach).
This is what concentric-css does:
Order properties applying outside the box model, moving inward to intrinsic changes.
- Positioning
- Visibility
- Box model
- Dimensions
- Text
Install prettier plugin
npm install --save-dev prettier-plugin-css-order
The docs suggest to also explicitly install postcss
but I think this can/should be skipped because Vite does this already.
Configuration
.prettierrc
{
"plugins": ["prettier-plugin-css-order"],
"cssDeclarationSorterKeepOverrides": false
}
The config cssDeclarationSorterKeepOverrides
is true
per default, but it is recommended to turn this off if you can.
Read more about what this does here: https://github.com/Siilwyn/css-declaration-sorter#keepoverrides
6. Pre-Commit and Pre-Push hooks
With Husky you can run checks on the code you are about to commit/push. I use this to enforce the formatting rules for all commits and check for Typescript issues before pushing. The fact that this rules trigger from time to time is a good indicator that they are indeed very helpful for me :-)
And lint-staged
is yet another tool that can run linters on staged files only.
As per Prettier docs you can run this command to automatically setup lint-staged and husky with a pre-commit hook. It will also add the necessary configuration to your package.json
npx mrm@2 lint-staged
Instead of the generated configuration I use this setup which does not allow you to commit anything with ESLint warnings and formats all files with prettier:
// package.json
…
"lint-staged": {
"*.{js?(x),ts?(x)}": [
"eslint --max-warnings 0",
"prettier --write --ignore-unknown"
],
"!*.{js?(x),ts?(x)}": "prettier --write --ignore-unknown"
}
…
git add --all
git commit -m "install/configure husky and lint-staged"
7. TypeScript checks with pre-push hook
Because for Typescript the context of "only staged files" is not enough, you need to run tsc
on the whole project instead of using lint-staged. As this takes a little longer, I do not want to run this for every commit but only before pushing code.
Add a pre-push file in the .husky directory:
mkdir -p .husky && touch .husky/pre-push
Copy this script to the created file:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
printf "\n[PRE-PUSH HOOK] Running tsc checks. This might take a few moments.\n\n"
npx tsc --noEmit
git add --all
git commit -m "add pre-push TypeScript check"
Done!
That's it, you can now start doing changes and enjoy your setup. Have fun!
And please let me know if this article has helped you. I am always happy to receive feedback and hear about your experiences.
GitHub Template Repository: https://github.com/receter/my-vite-react-template
Top comments (2)
Hard pass on git hooks. They generate more problems that advantages especially when you have complex git flow, need to merge/rebase/hard push, have problem with conflicts etc.
I prefer lint and prettier on save (action in editor/IDE) + same on CI/CD.
Hi dikamilo,
Can you still remember what problems you had with git hooks?
Also I would be interested in how you use prettier/lint in CI/CD.
Thanks for your comment!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.