Vite React App — shadcn/ui— ESLint — Prettier —Husky — Lint-Staged initial setup

Sanjay K
YavarTechWorks
6 min readJun 3, 2024

--

When we decide to use shadcn/ui for our new React application, we need to follow the steps given in the installation page of shadcn/ui.

We need to choose the Vite option for creating the React application.

Run the following command in the terminal.

npm create vite@latest

This will ask for the name of the new React application that we need to create. Once we choose name, we need to choose the framework. Here I selected React.

After selecting framework, we need to choose variant. We shall select the TypeScript.

Now the project will be created and we should switch to the project directory. After switching to the project directory, we need to run the following commands to start the local development server.

npm install 
npm run dev

Now we need to install and initialize tailwind CSS in our project.

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

This will install tailwind css, postcss and autoprefixer as development dependencies. These packages supports tailwind css. The second command will initialize the tailwind css in our project and creates a tailwind.config.js file.

We need to add the following code in the tsconfig.json file.

// tsconfig.json
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
// ...
}
}

Run the following command to install @types/node as dev dependency.

# (so you can import "path" without error)
npm i -D @types/node

After installing, add the following code in the vite.config.ts file.

// vite.config.ts
import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})

Now we need to initialize shadcn/ui in our project. Run the following command.

npx shadcn-ui@latest init

It will ask for the following questions to configure components.json file.

Refer the below image for choosing the options.

Now the shadcn/ui is successfully initialized and we shall now add components to our projects.

To add a Button component from shadcn/ui, use the following command.

npx shadcn-ui@latest add button
// App.tsx
import { Button } from "@/components/ui/button"

export default function Home() {
return (
<div>
<Button>Click me</Button>
</div>
)
}

After adding the Button component, we shall import and use it like the image above.

Now we shall see how to install and configure Eslint, Prettier, Husky and Lint Staged in our application.

Run the following command to install these packages as dev dependencies.

npm i --save-dev eslint prettier husky lint-staged

Now, create a .prettierrc.json file in the root directory and add the configurations object. In my case, I added the following rules.

// .prettierrc.json file
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"bracketSpacing": true,
"printWidth": 100,
"endOfLine": "auto"
}

You can also add a .prettier ignore file to inform prettier not to write anything on those files.

// .prettierignore
package.json
package-lock.json
dist
node_modules

Now initialize the Eslint by running the command below.

npx eslint --init

A list of questions will be asked and we need to select the options. Refer the below image for answers.

It will also ask for installing some packages which supports Eslint in our project. We need to install them for added benefits.

Now, rename the .eslintrc.cjs file to .eslintrc.json and add the required rules. Since the .cjs file is not being detected by the Eslint, we are renaming it to .json file.

I added the following configurations and rules in the .eslintrc.json file. It is up to the project requirements. We can add or remove rules, if needed. I also have installed two extra packages eslint-config-prettier and eslint-plugin-prettier (very light weight) as dev dependency to resolve the conflicts arising between the prettier and eslint. If you use the rules given below, you must have these two packages installed, else you need to remove some rules.

Also, delete the automatically generated eslint.config.js file as it is not needed. The only configuration file needed for Eslint is .eslintrc.json file.

//.eslintrc.json

{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"ecmaVersion": 2021,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["@typescript-eslint", "react", "react-hooks", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"prettier"
],
"rules": {
// General rules
"no-console": ["error", { "allow": ["error"] }],
"no-debugger": "warn",
"no-dupe-else-if": "warn",
"no-irregular-whitespace": "warn",
"no-setter-return": "warn",
"no-unsafe-finally": "warn",

// Best Practices
"accessor-pairs": "error",
"array-callback-return": "warn",
"dot-notation": "warn",
"no-eq-null": "warn",
"no-eval": "error",
"no-cond-assign": "warn",
"no-prototype-builtins": "warn",
"no-inner-declarations": "warn",
"no-implicit-globals": "warn",
"no-type-assertion/no-type-assertion": "off",
"no-implied-eval": "error",
"no-new-func": "warn",
"no-return-await": "warn",
"no-proto": "warn",
"no-useless-catch": "warn",
"no-with": "error",
"require-await": "warn",
"no-extra-boolean-cast": "warn",
"no-empty": "off",
"no-case-declarations": "warn",
"no-global-assign": "warn",
"linebreak-style": 0,
"no-bitwise": "warn",
"no-nested-ternary": "warn",
"no-unneeded-ternary": "warn",
"spaced-comment": ["warn", "always"],

//ES6
"no-var": "warn",
"prefer-const": "warn",

// TypeScript specific rules
"@typescript-eslint/no-inferrable-types": "warn",
"@typescript-eslint/ban-types": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-var-requires": "warn",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-empty-function": "off",
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",

// Ignore no-unused-vars if prefixed with underscore
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
},
"settings": {
"react": {
"version": "detect"
}
}
}

Now we need to initialize git and the Lint-Staged package. Run the following command.

git init
npx mrm lint-staged

This will create a .husky folder in the root directory and it will have a pre-commit hook executing npx lint-staged command automatically like below.

It will also add some scripts in the package.json file automatically like below.

Add the following scripts in the package.json file

// package.json  
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,json,ts,tsx,scss,css}": [
"prettier --single-quote --write"
],
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --fix"
]
}

Now we are good to go. Now when we stage the changed files and commit them, firstly prettier writes the staged files and eslint checks the staged files. Here I have used a console.log statement in my App.tsx file and tried to commit it. But the commit got blocked by husky due to the eslint rule.

So our rules are working fine now.

Info:

The following are the uses of Eslint, Prettier, Husky and Lint-Staged packages:

Prettier is used to format and beautify the code. Eslint enforces coding standards and patterns.

Husky is used to run scripts during pre-commit or any kind of git hooks.

Lint-staged runs the scripts only on the files that are staged for committing, leaving all other files in the project or directory.

In this setup, we are running the lint-staged command on the pre-commit process and the lint-staged runs the prettier — single-quote — write followed by the eslint — fix.

So, if we commit the staged files, prettier formats these files and eslint checks for standards. If anything is wrong, it tries to fix it or it stops the commit and forces us to rectify the code before committing.

--

--