React + Webpack + TypeScript Project Setup

React + Webpack + TypeScript Project Setup

React + Webpack + TypeScript Project Setup: Let's get React and TypeScript setup, its a lot easier than you think!

React + Webpack + TypeScript Project Setup: Let's get React and TypeScript setup, its a lot easier than you think!

TL;DR: Can’t possibly summarize this in a single sentence but there is a repo that you can fork which has all of the boilerplate setup.

Let’s Get Started!!

Firstly you will need to create a directory/repo for your project, once you have done this you will need to initialize the project. Run one of the following snippets in your terminal to do so:

//If you want to use npm 
npm init
//If you want to use yarn 🧶
yarn init

Just follow along with the prompts in the terminal, once the initialization is complete you should see a package.json file in the directory. If you don’t know what a package.json file is then this post is not for you, I would recommend that you play with React and npm more before continuing.

Add Some Dependencies 😵

The 3 dependencies that you’ll need are react, react-dom, and typescript which are all pretty straightforward, but you’ll also need 24 devDependencies.

To install the 3 dependencies run the following

//Optionally you can install styled-components
//npm
npm install react react-dom typescript
//yarn 🧶
yarn add react react-dom typescript

For this post, we’ll be using babel so you’ll need to install babel-loader, a couple of babel plugins, and some babel presets.

Something to note is that as of babel v7, babel ships with Typescript support so we don’t need a separate TypeScript loader 😃.

//npm
npm install babel-loader @babel/plugin-external-helpers @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/preset-env @babel/preset-react @babel/preset-typescript --save-dev
//yarn 🧶
yarn add babel-loader @babel/plugin-external-helpers @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/preset-env @babel/preset-react @babel/preset-typescript -D

Ok on to installing the testing specific devDependencies. We’ll be using Jest and Enzyme along with some enzyme specific dependencies.

//npm
npm install enzyme enzyme-adapter-react-16 enzyme-to-json jest ts-jest --save-dev
//yarn 🧶
yarn add enzyme enzyme-adapter-react-16 enzyme-to-json jest ts-jest -D

Ok just a couple more dependencies, obviously we need Webpack, Wepback plugins, and the types for the various dependencies

//npm
npm install @types/enzyme @types/enzyme-adapter-react-16 @types/jest @types/react @types/react-dom html-webpack-plugin source-map-loader webpack webpack-cli webpack-dev-server webpack-hot-middleware --save-dev
//yarn 🧶
yarn add @types/enzyme @types/enzyme-adapter-react-16 @types/jest @types/react @types/react-dom html-webpack-plugin source-map-loader webpack webpack-cli webpack-dev-server webpack-hot-middleware -D

Oof ok we’re done with the dependencies finally… 🎊

Webpack Config 🛠

You should be somewhat familiar with Webpack configs but all we’re doing is checking the mode and adjusting the config based on the environment mode (production or development). Since I’m using styled-components the only loader I need is babel-loader with the various plugins and presets, but if you have CSS in your project you’ll need a CSS loader.

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

module.exports = (env, { mode = 'development' }) => {
  const config = {
    mode,
    entry: {
      app: './src/index.tsx',
    },
    devtool: '',
    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx|tsx|ts)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env',
                '@babel/preset-react',
                '@babel/preset-typescript',
              ],
              plugins: [
                '@babel/plugin-external-helpers',
                'babel-plugin-styled-components',
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-proposal-object-rest-spread',
              ],
            },
          },
        },
      ],
    },
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'index.js',
      libraryTarget: 'umd',
      publicPath: '/dist/',
      umdNamedDefine: true,
    },
    optimization: {
      mangleWasmImports: true,
      mergeDuplicateChunks: true,
      minimize: true,
      nodeEnv: 'production',
    },
    plugins: [
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': '"production"',
      }),
    ],
  };

  /**
   * If in development mode adjust the config accordingly
   */
  if (mode === 'development') {
    config.devtool = 'source-map';
    config.output = {
      filename: '[name]/index.js',
    };
    config.module.rules.push({
      loader: 'source-map-loader',
      test: /\.js$/,
      exclude: /node_modules/,
      enforce: 'pre',
    });
    config.plugins = [
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': '"development"',
      }),
      new HtmlWebpackPlugin({
        filename: path.resolve(__dirname, 'dist/index.html'),
        template: path.resolve(__dirname, 'src', 'index.html'),
      }),
      new webpack.HotModuleReplacementPlugin(),
    ];
    config.devServer = {
      contentBase: path.resolve(__dirname, 'dist'),
      publicPath: '/',
      stats: {
        colors: true,
        hash: false,
        version: false,
        timings: true,
        assets: true,
        chunks: false,
        modules: false,
        reasons: false,
        children: false,
        source: false,
        errors: true,
        errorDetails: true,
        warnings: false,
        publicPath: false,
      },
    };
    config.optimization = {
      mangleWasmImports: true,
      mergeDuplicateChunks: true,
      minimize: false,
      nodeEnv: 'development',
    };
  }
  return config;
};

