In this book, we are going touseVisual Studio Code (VS Code) as our code editor. Feel free to use whichever editor you prefer, but keep in mind that the extensions used and settings configured may be slightly different in the editor ofyour choice.
Let’s now install VS Code and useful extensions, and then continue setting up all the tools needed for ourdevelopment environment.
Installing VS Code and extensions
Before wecan get started developing and setting up the other tools, we need to set up our code editor by followingthese steps:
- DownloadVS Code for your operating system from the official website (at the time of writing, theURL ishttps://code.visualstudio.com/). We are going to use version1.84.2 inthis book.
- After downloading and installing the application, open it, and you should see thefollowing window:
Figure 1.1 – A fresh installation of VS Code (on macOS)
- To make things easier later, we are going to install some extensions, so click on theExtensions icon, which is the fifth icon from the top on the left in the screenshot. A sidebar should open, where you will seeSearch Extensions in Marketplace at the top. Enter an extension name here and click onInstall to install it. Let’s start by installing theDocker extension:
Figure 1.2 – Installing the Docker extension in VS Code
- Install thefollowing extensions:
- Docker (by Microsoft)
- ESLint (by Microsoft)
- Prettier – Code formatter (by Prettier)
- MongoDB for VS Code (by MongoDB)
Support for JavaScript and Node.js already comes built-in withVS Code.
- Create a folder for the projects made in this book (for example, you can call it
Full-Stack-React-Projects
). Inside this folder, create a new foldercalledch1
. - Go to theFiles tab (first icon from top) andclick theOpen Folder button to open the empty
ch1
folder. - If you get a dialog askingDo you trust the authors of the files in this folder?, checkTrust the authors of all files in the parent folder ‘Full-Stack-React-Projects’ and then click on theYes, I trust theauthors button.
Figure 1.3 – Allowing VS Code to execute files in our project folder
Tip
You can safely ignore this warning in your own projects, as you can be sure that those do not contain malicious code. When opening folders from untrusted sources, you can pressNo, I don’t trust the authors, and still browse the code. However, when doing so, some features of VS Code willbe disabled.
We have now successfully set up VS Code and are ready to start setting up our project! If you have cloned the folder from the GitHub code examples provided, a notification telling you that a Git repository was found will also pop up. You can simply close this one, as we only want to open thech1
folder.
Now that VS Code is ready, let’s continue by setting up a new projectwith Vite.
Setting up a project with Vite
For this book, we are going to useVite to set up our project, as it is the most popular and liked according toThe State of JS 2022 survey (https://2022.stateofjs.com/). Vite also makes it easy to set up a modern frontend project, while still making it possible to extend the configuration later if needed. Follow these steps to set upyourprojectwith Vite:
- In the VS Code menu bar, go toTerminal |New Terminal to open anew Terminal.
- Inside the Terminal, run thefollowing command:
$ npm create vite@5.0.0 .
Make sure there is a period at the end of the command to create the project in the current folder instead of creating anew folder.
Note
To keep the instructions in this book working even when new versions are released, we pin all packages to a fixed version. Please follow the instructions with the given versions. After finishing this book, when starting new projects on your own, you should always try using the latest versions but keep in mind that changes might be needed to get them working. Consult the documentation of the respective packages and follow the migration path from the book version to thelatest version.
- When asked if
create-vite
should be installed, simply typey
and press theReturn/Enter keyto proceed. - When asked about the framework, use the arrow keys to selectReact and pressReturn. If you are being asked for a project name, pressCtrl +C to cancel, then run the command again, making sure there is a period at the end to select thecurrent folder.
- When asked about the variant,selectJavaScript.
- Now, our project is set up and we can run
npm install
to installthe dependencies. - Afterward, run
npm run dev
to start the dev server, as shown in thefollowing screenshot:
Figure 1.4 – The Terminal after setting up a project with Vite and before starting the dev server
Note
For simplicity in setting up, we just usednpm
directly. If you preferyarn
orpnpm
, you can instead runyarn create vite
orpnpm create
vite
, respectively.
- In theTerminal, you will see a URL telling you where your app is running. You can either holdCtrl (Cmd on macOS) and click on the link to open it in your browser, or manually enter the URL ina browser.
- To test whether your app is interactive, click the button with thetextcount is 0, and it should increase the count every time itis pressed.
Figure 1.5 – Our first React app running with Vite
Alternatives to Vite
Alternatives toVite are bundlers, such as webpack, Rollup, and Parcel. These are highly configurable but often do not offer a great experience for dev servers. They first must bundle all our code together before serving it to the browser. Instead, Vite natively supportstheECMAScript module (ESM) standard. Furthermore, Vite requires very little configuration to get started. A downside of Vite is that it can be hard to configure certain more complex scenarios with it. An upcoming bundler that is promising is Turbopack; however, it is still very new at the time of writing. For full-stack development with server-side rendering, we will later get to know Next.js, which is a React framework that also provides a dev server out ofthe box.
Now that our boilerplate project is up and running, let’s spend some time setting up tools that will enforce best practices and a consistentcode style.
Setting up ESLint and Prettier to enforce best practices and code style
Now that our React app is set up, we are going to set upESLint to enforce coding best practices with JavaScript and React. We are also going to set upPrettier to enforce acode style and automatically formatour code.
Installing the necessary dependencies
First, we are going to install all thenecessary dependencies:
- In the Terminal, click on theSplit Terminal icon at the top right of theTerminal pane to create a newTerminal pane. This will keep our app running while we runother commands.
- Click on this newly opened pane to focus it. Then, enter the following command to install ESLint, Prettier, and therelevant plugins:
$ npm install --save-dev prettier@3.1.0 \ eslint@8.54.0 \ eslint-plugin-react@7.33.2 \ eslint-config-prettier@9.0.0 \ eslint-plugin-jsx-a11y@6.8.0
The packages installed arethe following:
prettier
: Formats our code automatically according to a definedcode styleeslint
: Analyzes our code and enforcesbest practiceseslint-config-react:
Enables rules in ESLint relevant toReact projectseslint-config-prettier:
Disables rules relating to code style in ESLint so that Prettier can handlethem insteadeslint-plugin-jsx-a11y
: Allows ESLint to check for accessibility (a11y
) issues in ourJSX code
Note
The--save-dev
flag innpm
saves those dependencies asdev
dependencies, which means that they will only be installed for development. They will not be installed and included in a deployed app. This is important in order to keep the size of our containers as small aspossible later.
After the dependencies are installed, we need to configure Prettier and ESLint. We will start withconfiguring Prettier.
Configuring Prettier
Prettier willformat the code for us and replace the default code formatter for JavaScript in VS Code. It will allow us to spend more time writing code, automatically formatting it for us properly when we save the file. Follow these steps toconfigure Prettier:
- Right-click below the files list in the left sidebar of VS Code (if it is not opened, click theFiles icon) and pressNew file... to create a new file. Call it
.prettierrc.json
(do not forget the period at the beginning of thefile name!). - The newly created file should open automatically, so we can start writing the following configuration into it. We first create a new object and set the
trailingComma
option toall
to make sure objects and arrays that span over multiple lines always have a comma at the end, even for the last element. This reduces the number of touched lines when committing a changevia Git:{ "trailingComma": "all",
- Then, we set the
tabWidth
option to2
spaces: "tabWidth": 2,
- Set the
printWidth
to80
characters per line to avoid long lines inour code: "printWidth": 80,
- Set the
semi
option tofalse
to avoid semicolons wherenot necessary: "semi": false,
- Finally, we enforce the use of single quotes instead ofdouble quotes:
"jsxSingleQuote": true, "singleQuote": true}
Note
These settings for Prettier are just an example of a coding style convention. Of course, you are free to adjust these to your own preferences. There are many more options, all of which can be found in thePrettierdocs (https://prettier.io/docs/en/options.html).
Configuring the Prettier extension
Now that wehave a configuration file for Prettier, we need to make sure the VS Code extension is properly configured to format the codefor us:
- Open the VS Code settings by going toFile |Preferences... |Settings on Windows/Linux, orCode |Settings... |Settingson macOS.
- In the newly opened settings editor, click on theWorkspace tab. This ensures that we save all our settings in a
.vscode/settings.json
file in our project folder. When other developers open our project, they will automatically be using those settingsas well. - Search for
editor format on save
and check the checkbox to enable formatting codeon save. - Search for
editor default formatter
and selectPrettier - Code formatter fromthe list. - To verify that Prettier works, open the
.prettierrc.json
file, add some extra spaces to the beginning of a line, and save the file. You should notice that Prettier reformatted the code to adhere to the defined code style. It will reduce the number of spaces for indentationto two.
Now that Prettier is set up properly, we do not need to worry about formatting our code manually anymore. Feel free to just type in code as you go and save the file to get it formattedforyou!
Creating a Prettier ignore file
To improveperformance and avoid running Prettier on files that should not be automatically formatted, we can ignore certain files and folders by creating a Prettier ignore file. Followthese steps:
- Create a new file called
.prettierignore
in the root of our project, similar to how we created the.
prettierrc.json
file. - Add the following contents to it to ignore the transpiledsource code:
dist/
Thenode_modules/
folder is automatically ignoredby Prettier.
Now that we have successfully set up Prettier, we are going to configure ESLint to enforce codingbest practices.
Configuring ESLint
While Prettier focuses on the style and formatting of our code, ESLint focuses on the actual code, avoiding common mistakes or unnecessary code. Let’s configureit now:
- Delete the automatically created
.
eslintrc.cjs
file. - Create a new
.eslintrc.json
file and start writing the following configuration into it. First, we setroot
totrue
to make sure ESLint does not look at parent folders formore configuration:{ "root": true,
- Define an
env
object, in which we set the browser environment totrue
so that ESLint understands browser-specific globals such asdocument
andwindow
: "env": { "browser": true },
- Define a
parserOptions
object, where we specify that we are using the latest ECMAScript versionand ESM: "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" },
- Define an
extends
array to extend from recommended configurations. Specifically, we extend from ESLint’s recommended rules and the recommended rules for the pluginswe installed: "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:react/jsx-runtime", "plugin:jsx-a11y/recommended",
- As the last element of the array, we use
prettier
to disable all code style-related rules in ESLint and let Prettierhandle it: "prettier" ],
- Now, we definesettings for the plugins. First, we tell the
react
plugin to detect our installed Reactversion automatically: "settings": { "react": { "version": "detect" } },
- Finally, outsideof the
settings
section, we define anoverrides
array, in which we specify that ESLint should only lint.js
and.
jsx
files: "overrides": [ { "files": ["*.js", "*.jsx"] } ]}
- Create a new
.eslintignore
file, with thefollowing contents:dist/vite.config.js
Thenode_modules/
folder is automatically ignoredby ESLint.
- Save the files and run
npx eslint src
in the Terminal to run the linter. You will see that there are some errors already due to our configured rules not matching the source provided by the default projectin Vite:
Figure 1.6 – When running ESLint for the first time, we get some errors about rule violations
- Fortunately, all these issues are automatically fixable by ESLint. Run
npx eslint src --fix
to fix the issues automatically. Now, when you runnpx eslint src
again, you will not get any output. This means that there were nolinter errors!
Tip
Thenpx
command allows us to execute commands provided bynpm
packages, in a similar context as running them inpackage.json
scripts would do. It can also run remote packages without installing them permanently. If the package is not installed yet, it will ask you whether it shoulddo this.
Adding a new script to run our linter
In the previous section, we have been calling the linter by runningnpx eslint src
manually. We are now going to add alint
scripttopackage.json
:
- In the Terminal, run the following command to define a
lint
script in thepackage.json
file:$ npm pkg set scripts.lint="eslint src"
- Now, run
npm run lint
in the Terminal. This should executeeslint src
successfully, just likenpx eslint
src
did:
Figure 1.7 – The linter running successfully, with no errors
After setting up ESLint and Prettier, we still need to make sure that they run before we commit code. Let’s set up Husky to make sure we commit propercode now.
Setting up Husky to make sure we commit proper code
After setting up Prettier and ESLint, we will now get our code automatically formatted on save by Prettier and see errors from ESLint in VS Code when we make mistakes or ignore best practices. However, we might miss some of these errors and accidentally commit code that is invalid. To avoid this, we can set upHusky andlint-staged, which run before we commit our code to Git and ensure that Prettier and ESLint are executed successfully on the source code before itis committed.
Important
If you cloned the full repository for the book, Husky may not find the.git
directory when runningnpm install
. In that case, just rungit init
in the root of the correspondingchapter folder.
Let’s set Husky and lint-stagedup by followingthese steps:
- Run the following command to install Husky and lint-staged as
dev
dependencies:$ npm install --save-dev husky@8.0.3 \ lint-staged@15.1.0
- Open the
package.json
file and add the followinglint-staged
configuration to it in a new object afterdevDependencies
, then save the file. This will run Prettier and ESlint on all committed.js
and.jsx
files and attempt to automatically fix code style and linter errors,if possible: "lint-staged": { "**/*.{js,jsx}": [ "npx prettier --write", "npx eslint --fix" ] }
- Initialize a Git repository in the
ch1
folder and make an initial commit with just thepackage.json
file, as lint-staged does not get executed on theinitial commit:$ git init$ git add package.json$ git commit -m "chore: initial commit"
- Add the
husky install
script to aprepare
script inpackage.json
, so that Husky getsinstalled automatically when the project is cloned andnpm install
is executed:$ npm pkg set scripts.prepare="husky install"
- Since we do not need to run
npm install
again right now, we need to manually run theprepare
scriptthis time:$ npm run prepare
- Add a
pre-commit
hook for lint-staged, so that ESLint and Prettier run every time we dogit commit
:$ npx husky add .husky/pre-commit "npx lint-staged"
- Now, add all files to Git and attempt to makea commit:
$ git add .$ git commit -m "chore: basic project setup"
If everything worked successfully, you should seehusky
runninglint-staged
, which, in turn, runsprettier
andeslint
, after you rungit commit
. If you are getting aconfiguration error, ensure that all files are saved properly andthen rungit
commit
again.
Figure 1.8 – Husky and lint-staged successfully enforcing code style and best practices before we commit
Setting up commitlint to enforce a standard for our commit messages
In addition to linting our code, we can also lint our commit messages. You may have noticed that we were prefixing our commit messages with a type already (thechore
type). Types make it easier to follow what was changed in a commit. To enforce the use of types, we can set upcommitlint. Follow these steps to setit up:
- Install commitlint and a conventional configfor commitlint:
$ npm install --save-dev @commitlint/cli@18.4.3 \ @commitlint/config-conventional@18.4.3
- Create a new
.commitlintrc.json
file in the root of our project and add thefollowing contents:{ "extends": ["@commitlint/config-conventional"]}
- Add a
commit-msg
hookto Husky:$ npx husky add .husky/commit-msg \ 'npx commitlint --edit ${1}'
- Now, if we try adding our changed files and committing without a type or a wrong type, we will get an error from commitlint and will not be able to make such a commit. If we add the correct type, itwill succeed:
$ git add .$ git commit -m "no type"$ git commit -m "wrong: type"$ git commit -m "chore: configure commitlint"
The following figure showsHusky in action. If we write an incorrect commit message, it will reject it and not let us commit the code. Only if we enter a properly formatted commit message will the commitgo through:
Figure 1.9 – commitlint working successfully and preventing commits without a type and with wrong types
Commit messages in thecommitlint conventional config (https://www.conventionalcommits.org/) are structured in a way where a type must be listed first, then an optional scope follows, and then the description follows, suchastype(scope): description
. Possible types areas follows:
fix
: Forbug fixesfeat
: Fornew featuresrefactor
: For restructuring the code without adding features orfixing bugsbuild
: For changes in the build systemor dependenciesci
: For changes in theCI/CD configurationdocs
: For changes in thedocumentation onlyperf
: Forperformance optimizationsstyle
: For fixingcode formattingtest
: Foradding oradjusting tests
The scope is optional and best used in a monorepo to specify that changes were made to a certain app or librarywithin it.