Rangga Putra
Posted on January 15, 2023
First, initiate the project by running
npm init
After it's done, let's install the packages we need to run a basic React Single Page Application.
npm i react react-dom react-router-dom
For us to be able to use modern Javascript we need babel to compile our codes.
npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader
create a .babelrc
file to place our babel configuration, for now, only set it to use the preset-env and preset-react
// .babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
Now let's bring webpack into our project
npm i -D webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin
we will use different webpack configurations for the development and production server, so will split our webpack configuration into several files, so later we need to merge it with webpack-merge
.
The html-webpack-plugin
will generate an HTML5 file for us that includes all your webpack bundles. The webpack-dev-server
is required to serve our project in development, and we will use the webpack-cli
to build and serve our project.
Now we have to setup the webpack configurations and the app's entry point. First, we create the common webpack configuration in a file named webpack.common.js
in there we will set the app's entry point, how files are resolved, and bundles output and we will also configure webpack to handle asset files like images and font.
// webpack.common.js
const path = require("path");
module.exports = {
entry: {
app: "./src/index.js",
},
resolve: {
extensions: ["*", ".js", ".jsx"],
},
output: {
filename: "[name]-[fullhash].js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
optimization: { runtimeChunk: true },
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.(svg|ico|png|jpg|jpeg|gif|webp)$/,
use: {
loader: "file-loader",
options: {
name: "[name]-[fullhash].[ext]",
outputPath: "assets/img",
},
},
},
{
test: /\.(otf|eot|ttf|woff2|woff)$/,
use: {
loader: "file-loader",
options: {
name: "[name]-[fullhash].[ext]",
outputPath: "assets/font",
},
},
},
],
},
};
Next, let's create a configuration for the development, and name the file webpack.dev.js
we will merge the common configration with this development-only configuration in which we set the dev server, and type of source-map and we will also configure webpack to handle CSS files and HTML templates.
// webpack.dev.js
const path = require("path");
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
mode: "development",
devtool: "eval-source-map",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
devServer: {
static: {
directory: path.join(__dirname, "dist"),
},
liveReload: true,
open: true,
port: 8080,
historyApiFallback: true,
compress: true,
},
optimization: {
minimize: false,
},
plugins: [
new HtmlWebpackPlugin({
title: "react app",
template: "./src/index.html",
}),
],
});
Finally, we create a configuration for the production. for the production build, we want to minimize the bundles so we add additional plugins to optimize our file, for CSS we use css-minimizer-webpack-plugin
to minify the CSS using nanocss under the hood and mini-css-extract-plugin
to extract our CSS into separated bundle file. so let's install both of them.
npm i -D css-minimizer-webpack-plugin mini-css-extract-plugin
For HTML optimization, we will use the HtmlWebpackPlugin
to minify our document, while for Javascript we can use terser which is included in webpack 5 and enabled by default.
// webpack.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const common = require("./webpack.common.js");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "production",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
optimization: {
minimize: true,
minimizer: [
`...`,
new CssMinimizerPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
minify: {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
},
}),
],
},
plugins: [new MiniCssExtractPlugin()],
});
For the React app's entry point, first let's create a folder called src
inside the folder, create an HTML5 document to attach our React app into
// src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
</body>
</html>
Let's also create a React component with a little hello world in it
// src/App.jsx
import React from "react";
const App = () => {
return <h1>Hello World</h1>;
};
export default App;
Finally, create a Javascript to render our main React app and setup react-router
routes
// src/index.js
import React from "react";
import { createRoot } from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from "./App";
const router = createBrowserRouter([
{
path: "/",
element: <App />,
},
]);
createRoot(document.getElementById("app")).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
Let's also add scripts to run and build our project to the package.json
"scripts": {
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
Now try running npm run dev
command and it should work and launch a development server
Posted on January 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.