TypeScript Config 👨‍💻

Everything in the TypeScript configuration is opinionated, what I mean by that is that you can edit it to your heart’s content and it shouldn’t break your application, what I have in the repo is just what I like as some defaults. Just make sure that the tsconfig.json file is at the root of your project.

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "jsx": "react",
    "module": "amd",
    "noImplicitAny": true,
    "outDir": "./dist/",
    "preserveConstEnums": true,
    "removeComments": true,
    "sourceMap": true,
    "target": "es6",
    "moduleResolution": "node",
    "strict": true,
    "alwaysStrict": true,
    "strictNullChecks": false,
    "downlevelIteration": true
  },
  "include": [
    "./src/"
  ],
  "exclude": [
    "node_modules"
  ]
}

Jest Config 🧪

The Jest configuration file is used to configure Jest, the testing framework that we’ll be using. Make sure to place the jest.config.json file at the root of your project. Again like the TypeScript config, this is opinionated so please feel free to change it, everything is pretty standard though: (We’ll talk about the setupEnzyme.js file a second)

{
  "roots": [
    "<rootDir>/src"
  ],
  "transform": {
    "^.+\\.tsx?$": "ts-jest"
  },
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(ts|tsx)$",
  "testPathIgnorePatterns": [
    "./src/__tests__/setupEnzyme.ts"
  ],
  "collectCoverageFrom": [
    "src/**/*.{js,jsx,ts,tsx}",
    "!/node_modules/"
  ],
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js",
    "jsx"
  ],
  "snapshotSerializers": [
    "enzyme-to-json/serializer"
  ],
  "setupFilesAfterEnv": [
    "<rootDir>/src/__tests__/setupEnzyme.ts"
  ],
  "moduleNameMapper": { 
    "\\.(css|less|scss|sass)$": "identity-obj-proxy" 
  }
}

Src 🚗

(These emojis mean nothing 😆)

At the root of your project, you’ll want to create a src directory where all of the project code will live. Inside of the src directory, we’ll have 3 directories, __tests__ this is where all of our tests will live (Some people are hella opinionated about where this lives, so it is really up to you), components obviously where your components live, and declerations this is where we will be putting the declaration files for our project. Of course, you can name these directories whatever you want and you can create other directories if you would like as well, this is just a suggested project architecture, just note that you may have to edit the various configurations if you don’t follow this architecture exactly.

Alongside these directories, we have 2 files, index.tsx, which is the entry point for the project, and index.html, which is the template html file used by the HtmlWebpack plugin.

Inside of the __tests__ directory, you’ll need to create a file named setupEnzyme.ts , this file is referenced in the jest.config.json and has a really simple config for Enzyme.

import * as Enzyme from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({
  adapter: new Adapter()
});

Go ahead and create a simple component and use it in the project entry point ( index.tsx ) and run the following command in the terminal:

npx webpack-dev-server -open -colors -hot -mode development

A browser window should pop open and you should see your component (make sure you check your terminal for errors though)!

Yay, you’re done!!! 🍰

You have all you need to get your React TypeScript project up and running. If you want to access all of the source code you can go to the following github repo. If you want to suggest a change make a pull-request!

reactjs webpack typescript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

ReactJS Web App Development Services

We provide top-notch ReactJS development services to global clients. Hire expert ReactJS developers from top React JS development company, Skenix Infotech.

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.