Introduction
The create-react-app is the go-to approach to quickly set up a react application for a long time. But with the introduction of Vite bundler, things have changed dramatically. With the right set of tools, you will see how much easier and super fast your React app can be built. The developer experience with this is pure bliss compared to the create react app(CRA) because of the following reasons,
- CRA abstracts a lot of technologies or tools that are used to deliver the final bundle so as a developer you will have a limited understanding of what is happening under the hood, which is kind of a bummer for your career.
- It uses a lot of popular third-party packages internally that are not exposed to the outside world which makes it difficult to customise.
- It may not support all the latest libraries or tools that you intend to use.
Objective
The main objective of this article is to get your hands dirty and understand what it takes to build a simple hello-world application from scratch.
Technologies/Features used
The app we are going to build will have the following features. Again this is my set of tools feel free to change it based on your preference.
Feature | Technology used |
---|---|
Package manager | PNPM |
Package bundler | Vite |
Programming language | Typescript |
JS Framework/library | React |
CSS library | TailwindCss |
Basic linting | ESLint |
Code formatting | Prettier |
Pre-commit hook validator | Husky |
Linting only staged files | lint-staged |
Lint git commit subject | commitlint |
Prerequisites
Tools
You will need the following things properly installed on your computer.
PNPM install
- If you have installed the latest v16.x or greater node version in your system, then enable the pnpm using the below cmd
corepack enable
corepack prepare pnpm@latest --activate
- If you are using a lower version of the node in your local system then check this page for additional installation methods https://pnpm.io/installation
App creation
- Let's create our app by running these commands.
pnpm create vite react-app-v2 --template react-ts
pnpm create vite <app-name> --template react-ts
cd <app-name>
pnpm install && pnpm update
That's it, your app is ready. Run pnpm dev
and check out your app.
- Initialize git if you want and enforce the node version with some info in the README.md.
git init
echo -e "node_modules\ncoverage" > .gitignore
npm pkg set engines.node=">=20.11.0" // Use the same node version you installed
- Specify the latest PNPM version to use for this project by setting the packageManager property in the package.json file.
npm pkg set packageManager="pnpm@9.12.3"
pnpm -v
Code formatter
I'm going with Prettier to format the code. Formatting helps us to keep our code uniform for every developer.
Installation
Let's install the plugin and set some defaults. Here I'm setting the single quote to be true, update it according to your preference.
pnpm add -D prettier
echo '{\n "singleQuote": true\n}' > .prettierrc.json
echo -e "coverage\npublic\ndist\npnpm-lock.yaml" > .prettierignore
VS Code plugin
- If you are using VS Code, then navigate to the
Extensions
and search forPrettier - Code formatter
and install the extension.
Extension link: https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
Let's update the workspace to use the prettier as the default formatter and automatically format the file on save.
Create the workspace settings JSON and update it with the following content.
mkdir .vscode && touch .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.associations": { "*.svg": "html" },
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
- Now open the
src/App.tsx
in your VSCode editor and save it. If the semicolons are automatically created then it confirms that our auto formatting is working fine.
Linting
Vite react-ts
template comes with a built-in ESLint setup which covers the plugins for react and typescript support.
The vite starter template recommends few improvements to the linter for production app in the Readme file so lets add that as well.
Let's add a few more plugins to keep our linting strong.
- Install the eslint-plugin-jsx-a11y and eslint-plugin-react
pnpm add -D eslint-plugin-react eslint-plugin-jsx-a11y
- The updated linter configuration will look something like this,
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import react from 'eslint-plugin-react'
import jsxA11y from 'eslint-plugin-jsx-a11y'
export default tseslint.config(
{ ignores: ['coverage', 'public', 'dist', 'pnpm-lock.yaml'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
parserOptions: {
ecmaFeatures: { jsx: true },
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'jsx-a11y': jsxA11y,
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
'react/react-in-jsx-scope': 'off',
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
settings: { react: { version: 'detect' } },
}
)
Integrating Prettier with ESLint
Linters usually contain not only code quality rules but also stylistic rules. Most stylistic rules are unnecessary when using Prettier, but worse – they might conflict with Prettier!
We are going to use Prettier for code formatting concerns, and linters for code-quality concerns. So let's make the linter to run the stylistic rules from prettier instead.
- Install the necessary plugins
pnpm add -D eslint-config-prettier eslint-plugin-prettier
- Add the
eslintPluginPrettierRecommended
as the last element in the array.
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
/** @type {import('eslint').Linter.Config[]} */
export default [
...,
{
extends: [
js.configs.recommended,
...tseslint.configs.recommended,
eslintPluginPrettierRecommended,
],
...
}
]
For more info on this: https://prettier.io/docs/en/integrating-with-linters.html
- Let's create scripts for running the linter and prettier in the package.json file.
npm pkg set scripts.lint="eslint ."
npm pkg set scripts.format="prettier --write ."
- Run the
pnpm lint
cmd to run the ESLint. If it throws, errors like below then our linter prettier integration is working as expected.
To fix it just run pnpm format
cmd and run the pnpm lint --fix
cmd again. Now the errors should be gone.
Pre-commit hook validation
Even if we added all these linter and formatter mechanisms to maintain the code quality, we can't expect all the developers to use the same editor and execute the lint
and format
command whenever they are pushing their code.
To automate that we need some kind of pre-commit hook validation. That's where husky and lint-staged plugins come in handy let's install and set them up.
- Install the husky, commitlint, and lint-staged NPM package and initialize it as shown below,
pnpm add -D @commitlint/cli @commitlint/config-conventional
echo -e "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.mjs
pnpm add -D husky lint-staged
pnpm exec husky init
echo "pnpm lint-staged" > .husky/pre-commit
echo "npx --no -- commitlint --edit \${1}" > .husky/commit-msg
- Update the package.json file and include the following property. This will run the ESLint on all the script files and prettier on the other files.
"lint-staged": {
"**/*.{js,ts,jsx,tsx}": [
"eslint --fix"
],
"**/*": "prettier --write --ignore-unknown"
},
Absolute path import support
We often move around the files to make it more meaningful, when we are doing that, it would be great if we don't have to update the import statements. To do that,
- Install the @types/node NPM package
pnpm add -D @types/node
- Open the vite.config.ts file and update it like this,
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: { alias: { src: resolve('src/') } },
})
The resolve
property helps us to use absolute import paths instead of relative. For ex:
import { add } from 'src/utils/arithmetic'
import { App } from 'src/components/app'
App code cleanup:
- Update the
App.tsx
with the following content,
export const App = () => {
return <div className="font-semibold text-lg text-green-500">Rendered from react app</div>
}
- Delete the App.css file
rm -rf src/App.css
- Update the Import in the
src/main.tsx
file
- import App from "./App";
+ import { App } from "./app";
- Run the app and you will see the content in the
app.tsx
with tailwind classes applied.
pnpm dev
Next part
In the next part of this series, we will see how to add styling support and image rendering using SVG.
Top comments (0)