DEV Community

Cover image for Webpack with React Typescript
Sooraj (PS) for Skcript

Posted on • Updated on • Originally published at skcript.com

Webpack with React Typescript

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?

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.

npm init --y
Enter fullscreen mode Exit fullscreen mode

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

You can also run.

npm init
Enter fullscreen mode Exit fullscreen mode

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


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

"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"
}
Enter fullscreen mode Exit fullscreen mode

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.

"scripts": {
  "dev": "cross-env NODE_ENV=development webpack-dev-server",
  "build": "cross-env NODE_ENV=production webpack",
  "start": "serve dist"
},
Enter fullscreen mode Exit fullscreen mode

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.

{
  "presets": ["@babel/env", "@babel/react", "@babel/typescript"]
}
Enter fullscreen mode Exit fullscreen mode

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

tsc --init
Enter fullscreen mode Exit fullscreen mode

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

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

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:

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
Enter fullscreen mode Exit fullscreen mode

Next, we will create the configuration object as follows:

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;
Enter fullscreen mode Exit fullscreen mode

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

<!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>
Enter fullscreen mode Exit fullscreen mode

index.tsx

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

render(<App />, document.body);
Enter fullscreen mode Exit fullscreen mode

App.tsx

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

export default App;
Enter fullscreen mode Exit fullscreen mode

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.

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

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

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.

Top comments (0)