In this article, we will learn how to setup a webpack in our application.
Webpack also referred to as module bundler, is a tool for compiling JavaScript modules. It turns a large number of files into a single file (or a few files) that runs your software. It is capable of a wide range of jobs, including supporting you in putting your resources together.
Frist run the following command and create a project,
$ npx create-react-app webpack-configs $ cd webpack-configs
Now install webpack and babel,
npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin @babel/core @babel/preset-env babel-loader @babel/preset-react babel-plugin-transform-class-properties babel-plugin-transform-es2015-modules-commonjs
Once done, add your package.json file in following script,
"scripts": { ... "webpack": "webpack", "webpack-dev-server": "webpack-dev-server", "dev": "npm run webpack-dev-server -- --env mode=development", "prod": "npm run webpack -- --env mode=production" }
Then for the configuration of the babel you have to add the following command,
$ touch .babelrc
And add the following code into babelrc file
{ "presets": [ "@babel/preset-react", [ "@babel/preset-env", { "targets": { "browsers": "last 2 versions" }, "modules": false, "loose": false } ] ], "plugins": [ "transform-class-properties" ], "env": { "test": { "plugins": [ "transform-es2015-modules-commonjs" ] } } }
We’ll also need a file to store our app’s generic webpack configurations. Run the following command in your terminal:
$ touch webpack.config.js
Add following command to configrating webpack to load and static files
$ npm i -D babel-loader file-loader url-loader
Add following code into webpack file
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = ({ mode } = { mode: "production" }) => { console.log(`mode is: ${mode}`); return { mode, entry: "./src/index.js", output: { publicPath: "/", path: path.resolve(__dirname, "build"), filename: "bundle.js" }, module: { rules: [ { test: /\.jpe?g|png$/, exclude: /node_modules/, use: ["url-loader", "file-loader"] }, { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: "babel-loader" } ] }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html" }), ] } };
Then you should on devserver in webpack file
devServer: { open: true }
Then we have to setting hot modules replacement
However, we do have a problem. The server reloads every time we make a modification, and we lose our state. To address this, we may use the Hot Module Replacement plugin that comes with webpack in our setup. Make the following changes to the webpack.config.js file:
const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = ({ mode } = { mode: "production" }) => { console.log(`mode is: ${mode}`); return { mode, entry: "./src/index.js", devServer: { hot: true, open: true }, output: { publicPath: "/", path: path.resolve(__dirname, "build"), filename: "bundle.js" }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: "babel-loader" } ] }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html" }), new webpack.HotModuleReplacementPlugin() ] } };
Then add following command
npm i -D react-hot-loader
Update babelrc file
{ "presets": [ "@babel/preset-react", [ "@babel/preset-env", { "targets": { "browsers": "last 2 versions" }, "modules": false, "loose": false } ] ], "plugins": [ "transform-class-properties", "react-hot-loader/babel" ], "env": { "test": { "plugins": [ "transform-es2015-modules-commonjs" ] } } }
Add below code in your index.js file
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import reportWebVitals from './reportWebVitals'; const rootId = document.getElementById("root"); ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, rootId ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals(); if (module.hot && process.env.NODE_ENV === "development") { module.hot.accept("./App", () => { const NextApp = require("./App").default; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, rootId ); }); }
Handling styles in webpack you can see follow
npm i -D sass-loader css-loader style-loader
Setting up webpack options that are appropriate to your environment
Before we set up the loaders, we need to separate our settings. When shipping to manufacturing, we want the packages to be as light as feasible. In terms of development, though, we aren’t as concerned. As a result, in both modes, we’d handle stylesheets differently. Let’s get started with the environment-specific configurations.
mkdir build-utils
npm i -D webpack-merge
Replace the code in webpack.config.js with the following
const path = require("path"); const webpack = require("webpack"); const { merge } = require("webpack-merge"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const modeConfiguration = env => require(`./build-utils/webpack.${env}`)(env); module.exports = ({ mode } = { mode: "production" }) => { console.log(`mode is: ${mode}`); return merge( { mode, entry: "./src/index.js", devServer: { hot: true, open: true }, output: { publicPath: "/", path: path.resolve(__dirname, "build"), filename: "bundle.js" }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: "babel-loader" } ] }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html" }), new webpack.HotModuleReplacementPlugin() ] }, modeConfiguration(mode) ); };
Configuring production-specific settings
npm i -D mini-css-extract-plugin
Then, under build utils/webpack.production.js, add the following code:
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = () => ({ output: { filename: "production.js" }, module: { rules: [ { test: /\.sa?css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] } ] }, plugins: [new MiniCssExtractPlugin()] });
Even if it isn’t optimised, we can now see our CSS file in the output folder. We can use plugins like optimize-css-assets-webpack-plugin and uglifyjs-webpack-plugin to minify CSS.
To install the plugins that will help us improve our CSS, run the following commands:
npm i -D optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
Update the webpack.production.js
file with the code below:
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); module.exports = () => ({ devtool: "nosources-source-map", output: { filename: "production.js" }, optimization: { minimizer: [ new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true // set to true if you want JS source maps for css }), new OptimizeCSSAssetsPlugin({}) ] }, module: { rules: [ { test: /\.sa?css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] } ] }, plugins: [new MiniCssExtractPlugin()] });
Then, start your project you can see the below code,
npm run dev