Webpack with React Typescript
Tags: react, beginners, webpack, typescript
Published: 2020-08-23 13:41:43

Ever wondered if there is a way to just tie up all your code into one single module for easy usage. If so, in this article I will show you how to bundle all your code into a single javascript module that you can easily use in any other project.

So you write a web app with multiple dependencies like jquery etc, images and multiple styles and then you look at the code and think, “If I am going to use this code in the client then I will need to import each and every module along with the application javascript files. Great!”. This is where webpack comes to the rescue.

### What is Webpack?

![](https://www.skcript.com/svrmedia/heroes/image7-1.gif)

**Webpack** is a static module bundler for JavaScript applications. As you can see from the name, Web + pack - means creating a single package for the web. So, it takes all your code, runs through your code, transpile into the correct format, and gives you full control to bundle all your files into a single or a few files to easily run on the browser. In this article, we will build and configure a React TS app using Webpack to load on the client.

### Setting up the project:

#### We will be creating the project from scratch.

**Step 1: Initialize package.json**

The first step is to create a folder and initialize that with npm init for the package.json file. For this project, we will follow the default options. To create a default package.json file, run the following command from the folder on your terminal or vscode terminal.

```sh
npm init --y
```

![](https://www.skcript.com/svrmedia/heroes/image4-24.png)

The --y command will choose the default values for all the fields.

You can also run.

```sh
npm init
```

But, this will take you through all the fields manually and ask you for a value. You can skip each value by pressing enter.

![](https://www.skcript.com/svrmedia/heroes/image3-4.gif)
Me when I say yes to each field.

I prefer the --y param because it lets you create the same file with one command rather than each field.

**Step 2: Add the necessary packages to the package.json**

We will be adding the following to the package.json file

Developer Dependencies

* **babel** (core, env, react, ts and loader) as the transcompiler.
* **cross-env** for setting environment variables across cross platforms.
* **html-webpack-plugin** to create HTML files and serve your bundle.
* **serve** to serve the single page created.
* **terser-webpack-plugin** to minify your bundled javascript.
* **typescript**
* **@types/necessary packages** for the type-checked versions.
* **webpack** (core, cli, dev-server) as a webpack package.

Dependencies

* **react**
* **react-dom**

package.json

```json
"dependencies": {
  "react": "^16.12.0",
  "react-dom": "^16.12.0"
},
"devDependencies": {
  "@babel/core": "^7.7.7",
  "@babel/preset-env": "^7.7.7",
  "@babel/preset-react": "^7.7.4",
  "@babel/preset-typescript": "^7.7.7",
  "@types/node": "^12.12.5",
  "@types/react": "^16.9.11",
  "@types/react-dom": "^16.9.3",
  "babel-loader": "^8.0.6",
  "cross-env": "^6.0.3",
  "html-webpack-plugin": "^3.2.0",
  "serve": "^11.3.0",
  "terser-webpack-plugin": "^2.3.2",
  "typescript": "^3.7.4",
  "webpack": "^4.41.5",
  "webpack-cli": "^3.3.10",
  "webpack-dev-server": "^3.10.1"
}
```

**Step 3: Add the necessary scripts**

For our webpack to bundle everything we need to add the scripts to either create a dev server or a production build. Add the following under scripts in package.json.

```json
"scripts": {
  "dev": "cross-env NODE_ENV=development webpack-dev-server",
  "build": "cross-env NODE_ENV=production webpack",
  "start": "serve dist"
},
```

**cross-env** will make sure that the environment variable setting is consistent across all the platforms. We will create 2 scripts, 1 for the development and 1 for production. We will use the **webpack-dev-server** for the development bundle and **webpack** for the production build. The bundle will be created in the dist folder and we can **serve** the dist folder in the development or production builds.

This is the setup for package.json. After doing this run **npm install** to install all the dependencies.

**Step 4: Adding the babel configuration file**

Now for the babel compiler to work in sync with webpack, we need to add the configuration for babel. Create a file called ‘**.babelrc**’ and add the following in the file.

```json
{
  "presets": ["@babel/env", "@babel/react", "@babel/typescript"]
}
```

This will just tell babel to use the env, react and typescript presets.

**Step 5: Add the tsconfig for the typescript configurations**

We need to create a tsconfig.json file in our root directory for typescript configurations. If you have typescript installed, the easiest way to generate this file is to use

```sh
tsc --init
```

This will add a tsconfig.json to your root directory with all the possible configurations. For this project, we will create a tsconfig.json file manually and add simple configuration options like

```json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "jsx": "react",
    "moduleResolution": "node",
    "strict": true,
    "noEmit": true,
    "allowJs": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}
```

You can take a look at all possible options in the typescript documentation for further details.

**Step 6: Webpack Configuration**

This is one of the most confusing configuration options that developers come across in projects. Let us first create a file called webpack.config.js in the root directory and add the following.

First, we need to import our plugins. The 2 main plugins we will be using here are the **html-webpack plugin** and the **terser-webpack-plugin.** We will also import the path package to read the files from their relative path. Import them as follows:

```js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
```

Next, we will create the configuration object as follows:

```js
const isProd = process.env.NODE_ENV === "production";

const config = {
  mode: isProd ? "production" : "development",
  entry: {
    index: "./src/index.tsx",
  },
  output: {
    path: resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  resolve: {
    extensions: [".js", ".jsx", ".ts", ".tsx"],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "babel-loader",
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html",
      inject: "body",
    }),
  ],
};

if (isProd) {
  config.optimization = {
    minimizer: [new TerserWebpackPlugin()],
  };
} else {
  config.devServer = {
    port: 9000,
    open: true,
    hot: true,
    compress: true,
    stats: "errors-only",
    overlay: true,
  };
}

module.exports = config;
```

The most important options in webpack are **entry, output,** and **module**.

* The **entry** specifies the entry point of the application.
* **output** specifies where the bundle has to be built to.
* **modules** specify the test cases to classify the files and use the corresponding loaders for those files. In this case, we have used the babel-loader on the files with **.tsx** extension.

We have also added some ‘dev’ vs ‘prod’ conditions to either run on the dev server if the environment specified is **development** or minify the bundle if it is **production**.

**Step 7: Adding React**

Finally, we need to add a react in the code. Just add an src folder in the root directory and create the following files.

* **index.html**
* **index.tsx**
* **App.tsx**

Add the following code to the files.

**index.html**

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Webpack with React TS</title>
  </head>
  <body></body>
</html>
```

**index.tsx**

```js
import React from "react";
import { render } from "react-dom";
import App from "./App";

render(<App />, document.body);
```

**App.tsx**

```js
import React from "react";
const App: React.FC = (props) => {
  return <div>Webpack is cool!</div>;
};

export default App;
```

**Step 8: Run the webpack servers**

**npm run dev:** This will use the webpack dev-server to create a dev server and will watch for your code changes and be recompiled every time you make a change.

![](https://www.skcript.com/svrmedia/heroes/image2-33.png)

**npm run build:** This command will build your code and generate a single bundle file and insert it into the html file generated.

![](https://www.skcript.com/svrmedia/heroes/image6-11.png)

**npm run start:** This command will run the serve package which will use the dist folder to create a static page.

![](https://www.skcript.com/svrmedia/heroes/image1-34.png)

![](https://www.skcript.com/svrmedia/heroes/image5-20.png)

And that’s it. We have our application with a webpack configured and ready to go. The main reason for writing this article is to make the people understand how the webpack works or any other generic bundling tool works. A lot of people would say to just use a template and get it done within 5 - 10 minutes, but the whole point is to understand what you are doing with it. I have had a lot of issues with this because I used to use templates, but once I got to know how the actual flow works, it was really interesting.