Language: [๐ช๐ธ] Espaรฑol - [๐บ๐ธ] English
Vite is by far the best alternative for creating React projects today.
npm create vite@latest <project-name> -- --template <react-swc|react-swc-ts>
# npm 7+, extra double-dash is needed
cd <project-name>
npm install
npm run dev
With these commands, we create a very basic and clean project to serve as a starting point, but it will gonna need some extra tools to automate tasks that can make your life and the life of your development team easier.
VSCode
It's recommended to make these configurations on project settings and not in the global settings.
We will start creating a .vscode
folder with a settings.json
file inside.
# ๐ File: /.vscode/settings.json
-----------------------------------
{
"explorer.fileNesting.patterns": {
"*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js, $(capture)*.snap",
"*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx, $(capture)*.snap",
"*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts, $(capture)*.snap",
"*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx, $(capture)*.snap",
},
"emmet.excludeLanguages": [],
"emmet.includeLanguages": {
"markdown": "html",
"javascript": "javascriptreact",
"typescript": "typescriptreact"
},
"emmet.showSuggestionsAsSnippets": true,
"emmet.triggerExpansionOnTab": true,
"files.exclude": {
"**/*.js.map": {
"when": "$(basename)"
},
"**/node_modules": true,
},
"html.autoClosingTags": true,
"javascript.autoClosingTags": true,
"javascript.suggest.completeFunctionCalls": true,
"typescript.suggest.completeFunctionCalls": true,
"javascript.inlayHints.functionLikeReturnTypes.enabled": true,
"typescript.inlayHints.functionLikeReturnTypes.enabled": true,
"javascript.inlayHints.parameterNames.enabled": "all",
"typescript.inlayHints.parameterNames.enabled": "all",
"javascript.suggest.autoImports": true,
"search.exclude": {
"**/coverage": true,
"**/node_modules": true
},
"typescript.autoClosingTags": true,
"typescript.suggest.autoImports": true,
}
There are a lot of VSCode extensions and configurations out there. If you are hungry for more check VSCode - Essentials and VSCode - React Flavored.
Debugging
There is no need to install an extra extension for debug React from VSCode.
# ๐ File: /.vscode/launch.json
-----------------------------------
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome", //or "msedge"
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}
If you want to disable the browser opening each time add BROWSER=none
on .env
file in your project. Also change the dev script to use the same port.
# ๐ File: package.json
-----------------------------------
{
"scripts": {
- "dev": "vite",
+ "dev": "vite --port 3000",
}
}
Run the npm run dev
command and start the browser from the Run and Debug panel
. Now you can add break points directly on the VSCode.
Or if you only need a quick verification use the Simple Browser inside VSCode.
VSCode - Hidden Browser Inside
Camilo Martinez ใป Apr 3 '23
Extensions
If you want that VSCode show extensions recommendation when open the project
# ๐ File: /.vscode/extentions.json
-----------------------------------
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"stylelint.vscode-stylelint",
"ZixuanChen.vitest-explorer"
]
}
Linter
- ES Lint extension
# ๐ File: /.vscode/settings.json
-----------------------------------
{
+ "editor.formatOnSave": true,
+ "javascript.format.enable": false,
+ "javascript.validate.enable": true,
+ "typescript.format.enable": false,
+ "typescript.validate.enable": true,
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": true
+ }
}
Install and config on the project folder:
npm install -D eslint
npm init @eslint/config
You can choose the better for you, but my opinionated configurations are:
Use: To check syntax, find problems, and enforce code style
Type of modules: JavaScript modules (import/export)
Framework: React
Typescript: No #or Yes if the project uses it
Run: Browser #and Node if use Next.js
Style guide: Popular -> Standard #JS without semi-colon ;
Format: JSON
Semi-colon exception
Because thestandard
style guide does not use semi-colons (;
) take this in mind. If the next statement right after the line without a semicolon starts with one of the following special operators[
,(
,+
,\
*,/
,-
,,
,.
, it will be recognized as an expression to the previous statement. Then you are going to need to start the line with;
.
You will be asked to install extra packages. Answer yes. When finish update configurations rules
:
# ๐ File: .eslintrc.json
-----------------------------------
{
"rules": {
+ "no-console": "warn",
+ "react/prop-types": "off",
+ "react/self-closing-comp": "warn",
+ "react/react-in-jsx-scope": "off"
},
+ "settings": {
+ "react": {
+ "version": "detect"
+ }
+ }
}
If you are using TypeScript
also need to add this configuration:
# ๐ File: .eslintrc.json
-----------------------------------
{
"parserOptions": {
+ "project": ["tsconfig.json"],
+ "createDefaultProgram": true
},
"rules": {
"no-console": "warn",
"react/prop-types": "off",
"react/self-closing-comp": "warn",
+ "@typescript-eslint/consistent-type-definitions": ["error", "type"],
+ "@typescript-eslint/explicit-function-return-type": "off",
},
}
Create a .eslintignore
file on the root of the folder project:
# ๐ File: .eslintignore
-----------------------------------
build
coverage
dist
There is no need to add
node_modules
because it was ignored by default.
If you don't want to use ES Lint
extensions, add list
and fix
command at end of scripts
:
# ๐ File: package.json
-----------------------------------
{
"scripts": {
+ "lint": "eslint .",
+ "lint:fix": "eslint . --fix --ext .js,.jsx,.ts,.tsx"
}
}
Avoid import React error
Since React 17, you don't need to
import React
to use JSX anymore. But we would still need to import React to use Hooks or other exports that React provides.
To avoid ES Lint
warns about import React, add a plugin:
# ๐ File: .eslintrc.json
-----------------------------------
{
"extends": [
"plugin:react/recommended",
"standard-with-typescript",
+ "plugin:react/jsx-runtime",
],
}
Blank Lines
If you want to preserve a blank line's previous definitions.
# ๐ File: .eslintrc.json
-----------------------------------
{
"rules": {
+ "padding-line-between-statements": [
+ "error",
+ {
+ "blankLine": "always",
+ "prev": "*",
+ "next": "return"
+ },
+ {
+ "blankLine": "always",
+ "prev": [
+ "const",
+ "let",
+ "var"
+ ],
+ "next": "*"
+ },
+ {
+ "blankLine": "any",
+ "prev": [
+ "const",
+ "let",
+ "var"
+ ],
+ "next": [
+ "const",
+ "let",
+ "var"
+ ]
+ }
+ ]
},
}
Auto sort
If you don't want to deal with sorting imports and properties set this configuration.
# ๐ File: .eslintrc.json
-----------------------------------
{
"rules": {
+ "import/order": [
+ "warn",
+ {
+ "pathGroups": [
+ {
+ "pattern": "~/**",
+ "group": "external",
+ "position": "after"
+ }
+ ],
+ "newlines-between": "always-and-inside-groups"
+ }
+ ],
+ "react/jsx-sort-props": [
+ "warn",
+ {
+ "callbacksLast": true,
+ "shorthandFirst": true,
+ "noSortAlphabetically": false,
+ "reservedFirst": true
+ }
+ ]
},
}
ย Format
ES Lint
can be enough, and Prettier it's optional because have a better performance formatting thanES Lint
. If you want to use it go ahead. But there is a problem, they fight to try both to format code, so you have to know how to configure them to work together.
If you want to use it go ahead.
- Prettier - Code formatter extension
# ๐ File: /.vscode/settings.json
-----------------------------------
{
- "editor.codeActionsOnSave": {
- "source.fixAll.eslint": true
- }
+ "eslint.probe": [
+ "javascript",
+ "javascriptreact",
+ "typescript",
+ "typescriptreact"
+ ],
+ "[javascript][typescript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": false,
// Runs Prettier, then ESLint
+ "editor.codeActionsOnSave": [
+ "source.formatDocument",
+ "source.fixAll.eslint"
+ ],
+ }
}
Install Prettier:
npm install -D prettier
And ESLint (JS) for prettier:
npm install -D eslint-config-prettier
Or TSLint (TS) for prettier:
npm install -D tslint-config-prettier
Create a .prettierignore
file on the root of the folder project:
# ๐ File: .prettierignore
-----------------------------------
build
coverage
dist
package-lock.json
There is no need to add
node_modules
because it was ignored by default.
Create a .prettierrc.json
file on the root of the folder project:
# ๐ File: .prettierrc.json
-----------------------------------
{
"semi": false,
"singleQuote": true
}
Add extends prettier configuration at the end of extends
:
# ๐ File: .eslintrc.json
---
{
"extends": [
"plugin:react/recommended",
"standard-with-typescript",
"plugin:react/jsx-runtime",
+ "prettier", //at last
],
}
If you don't want to use prettier extensions, add check
and write
command at end of scripts
:
# ๐ File: package.json
-----------------------------------
{
"scripts": {
+ "format": "prettier . --check",
+ "format:fix": "prettier . --write"
}
}
HTML Linter
npm install -D htmlhint
If you also want to lint HTML with eslint
install this additional plugin:
npm install -D eslint-plugin-html
And add html
to the list of plugins
# ๐ File: .eslintrc.json
-----------------------------------
{
"plugins": [
"react",
+ "html"
],
}
CSS Linter
- Stylelint extension
Install and config on the project folder:
npm install -D stylelint stylelint-config-standard stylelint-config-idiomatic-order
Create a configuration file named .stylelintrc.json
in the top level of your repository.
# ๐ File: .stylelintrc.json
-----------------------------------
{
"extends": [
"stylelint-config-standard",
"stylelint-config-idiomatic-order"
],
"rules": {
"declaration-colon-newline-after": "always-multi-line"
},
"ignoreFiles": [
"build/**",
"coverage/**",
"dist/**",
"**/*.js",
"**/*.jsx",
"**/*.ts",
"**/*.tsx"
]
}
If you are going to use styled components
also install
npm install -D stylelint-config-styled-components
# ๐ File: .stylelintrc.json
-----------------------------------
{
"extends": [
"stylelint-config-standard",
"stylelint-config-idiomatic-order",
+ "stylelint-config-styled-components"
],
"ignoreFiles": [
"build/**",
"coverage/**",
"dist/**",
"**/*.js",
- "**/*.jsx",
"**/*.ts",
- "**/*.tsx"
]
}
To prevent both VS Code's built-in linters and Stylelint from reporting the same errors, you can disable the built-in linters.
# ๐ File: /.vscode/settings.json
-----------------------------------
{
+ "stylelint.enable": true,
+ "css.validate": false,
+ "less.validate": false,
+ "scss.validate": false,
+ "[css][scss]": {
+ "editor.defaultFormatter": "stylelint.vscode-stylelint",
+ "editor.codeActionsOnSave": [
+ "source.fixAll.stylelint"
+ ],
+ }
}
Stylelint has more than 170ish rules. Sometimes it will show you an error that will literally cause a problem.
Git Linter
If the project doesn't have a git repository. First, run:
git init
It works over Husky and only runs linters against staged git files. By doing so you can ensure no errors go into the repository and enforce code style.
Install and config on the project folder:
npx mrm@3 lint-staged
Testing
Use Vitest. It's compatible with Jest language API so you don't need to relearn the syntax.
npm install -D vitest
With the global
flag you don't need to import de dependencies on each file adding automatic support to Jest.
# ๐ File: vitest.config.ts
-----------------------------------
- import { defineConfig } from 'vite'
+ import { defineConfig } from 'vitest/config'
export default defineConfig({
+ test: {
+ globals: true,
+ },
})
If you are using typescript, also add this configuration.
# ๐ File: tsconfig.json
-----------------------------------
{
+ "compilerOptions": {
+ "types": ["vitest/globals"],
+ }
}
The next step, it's not required. But if you want to take advantage of IntelliSense it's recommended to start the test files with:
# ๐ Files: *.test.js
-----------------------------------
import { it, expect, describe } from "vitest";
Update run test scripts like this:
# ๐ File: package.json
-----------------------------------
{
"scripts": {
+ "test": "vitest --run --reporter verbose",
+ "test:w": "vitest",
+ "test:ui": "vitest --ui",
}
}
Snapshot
If you want the snapshots to be located at the same level as test files instead of __snapshots__
folder. Add this property.
# ๐ File: vitest.config.ts
-----------------------------------
export default defineConfig({
test: {
globals: true,
+ resolveSnapshotPath: (testPath, snapExtension) => testPath + snapExtension,
},
})
Coverage
For coverage reports, we need to install @vitest/coverage-v8
npm install -D @vitest/coverage-v8
Update run test scripts like this:
# ๐ File: package.json
-----------------------------------
{
"scripts": {
+ "test:c": "vitest run --coverage",
+ "test:cw": "vitest watch --coverage"
}
}
Add the @vitest/coverage-v8
configuration.
# ๐ File: vitest.config.ts
-----------------------------------
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
+ reporters: ['verbose'],
+ coverage: {
+ all: true,
+ reporter: ['text', 'html', 'lcov'],
+ include: ['**/src/**/*.{js,jsx,ts,tsx}'],
+ exclude: [
+ '**/src/main.{js,jsx,ts,tsx}',
+ '**/*.types.{ts,tsx}',
+ '**/*.test.{js,jsx,ts,tsx}',
+ '**/src/vite-env*',
+ ],
+ statements: 0,
+ branches: 0,
+ functions: 0,
+ lines: 0,
+ },
},
})
RTL (React Testing Library)
Run this command to install RTL
.
npm install -D @testing-library/react @testing-library/dom @testing-library/user-event @testing-library/jest-dom
Also need to install jsdom
(or happy-dom
)
npm install -D jsdom
And add it as environment
# ๐ File: vitest.config.ts
-----------------------------------
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
+ environment: 'jsdom',
},
})
With setupFiles
properties we can extend the jest-dom
matchers without importing them on each test file.
# ๐ File: .vitest/setup.ts
-----------------------------------
+ /* Extend Matchers */
+ import '@testing-library/jest-dom'
# ๐ File: vitest.config.ts
-----------------------------------
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
+ setupFiles: '.vitest/setup.ts',
},
})
If you are using eslint
it's good idea to add the RTL linters with this command:
npm install --D eslint-plugin-testing-library eslint-plugin-jest-dom
And add these configurations on the eslint
configuration file.
# ๐ File: .eslintrc.json
-----------------------------------
{
"extends": [
"plugin:react/recommended",
"standard-with-typescript",
"plugin:react/jsx-runtime",
"prettier",
+ "plugin:testing-library/react",
+ "plugin:jest-dom/recommended"
],
"plugins": [
"react",
"html",
+ "testing-library",
+ "jest-dom"
],
"rules": {
+ "testing-library/await-async-query": "error",
+ "testing-library/no-await-sync-query": "error",
+ "testing-library/no-debugging-utils": "warn",
+ "testing-library/no-dom-import": "off",
+ "jest-dom/prefer-checked": "error",
+ "jest-dom/prefer-enabled-disabled": "error",
+ "jest-dom/prefer-required": "error",
+ "jest-dom/prefer-to-have-attribute": "error"
},
}
Add into setupFiles
a configuration to avoid the global matcher and jest-dom
collisions.
# ๐ File: .vitest/setup.ts
-----------------------------------
/* Extend Matchers */
import '@testing-library/jest-dom'
+ import '@testing-library/jest-dom/extend-expect'
Mock Service Worker
If you also want to use msw to test HTTP requests you need to run this command.
npm install -D msw cross-fetch
And add this configuration to the global setup.
# ๐ File: .vitest/setup.ts
-----------------------------------
+ /* Mock Service Worker */
+ import { afterAll, afterEach, beforeAll } from 'vitest'
+ import { fetch } from 'cross-fetch'
+ import { server } from './mocks/server'
+ // Add `fetch` polyfill.
+ global.fetch = fetch
+ // Establish API mocking before all tests
+ beforeAll(() => server.listen({ onUnhandledRequest: `error` }))
+ // Reset any request handlers that we may add during the tests,
+ // so they don't affect other tests
+ afterEach(() => server.resetHandlers())
+ // Clean up after the tests are finished
+ afterAll(() => server. Close())
Debug
For visual debugging tests.
- Vitest extension
Debug
It's not an extension. It is an npm
package to install on your project that helps with debugging process.
npm install -S click-to-react-component
Even though click-to-react-component
is added to dependencies
, tree-shaking will remove click-to-react-component
from production
builds.
Using the alt
key (or option
in macOS) and with a combination of keys and clicking over the component in the browser, it will transport you to the source component in your editor.
Works with vite
adding these configurations on your project:
# ๐ File: /src/main.jsx
-----------------------------------
import React from "react"
import ReactDOM from "react-dom/client"
+import { ClickToComponent } from "click-to-react-component"
import App from "./App"
import "./index.css"
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
+ <ClickToComponent />
</React.StrictMode>
)
โ Sadly, it is not compatible with WSL, but you can use another alternative: ZSH + Oh My ZSH! on Windows without WSL
Styles
PostCSS
I actually prefer the PostCSS
approach instead of Sass
because it is fast, is closer to the CSS standard, and no need for the file extension rename. So in the future, you can get rid of PostCSS
and your project will continue working without needing a major migration.
npm install -D postcss-cli postcss
For me these are the essentials plugins to install:
npm install -D @csstools/postcss-nesting-experimental autoprefixer
Install
Autoprefixer
only if you need old browser support. There are a lot ofPostCSS
plugins, try to not install too many or very rare plugins that are not closer to CSS standards (or proposal).
Create a postcss.config.cjs
file on the root of the folder project:
# ๐ File: postcss.config.cjs
-----------------------------------
module.exports = {
"plugins": {
"@csstools/postcss-nesting-experimental": true,
"autoprefixer": true
}
}
Plugin order is important because we need that
nesting
runs beforeautoprefixer
If you decided to use Stylelint. Add this package:
npm install --D postcss-syntax
Add it as customSyntax
on .stylelintrc.json
file
# ๐ File: .stylelintrc.json
-----------------------------------
{
"extends": [
"stylelint-config-standard"
],
+ "customSyntax": "postcss-syntax",
}
Sass
If instead of PostCSS you want still to use Sass. Vite has SCSS
built support. Install this package:
npm install -D sass
Take care of using
sass
and notnode-sass
package because is deprecated.
If you decided to use Stylelint. Replace these packages:
npm remove stylelint-config-standard
npm install --D stylelint-config-standard-scss
Replace it as extends
on .stylelintrc.json
file
# ๐ File: .stylelintrc.json
-----------------------------------
{
"extends": [
- "stylelint-config-standard",
+ "stylelint-config-standard-scss"
]
}
Now rename manually all .css
files to .scss
and update src/App.js
to import src/App.scss
.
Deploy
If you are going to deploy the project on GitHub pages without using a custom domain you need to change some paths.
# ๐ File: vite.config.js
-----------------------------------
export default defineConfig({
plugins: [react()],
+ base: "./",
+ build: {
+ outDir: './docs'
+ }
})
Thatโs All Folks!
Happy Coding ๐
Top comments (2)
Excellent article, did not know about click to component , it is a live changer hack ๐
Recently i had a problem using Vite with Yarn, i had to use Pnpm like the docs recommends. Is curious because i already created React project using Yarn with no problems in the past. It must be something with the Yarn or Vite new versions.