This article explains how to build a modern web application development environment using React and TypeScript from scratch with webpack and Babel.
What is Webpack?
Webpack is a module bundler for JavaScript applications. It analyzes multiple JavaScript files and other assets (CSS, images, etc.) based on their dependencies and bundles them into single or multiple files that can be executed in the browser.
- Key Features:
- Module resolution: Interprets
importandrequiresyntax and resolves dependencies. - Bundling: Combines multiple files into one.
- Transpilation: Works with loaders like Babel to convert new JavaScript syntax for older browsers.
- Optimization: Performs optimizations like code minification and dead code elimination.
- Module resolution: Interprets
What is Babel?
Babel is a JavaScript transcompiler. It is primarily used to convert code written in the latest JavaScript (ES2015+) into compatible JavaScript (ES5, etc.) that runs in older browsers and execution environments.
- Key Features:
- Syntax conversion: Converts
async/await, arrow functions, class syntax, etc. - JSX conversion: Converts React’s JSX syntax to regular JavaScript.
- TypeScript conversion: Converts TypeScript code to JavaScript (does not perform type checking).
- Syntax conversion: Converts
Environment Setup
Installing Required Modules
Create a project directory and initialize with npm.
mkdir react_test
cd react_test
# Initialize the project
npm init -y
# Babel-related modules
npm install -D @babel/core # Babel core
npm install -D @babel/preset-env # Convert latest JS syntax for target environments
npm install -D @babel/preset-react # Convert React JSX
npm install -D @babel/preset-typescript # Convert TypeScript
# Webpack-related modules
npm install -D webpack webpack-cli babel-loader ts-loader # Webpack core, CLI, and loaders for Babel/TS
npm install -D webpack-dev-server html-webpack-plugin # Dev server and HTML generation plugin
# React and TypeScript modules
npm install react react-dom # React core and DOM library
npm install -D typescript @types/react @types/react-dom # TypeScript and React/ReactDOM type definitions
# Generate tsconfig.json
npx tsc --init
File Structure
The final file structure will look like this.
.
├── dist/
│ ├── index.html
│ └── main.js
├── node_modules/
├── package-lock.json
├── package.json
├── src/
│ ├── index.html
│ └── index.tsx
├── tsconfig.json
└── webpack.config.js
Configuration Files
src/index.html
The HTML file that serves as the entry point for the React application. React components are mounted on the div element.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React App</title>
</head>
<body>
<div id="app"></div>
<!-- Bundled JavaScript by Webpack is automatically injected here -->
</body>
</html>
src/index.tsx
The main entry file for the React application, written in TypeScript and JSX.
import React from "react";
import { createRoot } from "react-dom/client"; // Use createRoot from React 18
const App = () => {
return <h1>Hello React with TypeScript!</h1>;
};
// Use the new React 18 API
const container = document.getElementById("app");
if (container) {
const root = createRoot(container);
root.render(<App />);
}
.babelrc
The Babel configuration file. Defines which presets (sets of plugins) are used to transform the code.
{
"presets": [
"@babel/preset-env", // Convert latest JS for target environments
"@babel/preset-react", // Convert React JSX
"@babel/preset-typescript" // Convert TypeScript (no type checking)
]
}
package.json
Defines project metadata, scripts, and dependencies. Add the dev server startup command and build command to the scripts section.
{
"name": "react_test",
"version": "1.0.0",
"description": "React with TypeScript development environment",
"main": "index.js",
"scripts": {
"start": "webpack serve --open", // Start dev server and auto-open browser
"build": "webpack --mode production" // Build for production
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"babel-loader": "^9.1.0",
"html-webpack-plugin": "^5.5.0",
"ts-loader": "^9.4.1",
"typescript": "^4.8.4",
"webpack": "^5.75.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
tsconfig.json
The TypeScript compiler configuration file. Defines the rules for converting TypeScript code to JavaScript.
{
"compilerOptions": {
"target": "es2015", // Output JavaScript version
"module": "esnext", // Module system (esnext is flexible for Webpack)
"jsx": "react-jsx", // JSX conversion method (React 17+ new JSX transform)
"strict": true, // Enable strict type checking
"esModuleInterop": true, // Improve CommonJS and ES module compatibility
"skipLibCheck": true, // Skip type checking for declaration files (faster builds)
"forceConsistentCasingInFileNames": true, // Enforce consistent file name casing
"moduleResolution": "node", // Module resolution strategy
"resolveJsonModule": true, // Allow JSON file imports
"isolatedModules": true, // Compile each file as an independent module
"noEmit": true, // Don't output JS from TypeScript (Babel/Webpack handles this)
"allowJs": true, // Allow compiling JavaScript files
"lib": ["dom", "dom.iterable", "esnext"] // Available libraries
},
"include": ["src"] // Files to compile
}
webpack.config.js
The Webpack bundling configuration file. Defines the entry point, output, loaders, and plugins.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// Set to development mode (enables optimization and debug info)
mode: "development",
// Entry point (application starting point)
entry: "./src/index.tsx",
// Output configuration
output: {
path: path.resolve(__dirname, "dist"), // Output directory
filename: "bundle.js", // Output filename
clean: true, // Clean dist directory before build
},
// Module resolution settings
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"], // Extensions to resolve on import
},
// Module rules (loader configuration)
module: {
rules: [
{
test: /\.(ts|tsx)$/, // Apply to .ts or .tsx files
exclude: /node_modules/, // Exclude node_modules
use: {
loader: "babel-loader", // Transform using Babel
options: {
presets: [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
],
},
},
},
// Loaders for CSS, images, etc. can be added here
],
},
// Plugin configuration
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html", // HTML file to use as template
filename: "index.html", // Output HTML filename
}),
],
// Dev server configuration
devServer: {
static: {
directory: path.join(__dirname, "dist"), // Static file directory
},
compress: true, // Enable gzip compression
port: 3000, // Dev server port
open: true, // Auto-open browser on server start
hot: true, // Enable Hot Module Replacement
},
// Source map configuration (for debugging)
devtool: "eval-source-map",
};
Once all these configuration files are in place, you can start the dev server with npm start and create a production build with npm run build.