Published on

Creating a basic Typescript React Boilerplate.

Disclaimer: everything in this section is done on OSX you may need to change commands slightly to tailor to your os

Preface

With the development of tools like Create React App and Create React App Configuration Override, many development teams have built layers upon layers of configuration ontop of each other, creating an onion like architecture on the frontend. Most of these layers are unenceary and could be replaced with a fairly simple webpack configuration, that can be maintained and understood by the core team.

This Post aims to help you understand how you can quickly create a Typescript React webpack configuration that you can understand, extend and tailor to the needs of your team, allowing for faster build times and a more productive dev team overall.

Before jumping right into it the topics that we will be covering include

  • Setting up our project and repository with NPM and GIT
  • Installing the needed dependencies
  • Setting up a basic typescript config and solving basic config errors
  • Configuring webpack to use with typescript and React
    • Including loaders and plugins
  • Making our webpack config production ready
  • Scaling typescript type checking with your codebase to avoid slow build times

Setting up git and NPM

First off we want to start off by creating a folder for our typescript react project to do this, open terminal and navigate to our Desktop using the following command:

cd Desktop

Next, we want to create a directory on our Desktop called ts-react-boilerplate.

mkdir ts-react-boilerplate

After we have created a folder in our desired location, we navigate to it using cd and initialize NPM and Git.

cd ts-react-boilerplate
npm init -y
git init

After this is done, navigate to GitHub and create a repository, once a repository has been created we run:

git remote add origin <YourGithubRepoHere>
git add .
git commit -m "init commit"
git push origin master

Lastly we want to ignore some files for git, to do this create a .gitignore with the following contents.

node_modules
.DS_Store # osx specific

Setting Up Typescript

Setting up typescript couldn't be easier due the awsome work the microsoft team has done with the tooling, first off we need to install typescript using your desired package manager:

npm install --save-dev typescript

next we need to bootstrap a typescript configuration file all that is needed is to run the following command:

npx tsc --init

This will generate you a recomended tsconfig.json file with its default option.

The tsconfig file is used to tell typescript what kind of rules you want to enforce on your codebase. Using options like strict will not allow for returning undefined where there is no if statment before. You may want to take time to read through each setting in order to tailor it best to your needs.

Webpack Configuration

Now for the tool that brings everything together, Webpack. When installing webpack we need to install webpack and a couple of other webpack related tools, including webpack-cli and webpack-dev-server.

Install our webpack dependencies, by running the following command.

npm install webpack webpack-cli webpack-dev-server --save-dev

By default webpack will not be able to do much with our current project, so we need to create a new file in the root of the project with the name: webpack.config.js this is going to be the main file for your webpack configuration.

const path = require('path')

module.exports = {
  // this is going to be where our ReactDOM is going to mount our app
  entry: path.resolve(__dirname, './src/index.tsx'),
  // The output property is where out code is generated to after webpack is done processing it
  output: {
    path: path.resolve(__dirname, './dist'),
    // one thig worth mentioning here is the [contenthash] this adds a randomly generated hash to allow for easier cache busting.
    filename: 'index.[contenthash].js',
  },
  // This tells webpack what extentions to resolve
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
}

HtmlWebpackPlugin

Next step is to create an entry for users to enter our SPA through. For this the HtmlWebpackPlugin is ideal, the HtmlWebpackPlugin simplifies creation of HTML files to serve webpack bundles.

to get started with this plugin we first need to install it.

npm i html-webpack-plugin --save-dev

Next a template is needed for the plugin to reference as a base to use when generating our HTML, In the root of your project create a index.html file with the following contents.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Typescript Template</title>
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1"
    />
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

Now to get this working in the webpack config is really simple. All that is needed is to add the HtmlWebpackPlugin into the plugins section of the config, and then add our index.html as the template property of the plugin.

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

const path = require('path')

