This template is intended to help you start a new React SPA
project from scratch with a comprehensive file structure, required dependencies, built-in configurations, example components and good practices for React Web Development.
The project was bootstrapped with Create React App following this Tutorial. Below you will find some information about main features and how to perform common tasks.
This project supports a superset of the latest JavaScript
/TypeScript
standard. In addition to ES6 syntax features, it also supports:
- Exponentiation Operator (ES2016)
- Async/await (ES2017)
- Object Rest/Spread Properties (ES2018)
- Dynamic import() (stage 4 proposal)
- Class Fields and Static Properties (part of stage 3 proposal)
- TSX and TypeScript
Constant enums and namespaces are not supported, you can learn about the constraints of using Babel with TypeScript here.
- React 18.2.0 with
React Scripts 5.0.1
- SASS 1.60.0 with CSS Modules
- MUI 5.11.15 with
Emotion
styling engine,Roboto Fonts
andMaterial Icons
- TypeScript 4.7.4 with ES6
- I18next 22.4.13 for internationalization
- React Router 6.10.0 for the routing system
- Storybook 6.5.16 to document components
- ESLint 8.37.0 with
TypeScript
,React
,React Hooks
andJest
configuration - Stylelint 15.3.0 to analyse
CSS
/SCSS
files - Jest 29.5.0 to test
JavaScript
/TypeScript
files - React Testing Library 14.0.0 to test components
- Web Vitals 3.3.0 to meassure performance
- .editorconfig settings to standardize charset, ending of lines and indentation
- .vscode settings with integrated Chrome Debugger, faster search results and auto-format on save
- Environment files for
Local
,Test
,Development
,QA
,Staging
andProduction
- Install NodeJs
- Install Git
- Install VS Code
- Install VS Code recomented extensions:
- Install React Developer Tools for Google Chrome
- Open a new VS Code window:
File
>New Window
- Open a parent folder that will host this project (e.g.
~/Projects
):File
>Open Folder
- Open a new terminal:
Terminal
>New Terminal
- Clone repo:
git clone https://github.com/equisoide/react-mui-ts-template.git
- Install project dependencies:
cd react-mui-ts-template
npm run init
(performs a Clean Install)
- Restart VS Code to refresh TypeScript Intellisense, otherwise you might see errors in the editor:
- Close VS Code
- Open a new VS Code window
- Open the folder where the project was cloned
- Start the application:
- Open a new terminal
npm start
- Start debugging in VS Code:
- Press
F5
or click onRun and Debug
>Green Debug Icon
- You can set breakpoints and inspect components in the React Developer Tools
- Press
Command | Description | Evironment File |
---|---|---|
npm run init |
Installs project dependencies for the first time | N/A |
npm run lint |
Analyses JavaSript/TypeScript code | N/A |
npm run lint:f |
Try to fix JavaSript/TypeScript errors | N/A |
npm run slint |
Analyses CSS/SCSS styles | N/A |
npm run slint:f |
Try to fix CSS/SCSS errors | N/A |
npm test |
Executes Unit Tests outputting to out/coverage |
.env.test |
npm start |
Runs the App in http://localhost:4000 | .env.local |
npm run start-https |
Runs the App in https://localhost:4001 (HTTPS) | .env.https.local |
npm run build:l |
Builds the App to out/build/local |
.env.local |
npm run build:d |
Builds the App to out/build/development |
.env.development |
npm run build:q |
Builds the App to out/build/qa |
.env.qa |
npm run build:s |
Builds the App to out/build/staging |
.env.staging |
npm run build |
Builds the App to out/build/production |
.env.production |
npm run sbook |
Runs Storybook in http://localhost:4002 | .env.local |
npm run sbook-https |
Runs Storybook in https://localhost:4003 (HTTPS) | .env.https.local |
npm run sb-build:l |
Builds Storybook to out/storybook/local |
.env.local |
npm run sb-build:d |
Builds Storybook to out/storybook/development |
.env.development |
npm run sb-build:q |
Builds Storybook to out/storybook/qa |
.env.qa |
npm run sb-build:s |
Builds Storybook to out/storybook/staging |
.env.staging |
npm run sb-build |
Builds Storybook to out/storybook/production |
.env.production |
You can run local builds of the Application and Storybook by using http-server. The following example creates a local build of the App and runs it using http-server:
npm run build:l
npx http-server out/build/local
After cloning, your project should look like this:
π¦ react-mui-ts-template
βββ π .editorconfig EditorConfig settings
βββ π .env Variables common to all environments
βββ π .eslintignore Folders and files ignored by ESLint
βββ π .eslintrc ESLint configuration
βββ π .gitignore Folders and files ignored by Git
βββ π .npmrc Npm configuration
βββ π .stylelintrc Stylelint configuration
βββ π LICENSE License information
βββ π package-lock.json Npm dependency tree to recreate node_modules
βββ π package.json Project dependencies, scripts and more
βββ π README.md Project documentation
βββ π tsconfig.json TypeScript configuration
βββ π .env-override
β βββ π .env.development Environment variables for Development
β βββ π .env.https.local Environment variables for Local (HTTPS)
β βββ π .env.local Environment variables for Local
β βββ π .env.production Environment variables for Production
β βββ π .env.qa Environment variables for QA
β βββ π .env.staging Environment variables for Staging
β βββ π .env.test Environment variables for Unit Test
βββ π .storybook
β βββ π favicon.svg Favicon for Storybook
β βββ π main.js Storybook server behavior
β βββ π manager.js Customize how Storybook App renders
β βββ π preview.js Global code that applies to all stories
βββ π .vscode
β βββ π extensions.json Recomended extensions to load in VS Code
β βββ π launch.json Launch Chrome against localhost
β βββ π settings.json Settings for VS Code
βββ π public
β βββ π favicon.ico The icon found in the URL address bar
β βββ π index.html HTML where the React App is rendered
β βββ π logo192.png PWA icon (192x192)
β βββ π logo512.png PWA icon (512x512)
β βββ π manifest.json Metadata to install the App as a PWA
β βββ π robots.txt Instructions for search crawlers
βββ π src
βββ π index.tsx The application entry point
βββ π react-app-env.d.ts TypeScript declarations for React App
βββ π setupTests.ts Global setup before running tests
βββ π app
β βββ π index.tsx The main App component with routes
βββ π components/HelloWorld
β βββ π index.module.scss Component styles
β βββ π index.stories.tsx Storybook documentation
β βββ π index.test.tsx Jest testing file
β βββ π index.tsx Example component definition
β βββ ...
βββ π lang
β βββ π index.ts i18next configuration
β βββ π resources.en.json Application texts in English
β βββ π resources.es.json Application texts in Spanish
βββ π pages
β βββ ... React components for each page
βββ π stories
β βββ ... Files for the Storybook intro page
βββ π styles
β βββ π _reset.scss Simple CSS reset for consistent styles
β βββ π main.scss Main SASS file
βββ π util
βββ π web-vitals.ts Web Vitals reporting
For the project to build, these files must exist with exact filenames:
public/index.html
is the page templatesrc/index.tsx
is the TypeScript entry point
You may create subdirectories inside src
. For faster rebuilds, only files inside src
are processed by webpack. You need to put any TypeScript and SCSS files inside src
, otherwise webpack wonβt see them.
Only files inside public can be used from public/index.html
.
Most of the files you will create in the src
folder will be TypeScript, TypeScript with React or SASS:
.ts
: TypeScript files (Don't use.js
). Use it for:- Utilities. e.g.
arrays.ts
- Test of utilities. e.g.
arrays.test.ts
- Utilities. e.g.
.tsx
: TypeScript with React (Don't use.jsx
). Use it for:- Components. e.g.
HelloWorld/index.tsx
- Test of components. e.g.
HelloWorld/index.test.tsx
- Storybook stories. e.g.
HelloWorld/index.stories.tsx
- Components. e.g.
.scss
: Superset of CSS (Don't use.css
). Use it for:- Global styles. e.g.
main.css
- Component styles. e.g.
HelloWorld/index.module.scss
- Global styles. e.g.
This project supports Sass alongside CSS Modules:
Sass
is CSS with superpowersCSS Modules
scopes CSS by automatically creating a unique className
Sass
supports two syntaxes:
.scss
: Is an extension of CSS where every valid CSS is a valid .scss as well.sass
: Is an older indented syntax not recommended for use in new Sass files
In this project we use the .scss
syntax.
To express that a component depends on a .scss module, you should use the [name].module.scss
convention:
import styles from './index.module.scss';
function MyComponent() {
return <div className={styles.myClass}>My Component</div>;
}
In development, expressing dependencies this way allows your styles to be reloaded on the fly as you edit them. In production, all .scss
files will be concatenated into a single minified .css
file in the build output.
To share variables between Sass files, you can use Sass's @use rule. There is a SASS_PATH
variable in the .env
file that is used to locate .scss
files. Supposing that SASS_PATH='./src/styles'
and that you have _colors.scss
in that directory, then you can use it like this:
@use 'colors';
.info {
color: colors.$primary;
}
For information about how to structure a SASS codebase using the 7-1 Pattern you can read this article or take a look to the following boilerplate.
With webpack, using static assets like images and files works similarly to SCSS
.
To reduce the number of requests to the server, importing images that are less than 10,000 bytes returns a data URI instead of a path. This applies to the following file extensions: bmp, gif, jpg, jpeg, and png. You can control the 10,000 byte threshold by setting the IMAGE_INLINE_SIZE_LIMIT
environment variable as documented in the advanced configuration.
import logo from './logo.png';
function Header() {
return <img src={logo} alt="Logo" />;
}
You may require the local server to run the App or Storybook over HTTPS:
- Use
npm run start-https
to run the APP over HTTPS - Use
npm run sbook-https
to run Storybook over HTTPS
Note that you might get an error in the console telling that localhost.pem
or localhost-key.pem
files can't be found. This is because when running the App over HTTPS a valid Certificate Authority and an SSL certificate are needed.
To generate those files use mkcert:
- You need a package manager to install mkcert:
- MacOS: Use Homebrew (
brew install mkcert
) - Linux: Use Certutil
- Windows: Use Chocolatey
- MacOS: Use Homebrew (
- Once installed mkcert:
- Open a terminal at the root of the project
- Create a locally trusted CA with
mkcert -install
- Generate an SSL certificate with
mkcert localhost
localhost.pem
andlocalhost-key.pem
will be generated- Note that these files are included in the
.gitignore
<StrictMode>
lets you find common bugs in your components early during development. It also helps you to prepare your app for the future. You can read more about it here.
Strict Mode enables the following development-only behaviors:
- Your components will re-render an extra time to find bugs caused by impure rendering
- Your components will re-run Effects an extra time to find bugs caused by missing Effect cleanup
- Your components will be checked for usage of deprecated APIs.
To enabble/disable StrictMode you can use the REACT_APP_STRICT_MODE
environment variable. By default it's set to true
in the following files:
.env.development
.env.https.local
.env.local
npm-check-updates upgrades your package.json
dependencies to the latest versions, ignoring specified versions. Choose which packages to update in interactive mode:
$ npx ncu -i
Upgrading package.json
[====================] 46/46 100%
? Choose which packages to update Β»
β/β: Select a package
Space: Toggle selection
a: Toggle all
Enter: Upgrade
β― (*) react-router-dom ^6.9.0 β ^6.10.0
(*) typescript ^4.7.4 β ^5.0.3
(*) webpack ^5.76.3 β ^5.77.0
Install selected packages:
? Run npm install to install new versions? Β» y
Test everything is working fine
- Delete node_modules folder
- Delete out folder (if exists)
- Install project dependencies for the first time:
npm run init
- Restart VS Code in order to refresh TypeScript Intellisense
- Analyse JavaSript/TypeScript code:
npm run lint
- Try to fix JavaSript/TypeScript errors:
npm run lint:f
- Analyse CSS/SCSS styles:
npm run slint
- Try to fix CSS/SCSS errors:
npm run slint:f
- Execute Unit Tests outputting to out/coverage:
npm test
- Run the App in http://localhost:4000:
npm start
- Create a locally trusted CA:
mkcert -install
- Generate an SSL certificate:
mkcert localhost
- Run the App in https://localhost:4001:
npm run start-https
(HTTPS) - Build the App to out/build/local:
npm run build:l
- Run the App local build
npx http-server out/build/local
- Build the App to out/build/development:
npm run build:d
- Run the App development build
npx http-server out/build/development
- Build the App to out/build/qa:
npm run build:q
- Run the App qa build
npx http-server out/build/qa
- Build the App to out/build/staging:
npm run build:s
- Run the App staging build
npx http-server out/build/staging
- Build the App to out/build/production:
npm run build
- Run the App production build
npx http-server out/build/production
- Run Storybook in http://localhost:4002:
npm run sbook
- Run Storybook in https://localhost:4003:
npm run sbook-https
(HTTPS) - Build Storybook to out/storybook/local:
npm run sb-build:l
- Run the Storybook local build
npx http-server out/storybook/local
- Build Storybook to out/storybook/development:
npm run sb-build:d
- Run the Storybook development build
npx http-server out/storybook/development
- Build Storybook to out/storybook/qa:
npm run sb-build:q
- Run the Storybook qa build
npx http-server out/storybook/qa
- Build Storybook to out/storybook/staging:
npm run sb-build:s
- Run the Storybook staging build
npx http-server out/storybook/staging
- Build Storybook to out/storybook/production:
npm run sb-build
- Run the Storybook production build
npx http-server out/storybook/production
- Never delete and re-generate the
package-lock.json
file from scratch, it will break the App and Storybook! Letnpm
update that file every time you install a new dependency - Create reusable components inside the
src/components
folder. Define each component in its own folder with the following structure:βββ π src/components/MyComponent Component name in PascalCase βββ π index.module.cs Component styles (optional) βββ π index.stories.tsx Storybook documentation βββ π index.test.tsx Jest testing file βββ π index.tsx Component definition
- Prefer Function Components over Class Components, they offer almost the same: state and lifecycle methods, with the plus they are more lightway, have a sophisticated API and require less code. With the introduction of React Hooks it's possible to write your entire application with just functions as React Components:
// External imports import Box from '@mui/material/Box'; import { BoxProps } from '@mui/material'; import { useTranslation } from 'react-i18next'; // Local imports import styles from './index.module.scss'; // Component props export interface MyComponentProps { /** * The box container styles. * See: https://mui.com/material-ui/api/box */ box?: BoxProps } // Component definition function MyComponent({ box } : MyComponentProps) { const { t } = useTranslation(); const defaults = MyComponent.defaultProps; const boxProps = { ...defaults.box, ...box } as BoxProps; return ( <Box className={styles.box} {...boxProps}> {t('hello-world')} </Box> ); } // Default props MyComponent.defaultProps = { box: { sx: { background: 'blue' }, }, }; // Default export export default MyComponent;
- Use default
imports
andexports
when a module only exports a single thing (for example, a component). Named exports are useful for utility modules that export several functions. A module may have at most one default export and as many named exports as you like. - In general use Trailing Commas (except on
JSON
files), many coding styles now recommend using them all the time because they make it easier to add new parameters to your functions or copy/paste properties in arrays and objects and also helps with producing cleaner diff output - Add your own environment variables to the
.env-override/.env.local
file, this file should not be commited - Before running or building this application always run linters and unit tests
- When running
npm run lint
you get this error: "Expected linebreaks to be 'LF' but found 'CRLF'"- This happens because on Windows, Git converts linebreaks from
LF
toCRLF
when you checkout the code, but esLint is configured to accept valid ending of lines asLF
(unix style) - To avoid Git converting from
LF
toCRLF
, run the following commands:git config --global core.autocrlf false git config --global core.eol lf git rm --cached -r . git reset --hard
- This happens because on Windows, Git converts linebreaks from
- On VS Code you get this errors: "JSX element implicitly has type 'any'..."
- This happens because your Typescript IntelliSense is not working properly
- To fix it reload your code editor:
Ctrl + p
>Developer: Reload Window
- Official React Documentation
- React Function Components
- The TypeScript Handbook
- ES6
- Sass Basics
- MUI Crash Course
- MUI From Zero to Hero
- MUI Components
- MUI Templates
Juan Cuartas https://github.com/equisoide
Code and documentation released under the MIT license