Webpack has become one of the most important tools for modern web development and yet, it is a blackbox to many developers. In this tutorial, we are going to setup our own basic Webpack 4 configuration from scratch for React with Typescript.
If you just want to try something or build a simple side project, you should use the create-react-app
with Typescript. There is no configuration needed, you can focus on coding.
Webpack’s core concepts
At its core, Webpack is a static module bundler for modern JavaScript applications. When Webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.
To get started with Webpack, we only need to understand the following core concepts:
- Entry
- Output
- Loaders
- Plugins
The entry is which file, or module, should Webpack use to start resolving the dependencies. The default value in Webpack 4 is ./src/index.js
.
The output property tells Webpack how to name the bundle files and where it should output them. The default value in Webpack 4 is the ./dist
folder.
The loaders allow Webpack to process different types of imported files other than Javascript. Without loaders, Webpack only knows how to process Javascript files. Loaders allow you to create rules in your configuration file telling webpack to use a specific loader when it encounters a specific type of file.
Plugins allow you to extend Webpack’s capabilities like: bundle optimization, assets management, etc. There are many plugins that Webpack provides out-of-box.
Now that you know the basics, let’s install and configure Webpack.
Installing Webpack
First, let’s create a new project folder and initialize it:
mkdir react-typescript-webpack-tutorial
cd react-typescript-webpack-tutorial
npm init –y #-y skips all the questions
Let’s now install Webpack and the Webpack CLI as dev-dependencies:
#yarn
yarn add webpack webpack-cli --dev
#npm
npm i webpack webpack-cli --save-dev
Webpack 4 has two modes: development
and production
. The bundle will be minimized on production
mode only.
Let’s add two npm scripts to our package.json
to run Webpack:
"scripts": {
"start": "webpack --mode development",
"build": "webpack --mode production"
}
If we create an index.js
file inside an src
folder (default entry point in Webpack 4), we can run Webpack without any configuration.
Let’s create the src/index.js
file with dummy code:
console.log('hello')
And then run npm start
to generate our Javascript bundle file named main.js
inside the dist
folder.
Configuring Webpack
Let’s configure Webpack to better fit our needs.
First, we need to create Webpack’s configuration file named webpack.config.js
in the root of our project. The basic configuration looks like this:
const path = require("path")
module.exports = {
entry: "./src/index.js", // entry point
output: {
path: path.join(__dirname, "/dist"), // bundle output path
filename: "index_bundle.js" // bundle name
}
}
- We specified
src/index.js
as the entry point - We told Webpack to output the bundle into the
dist
folder with the nameindex_bundle.js
Next, let’s add Typescript.
Adding Typescript
First, we need to install the dependencies:
#yarn
yarn add typescript awesome-typescript-loader --dev
#npm
npm i --save-dev typescript awesome-typescript-loader
awesome-typescript-loader
will help Webpack compile our Typescript code and generate sourcemaps.
Adding a Typescript configuration file
Now we need to create a tsconfig.json
file at the root of our project, which will contain all the compilation settings:
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": [
"./src/**/*"
]
}
You can learn more about the tsconfig.json
file here.
Configuring Webpack for Typescript
We need to tell Webpack to use our awesome-typescript-loader
for Typescript files.
Let’s update our webpack.config.js
file, explanations are in comments:
const path = require("path")
module.exports = {
// Changed the entry point to a .tsx file
entry: "./src/index.tsx",
// Enable sourcemaps for debugging Webpack's output
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
output: {
path: path.join(__dirname, "/dist"),
filename: "index_bundle.js"
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
}
]
}
}
Testing the configuration
To test our configuration, we first need to change the extension of our index.js
file to index.tsx
and then add simple Typescript code inside it:
type Message = {
body: string,
from: string
}
let message: Message = {
from: 'Max',
body: 'Hi!'
}
console.log(`New message from ${message.from}: ${message.body}`)
If we run npm start
, you will see in the dist
folder that Webpack transformed our Typescript code and also generated a sourcemap file.
Adding React
Let’s now add React and ReactDOM, along with their declaration files, as dependencies:
# yarn
yarn add react react-dom @types/react @types/react-dom
# npm
npm i react react-dom @types/react @types/react-dom
And create a simple Message.tsx
React component in the src/components
folder:
import * as React from 'react'
class Message extends React.Component<MessageProps> {
render() {
return (
<div>
{`You got a new message from ${this.props.from}: ${this.props.body}`}
</div>
)
}
}
interface MessageProps {
body: string
from: string
}
export default Message
And modify the index.tsx
file to import React and ReactDOM and make it render our new Message
component:
import * as React from "react";
import * as ReactDOM from "react-dom";
import Message from "./components/Message";
ReactDOM.render(
<Message from='Max' body='Hi !' />,
document.getElementById("root")
);
Now if we run npm start
, Webpack should be able to tranform and bundle our React code!
Adding HTML
I voluntarily didn’t create an HTML file yet, because we are going to use a Webpack plugin called html-webpack-plugin
for that. This plugin will generate an HTML file using a template that we are going to give him, and automatically include our Webpack bundles inside the body:
# yarn
yarn add html-webpack-plugin --dev
# npm
npm i --save-dev html-webpack-plugin
After having installed the plugin, we need to add it to our Webpack config’s plugins section:
const path = require("path")
// Require the new plugin
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/index.tsx",
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"]
},
output: {
path: path.join(__dirname, "/dist"),
filename: "index_bundle.js"
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html" // Specify the HTML template to use
})
]
}
Now let’s create a simple index.html
template in the src
folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>TypeScript + React</title>
</head>
<body>
<div id="root">
</div>
</body>
</html>
Running npm start
will now generate our Javascript bundle and an HTML file with our bundle already included with a script tag inside the body.
Setting up a development server
Finally, we are going to setup a development server that will provide us live reloading using the webpack-dev-server
module.
First, we need to install the module:
# yarn
yarn add webpack-dev-server --dev
# npm
npm i webpack-dev-server --save-dev
And then change the start
script in our package.json
file to:
"scripts": {
"start": "webpack-dev-server --mode development --open --hot",
"build": "webpack --mode production"
}
We are telling Webpack DevServer to run on development mode while watching for changes.
- The
--hot
option enables Webpack’s Hot Module Replacement. - The
--open
option will open our default browser when we runnpm start
.
For more options, check out the DevServer section in the Webpack documentation
Conclusion
We can now run npm start
to start a development server with hot reloading and npm build
to have a minimized bundle for production.
This is only a basic configuration of Webpack for a React project in Typescript. This article is already long so I didn’t add other features, but you should definitely push it further by adding other loaders, plugins and optimizing the configuration.
If you have any question or suggestion, please leave a comment below.