A Complete Webpack Setup for React

A Complete Webpack Setup for React

Build a React project with Webpack 4 and Babel 7

Why Webpack?

Congrats. You have started using JavaScript in your application. You have heard great things about how awesome it is. So you have a single script for your page, maybe 500 lines and it’s mostly ok to manage. As you decide to add more features, more developers join you, and the project grows.

Now the script file is big and clunky. It’s hard to maintain and to find particular sections. So, the natural decision is to split the files into several smaller files. Great! But how do you manage all of these files? And more importantly, in what order they have to be loaded! Some files depend on others to be loaded first.

You think about it for some time and decide that it would be very nice if we could add some way for a particular file to say what other files it needs to be available before it can run its?dependencies?if you will. Good news! Node.js includes a mechanism to do exactly what we want: define “modules” which can have some private/local parts, can?export?some public parts, and can?require?other modules.

Great, we now have solved the dependency problem, but we still have multiple files and the need to?bundle?it all up into a single file, and we need to make that file work in a browser (not in NodeJS).

This is why webpack exists. It’s a tool that lets you bundle your JavaScript applications (supporting both ESM and CommonJS), and it can be extended to support many different assets such as images, fonts, and stylesheets.

Webpack is a?static module bundler?for modern JavaScript applications. When webpack processes your application, it internally builds a?dependency graph?that maps every module your project needs and generates one or more?bundles.

No alt text provided for this image
No alt text provided for this image

How does it work?

First, Webpack always needs at least one?entry point, you can have multiple ones. Webpack will analyze the dependencies of this file and to another file which then, in turn, has more dependencies, so webpack can build up a dependency graph.

webpack.config.js

module.exports = {
  entry: './path/to/my/entry/file.js'
};        

The?output?property tells webpack where to emit the?bundles?it creates and how to name these files. It defaults to?./dist/main.js?for the main output file and to the?./dist?folder for any other generated file. And there it will put all these dependencies into that file, correctly ordered and in one concatenated

webpack.config.js

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};
        

Between the entry point and output, there are two important steps:

  • Loaders?allow webpack to process other types of files and convert them into valid?modules?that can be consumed by your application and added to the dependency graph. Loaders are applied on a per-file level so we can have all javascript files should get handled by one loader and all CSS files should be handled by another loader.

babel-loader and css-loader are two popular examples which get used in a lot of projects

  • Plugins?can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.

Here we can apply some general transformations or optimizations like uglify, so this is on a global level and happens after the loaders did their job.

Finally, by setting the?mode?parameter to either?development,?production?or?none, you can enable webpack's built-in optimizations that correspond to each environment.

module.exports = {
  mode: 'production'
};        

So, let’s dive into building an example project setup.

Project Setup

First, you will need to download and install node

Create a folder

mkdir webpack-react-starter
cd webpack-react-starter        

Init your project. -y will skip the questions

npm init -y        

Install webpack, CLI and the development server for testing

npm install --save-dev webpack webpack-cli webpack-dev-server        

Install React and React DOM as dependencies

npm install react react-dom        

Install Core and JavasScipt Loaders

npm install --save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react        

Babel is a third party library that is used to convert ECMAScript 2015+ code into a backward-compatible version of JavaScript in current and older browsers or environments.

  • babel/core:?The core babel library
  • babel/preset-env:?Is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s)This is also known as browser polyfills
  • babel/preset-react:?Transform React JSX into regular JavaScript code
  • babel-loader:?Webpack loader helper

Install CSS Loaders

npm install --save-dev css-loader style-loader postcss-loader postcss --save-dev        

  • CSS-loader:?Handle CSS files
  • style-loader:?The style-loader takes CSS and actually inserts it into the page so that the styles are active on the page.
  • postcss-loader:?Will process CSS to work on older browsers

Install Image Loaders

npm install --save-dev file-loader url-loader        

  • URL-loader:?Will load the image files. Url loader depends on file-loader

Install Plugins

npm install --save-dev autoprefixer
npm install --save-dev html-webpack-plugin        

  • autoprefixer:?Autoprefixer is a PostCSS plugin which parses your CSS and adds vendor prefixes
  • HTML-webpack-plugin:?The?HtmlWebpackPlugin?simplifies the creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation.

Project Structure

Create a basic project structure:

mkdir -p src
touch src/index.html src/index.js src/index.css        

Open your favourite IDE, I recommend Visual Studio code

Edit your index.html

<!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>My React App</title>
	</head>
	<body>
	    <div id="root"></div>
	</body>
	</html>>        

index.html

Edit your index.js

import React from "react"
	import ReactDOM from "react-dom";
	

	import MyImage from './assets/dog.jpg';
	import './index.css';
	

	const App = () => {
	  return (
	    <div>
	        <div>Welcome to my-webpack-react-starter</div>
	        <img src={MyImage} />
	    </div>
	  );
	};
	

	ReactDOM.render(<App />, document.querySelector("#root"));;        

index.js

Edit your index.css