module.exports = {
  // this is going to be where our ReactDOM is going to mount our app
  entry: path.resolve(__dirname, './src/index.tsx'),
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.[contenthash].js',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html',
    }),
  ],
}

Loaders

At this point we have a webpack config that can load a html template using the template plugin, but by default webpack only understands JavaScript and JSON files.

In order for us to process our typescript and css files we we need to use loaders. Loaders allow for webpack to process any file type you can imagine, anyone is able to write their own loader from scratch. The webpack documentation around loaders lists a few around web based loaders. Although not common many people have expiermented with using webpack outside of just javascript and web based languages!

Loaders have two main properties

  • test takes a Regular expression to find the files you want to process
  • use tells webpack what loader you want to use to process that file

To process our typescript file we are going to use the ts-loader loader, firstly we will need to install this using NPM.

npm i ts-loader --save-dev

In order for webpack to be able to use these loaders, we will need to tell it what files to select and what loader to use with it.

  module: {
    rules: [
      {
        // Regex to select ts and tsx files
        test: /\.tsx?$/,
        loader: 'ts-loader',
      },
    ],
  },

and all together.

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  entry: path.resolve(__dirname, './src/index.tsx'),
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.[contenthash].js',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html',
    }),
  ],
}

You may also want to use css or in your project, to do this you will need to chain 2 different types of loaders, one being the style-loader and the other css-loader.

  • The style-loader injects our CSS into the DOM.
  • The css-loader interprets @import and url() and will resolve them.

Its recomended we chain them together so we can take full advantage of css, and maximise performance gains.

{
    test: /\.css$/i,
    use: ['style-loader', 'css-loader'],
},

Your webpack config should now look something like this

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  entry: path.resolve(__dirname, './src/index.tsx'),
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.[contenthash].js',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        loader: 'ts-loader',
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html',
    }),
  ],
}

now that we are able to process all the files required, next we need to setup our React App entry.

Firstly we need to install React and its typings.

npm install react react-dom
npm install @types/react @types/react-dom --save-dev

After react has been installed create a folder in the root of your project named src, this will be the home of all your code used to build the application.

inside the src folder create a index.tsx file:

import ReactDOM from 'react-dom'
import { App } from './App'

ReactDOM.render(<App />, document.getElementById('root'))

If you are using a modern IDE like vscode you may notice a weird error when you hover over your <App /> element, Cannot use JSX unless the '--jsx' flag is provided.ts(17004) don't worry nothing has gone wrong, this is letting us know that we have not let typescript know we are using JSX in our project. To fix this navigate to your tsconfig.json and find the property jsx and change it to "jsx": "react",. Depending on your project type you may want to use react-native or preserve.

Once this is done navigate back to your index.tsx and check that the error is gone, and create a file called App.tsx this is going to be the app container that handles all of our providers, global imports etc.

import React from 'react'
import './index.css'

export const App = () => <div>{'Hello World'}</div>

and lastly just a small simple css file

body {
  background: green;
}

NPM Scripts

Now that we have all the code required to have a SPA launched locally, we need a way to run all of this without running the full webpack serve command everytime we want to start our app (webpack serve --mode=development).

Inside the package.json scripts section add the following.

"start": "webpack serve --mode=development"

Your package.json should now look something like this

{
  "name": "ts-react-boilerplate",
  "version": "1.0.0",
  "description": "typescript boilerplate built in blog post",
  "author": "James Dinnes",
  "scripts": {
    "start": "webpack serve --mode=development"
  },
  "license": "MIT",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "@types/react": "^17.0.37",
    "@types/react-dom": "^17.0.11",
    "html-webpack-plugin": "^5.5.0",
    "ts-loader": "^9.2.6",
    "typescript": "^4.5.4",
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.7.1"
  }
}

Now when running npm run start a webpack dev server will be started on http://localhost:8080/. If everything has been done correctly you will see a green page with just Hello World.

Thats it! You now have your own typescript template and the knowledge to expand it to your needs!