body 
	    margin: 50;
	    padding: 50;
	}
	

	div {
	    background-color: teal;
	}
	

	img {
	    width: 640px;
	    height: 426px;
	}{        

index.css

Create an?assets?folder

Add a picture of your favorite pet. I called mine dog.jpg.

This should be your project structure:

No alt text provided for this image

project structure

Build Configuration for Webpack and Babel

Now, we will move to the actual build configuration for babel and webpack

Create a?.babelrc?file inside the root of your project folder and insert the below lines to it.

touch .babelrc        

Babel will automatically look for this file where we can configure how Babel behaves in there. In this file, you specify all the presets to apply in your code

{ "presets": ["@babel/preset-env", "@babel/preset-react"] }        

In your?package.json?file include your start script for dev, your build script for the production build.

This is the complete file:



{
  "name": "webpack-react-starter",
? "version": "1.0.0",
? "description": "A Webpack + Babel + React Starter bolerplate ",
? "repository": {
? ? "type": "git",
? ? "url": "https://github.com/mlomboglia/webpack-react-starter"
? },
? "keywords": [
? ? "Autoprefixer",
? ? "PostCSS",
? ? "Webpack",
? ? "React",
? ? "Babel"
? ],
? "author": "Marcos Lomboglia <[email protected]> (https://marcoslombog.com)",
? "main": "index.js",
? "scripts": {
? ? "test": "echo \"Error: no test specified\" && exit 1",
? ? "start": "webpack-dev-server --open --hot --mode development",
? ? "build": "webpack --mode production"
? },
? "license": "MIT",
? "browserslist": "> 1%,last 2 versions",
? "devDependencies": {
? ? "@babel/core": "^7.7.5",
? ? "@babel/preset-env": "^7.7.6",
? ? "@babel/preset-react": "^7.7.4",
? ? "autoprefixer": "^9.7.3",
? ? "babel-loader": "^8.0.6",
? ? "css-loader": "^3.3.2",
? ? "file-loader": "^5.0.2",
? ? "html-webpack-plugin": "^3.2.0",
? ? "postcss": "^8.1.0",
? ? "postcss-loader": "^4.0.2",
? ? "style-loader": "^1.0.1",
? ? "url-loader": "^3.0.0",
? ? "webpack": "^4.41.3",
? ? "webpack-cli": "^3.3.10",
? ? "webpack-dev-server": "^3.9.0"
? },
? "dependencies": {
? ? "react": "^16.12.0",
? ? "react-dom": "^16.12.0"
? }
}         

package.json

Create a?webpack.config.js?in the root folder

  • entry: webpack will start from index.js as the entry point
  • output: all files will be bundled into a file called bundle.js and copied to?/dist?folder
  • resolve:?webpack will resolve to .js and .jsx extensions
  • module:?this are the loader rules that will be considered. For js files, webpack should use the?babel-loader.?For css, use?style-loader?with?css-loader?and?postcss-loader. Finally for images, use the?url-loader.
  • plugins:?use the HtmlWebpackPlugin with index.html to inject the body


    const path = require('path')
	const autoprefixer = require('autoprefixer');
	const HtmlWebpackPlugin = require('html-webpack-plugin');
	

	module.exports = {
	    entry: './src/index.js',
	    output: {
	        path: path.resolve(__dirname, 'dist'),
	        filename: 'bundle.js',
	        chunkFilename: '[id].js',
	        publicPath: ''
	    },
	    resolve: {
	        extensions: ['.js', '.jsx']
	    },
	    module: {
	        rules: [
	            {
	                test: /\.js$/,
	                loader: 'babel-loader',
	                exclude: /node_modules/
	            },
	            {
	                test: /\.css$/,
	                exclude: /node_modules/,
	                use: [
	                    { loader: 'style-loader' },
	                    { 
	                        loader: 'css-loader',
	                        options: {
	                            modules: {
	                                localIdentName: "      [name]__[local]___[hash:base64:5]",
	                            },														
	                            sourceMap: true
	                        }
	                     },
	                     { 
	                         loader: 'postcss-loader',
	                        options: {
	                            postcssOptions: {
	                                plugins: [
	                                    [ 'autoprefixer', {}, ],
	                                ],
	                            },
	                        }
	                      }
	                ]
	            },
	            {
	                test: /\.(png|jpe?g|gif)$/,
	                loader: 'url-loader?limit=10000&name=img/[name].[ext]'
	            }
	        ]
	    },
	    plugins: [
	        new HtmlWebpackPlugin({
	            template: __dirname + '/src/index.html',
	            filename: 'index.html',
	            inject: 'body'
	        })
	    ]
	};;        

webpack.config.js

Running

Let’s run our example project in development first:

npm run start        

You should see a “compiled successfully” message and load the browser. If not, go to your browser on?https://localhost:8080?and you will see your running React App

To build your production release:

npm run build        

You will have your production build inside the?dist?folder. Just deploy it on any static host provider like AWS S3. I will cover this in a future article.

Happy Coding.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了