Webpack 3 quickstarter: Configure webpack from scratchby@nirjhor123
34,913 reads
34,913 reads

Webpack 3 quickstarter: Configure webpack from scratch

by NirjhorSeptember 30th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

WEBPACK! Simply, it’s a module bundler, means — you can create as many modules(not only JS, but also HTML & CSS too!) while developing an app. Webpack takes the responsibility to bundle your application and give you the customized simplest version of your app which contains only HTML, CSS & Javascript.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Webpack 3 quickstarter: Configure webpack from scratch
Nirjhor HackerNoon profile picture

Why another webpack tutorial? Because, almost everything about it is confusing and I’ve suffered a lot like you. That’s why I’ve decided to write this step-by-step procedure to make a better webpack configuration with a good understanding of how webpack works. I hope that you won’t get confused and leave again in the middle of configuring webpack again. [updated: 2018 Feb 22]

WEBPACK! Simply, it’s a module bundler, means — you can create as many modules(not only JS, but also HTML & CSS too!) while developing an app. Webpack takes the responsibility to bundle your application and give you the customized simplest version of your app which contains only HTML, CSS & Javascript.

I’ve realized that it’s a habit that have to be developed through understanding the core concepts of how webpack works and then applying it on different projects/demos.

This guide may let you easily configure webpack in just 5 minutes for any kind of projects. No Headaches anymore! In the end of this article, I’m going to give you the simplest cheat-sheet to get ready for any project . Follow along with me. This blog is going to be a bigger one, so why don’t you grab a coffee and stay with me patiently :)

Or, just go to this repo and clone it to use it in your project: webpack-boilerplate

Before starting, let’s see what’s inside this write up ->

  1. Project Setup1.1. Create project folder and land on the project root (via terminal)1.2. Initialize a project via npm1.3. Create project directories1.4. Populating our project directories1.5. Installing webpack

  2. Configuring package.json

  3. Land on the webpack config file3.1. Exporting our config object3.2. Define entry point(s)3.3. Define output point3.4. Define Context

  4. Setting up webpack-dev-server4.1. Installing webpack-dev-server4.2. Adding command to package.json4.3. Configuring webpack-dev-server

  5. Devtool Configuration

  6. Loaders and plugins6.1. Loaders6.2. Plugins

  7. Some loaders and plugins in action7.1. clean-webpack-plugin (PLUGIN)7.2. babel-loader (LOADER)7.3. html-loader (LOADER) & html-webpack-plugin (PLUGIN)7.4. css-loader (LOADER), style-loader (LOADER), sass-loader (LOADER), extract-text-webpack-plugin (PLUGIN)7.5. file-loader (LOADER)

NOTE: I’m using linux in my pc. If you’re using windows, I recommend to look for the respective commands on windows. Mac users should have the same commands as mine.


Follow along with me to create a basic project. App architecture is the most important key!

1.1. Create project folder and land on the project root (via terminal)

> mkdir project_name && cd project_name

1.2. Initialize a project via npm

> npm init

1.3. Create project directories

> mkdir src dist src/assets src/assets/media src/assets/js src/assets/scss

1.4. Populating our project directories

> touch webpack.config.js .babelrc src/index.html src/app.js src/assets/scss/app.scss

NOTE:_.babelrc_ file is for configuring babel (which is going to transpile our ES6/ES2015 code to ES5)_webpack.config.js_ for configuring our webpack’s responsibilities_README.md_ for documentation

1.5. Installing webpack

Install webpack

> npm i -D webpack

npm i -D webpack is just the shortcut of npm install — save-dev webpackAn awesome article about some npm tricks that is so useful for me

Project hierarchy for our setup:



Let’s get some extra headaches out of our brain. We need to build our project for development and for production. And, we don’t want to refresh our browser again and again while modifying our code every time. So why don’t we put some thing to watch our code? 😉

If webpack is already installed globally in your machine, simply write these commands into your package.json scripts:

"scripts": {"build": "webpack","build:prod": "webpack -p","watch": "webpack --watch"}

I think, the better approach is to install updated webpack locally for every project, which will give you a complete freedom in development process.If you’re following the steps already and installed webpack locally, then, changes in package.json would be:

"scripts": {"build": "./node_modules/.bin/webpack","build:prod": "./node_modules/.bin/webpack -p","watch": "./node_modules/.bin/webpack --watch"}

You can get the idea of the directory for those script commands below. Webpack executable binary file stays in this directory


NOTE: If you’re interested to know the details of webpack-cli:

Let’s make some configurations into webpack.config.js to make webpack a li’l bit educated 😃


First thing first -Webpack simply needs to have it’s 4 core things to execute properly. 1. Entry 2. Output 3. Loaders 4. Plugins

We’re going to define entry and output for webpack in this section and watch our first bundled output.

3.1. Exporting our config object

Since, we’re using node.js and webpack uses the modular pattern, we first need to export the configuration object from our webpack.config.js

module.exports = {// configurations here}

OR, this approach:

const config = {// configurations here};module.exports = config;

3.2. Define entry point(s)

Single entry point:

The app starts executing from this point if your app is SPA(Single Page Application). We’ll define a path relative to our project root

const config = {entry: './src/app.js',};

Multiple entry points:

If your app has multiple entry points (like: multi-page application), then, you have to define your entry points inside entry object with identical names. Multiple entry points are called chunks and the properties (individual entry point) of this entry object are called entryChunkName. So, let’s create it:

const config = {entry: {app: './src/app.js',vendors: './src/vendors.js'}}

Look carefully, our entry property is not a string anymore, it’s now a pure javascript object with different entries being the properties of it.

This is so helpful when we want to separate our app entry and vendor (like: jQuery/lodash) entry into different bundles.

3.3. Define output point

Webpack needs to know where to write the compiled files in the disk. That’s why we need to define output point for webpack.

NOTE: while there can be multiple entry points, only ONE output configuration is specified.

We define our output point as an object. This object must include these two following things at least: 1. filename (to use our output files) 2. path (an absolute path to preferred output directory)

We can define path of the output point manually. But that won’t be a wise choice, since our project root’s name and location may change later. Besides, you or your collaborator may clone your projects on different pc in which case the custom absolute path won’t work there too.So, to solve this, we use node.js path module which gives us the absolute path for our project root in a more convenient way.

To use node.js path module we need to import it in our config file and then use it in our output object

const config = {output: {filename: 'bundle.js',// Output path using nodeJs path modulepath: path.resolve(__dirname, 'dist')}};

You can use path.join or path.resolve, though both working kinda same. To not to make this article bigger and distracting, I’m going to skip the process of how node.js path.join and path.resolve works, but giving you the resources:

path.resolve resource : herepath.join resource : here

NOTE: when creating multiple bundles for multiple entry points, you should use one of the following substitutions to give each bundle a unique name

Using entry name:

filename: "[name].bundle.js"

Using hashes based on each chunks’ content:

filename: "[chunkhash].bundle.js"

For more naming options:

Besides, you may want to give a relative path to your output file in the _output.filename_

3.4. Define Context

Context is the base directory, an absolute path, for resolving entry points and loaders from configuration. By default the current directory is used, but it’s recommended to pass a value in your configuration. This makes your configuration independent from CWD (current working directory).

const config = {context: path.resolve(__dirname, "src")};

Until now, our basic setup:

Webpack config file basic setup — 1

Now, fire this command into your terminal to watch your first bundle:

> npm run build

For production ready bundle:

> npm run build:prod

For developing with watch mode ON:

> npm run watch

Voila! 😎 We’ve just landed on the ground of awesomeness!

Now, we’re going to add some loaders and plugins to make our actual configuration object after finishing two more setup. We’re going to use some automation that is provided by webpack.


Hey! Wasn’t that an easy setup to get our first bundle? Now we’re going to get some amazing things that’s gonna boost-up our development process and save us a lot of time. We’re going to get a real server! Yeah, webpack provides us a built-in server for development purpose, so that we’re going to see what’s going to happen while our application is ready for deployment into a real server. But we need to install this server setup first.

NOTE: This should be used for development only.

4.1. Installing webpack-dev-server

Install webpack-dev-server via terminal

> npm i -D webpack-dev-server

4.2. Adding command to package.json

Add this command to scripts in package.json

"dev": "./node_modules/.bin/webpack-dev-server"

4.3. Configuring webpack-dev-server

There are so many configuration options for webpack-dev-server. We’re going to look for some important ones.

In your config object let’s create a new property named devServer (syntax is important)

devServer: {}

This object is ready to get some configuration options such as:

#1 devServer.contentBase

Tell the server where to serve content from. This is only necessary if you want to serve static files.

NOTE: it is recommended to use an absolute path. It is also possible to serve contents from multiple directories

For our project architecture, we want all our static images to be stored in dist/assets/media directory

contentBase: path.resolve(__dirname, "dist/assets/media")

#2 devServer.stats

This option lets you precisely control what bundle information to be displayed. To show only errors in your bundle:

stats: 'errors-only'

for other stats options :


If you want dev-server to open the app at the first time in our browser and just refresh afterwards while we change our code

open: true

#4 devServer.port

Mention which port number you want your application to be deployed in your webpack-dev-server

port: 12000

#5 devServer.compress

Enable gzip compression for everything served

compress: true

Finally our devServer configuration looks like:

devServer: {contentBase: path.resolve(__dirname, "./dist/assets/media"),compress: true,port: 12000,stats: 'errors-only',open: true}


This option controls if and how source maps are generated. With this feature, we know exactly where to look in order to fix/debug issues in our application. Very very useful for development purpose, but should NOT use in production.

devtool: 'inline-source-map'

There are much more options for devtool here

We’ve setup most of the things that’s required for the first moment to configure webpack. Here’s the updated snippet of what we’ve done so far..

Webpack config file basic setup — 2

And our package.json looks like:

package.json file for webpack quickstart

NOTE: It’s worth to mention that at the time of writing this article I was on _webpack 3.6.0_ and _webpack-dev-server 2.9.1_ version. Your version number may differ than that of mine.


We’ve come so far. Now the fun part begins. We’re actually going to explore what webpack can do by itself through some configurations.

6.1. Loaders

Webpack enables use of loaders to pre-process files. This allows you to bundle any static resource way beyond JavaScript. Since webpack still doesn’t know what to do with these loaders, webpack config object use module property to know what loader to work and how to execute them.

module property of config object itself is an object. It works with some extra options mentioned below:

**# module.noParse**

Prevent webpack from parsing any files matching the given RegExp. Ignored files should not have calls to import, require, define or any other importing mechanism. This can boost build performance when ignoring large libraries.

module: {noParse: /jquery|lodash/}

**# module.rules**

It takes every loaders as a set of rules inside an array. Whereas every element of that array is an object containing individual loaders and their respective configurations.

From Webpack’s documentation

A Rule can be separated into three parts — Conditions, Results and Nested Rules.1. Conditions: There are two input values for the conditions a. The resource: An absolute path to the file requested. b. The issuer: The location of the import.

In a Rule the properties test, include, exclude and resource are matched with the resource and the property issuer is matched with the issuer.

2. Results: Rule results are used only when the Rule condition matches. There are two output values of a rule: a. Applied loaders: An array of loaders applied to the resource. b. Parser options: An options object which should be used to create the parser for this module.

3. Nested Rules: Nested rules can be specified under the properties rules and oneOf. These rules are evaluated when the Rule condition matches.

Okay! Let’s simplify them, since webpack doc always confuses us 😖😓

A loader needs some additional information to work correctly and efficiently in a module. We mention them in module.rules with some configuration parameters stated below:

**_test:_**(required) A loader needs to know which file extension it’s going to work with. We give the name with the help of RegExp

test: /\.js$/

**_include:_** (optional) A loader needs a directory to locate where it’s working files are stored.

include: /src/

**_exclude:_** (optional) We can save a lot of unwanted process like — we don’t want to parse modules inside node_modules directory and can save a lot of memory and execution time

exclude: /node_modules/

**_use:_** (required) A rule must have a loader property being a string. Mention the loaders you want to use in for that particular task. Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured).It can have a options property being a string or object. This value is passed to the loader, which should interpret it as loader options. For compatibility a query property is also possible, which is an alias for the options property. Use the options property instead.

use: {loader: "babel-loader",options: {presets: ['env']}}

Detail configuration setup for module.rules:

6.2. Plugins

The plugins option is used to customize the webpack build process in a variety of ways. webpack comes with a variety of built-in plugins available under webpack.[plugin-name]

Webpack has a plugin configuration setup in it’s config object with plugins property.

NOTE: Every plugin needs to create an instance to be used into config object.

We’re going to see them in action now!


7.1. clean-webpack-plugin (PLUGIN)

Every time we want to see our production ready dist folder, we need to delete the previous one. Such a pain! clean-webpack-plugin is to remove/clean your build folder(s) before building. It’s very easy to setup:

Install via npm

> npm i -D clean-webpack-plugin

Import into your webpack.config.js file

const CleanWebpackPlugin = require('clean-webpack-plugin');

Now, we’re going to use a plugin for the first time. Webpack has a plugin configuration setup in it’s config object. Every plugin needs to create an instance to be used into config object. So, in our plugins property:

plugins: [new CleanWebpackPlugin(['dist'])]

Here, in the instance of clean-webpack-plugin we mention dist as an array element. Webpack now knows that we want to clean/remove dist folder every time before building our bundle. This instance can have multiple directory/path as array elements and multiple options as object.

Syntax for clean-webpack-plugin usage:

plugins: [new CleanWebpackPlugin(paths [, {options}])]

You should watch the process of removing and creating your dist folder live in your directory and in your IDE too..

Reference doc: GitHub Doc

Until now our webpack.config.js looks like:

Webpack config file basic setup — 3

7.2. babel-loader (LOADER)

We all want to write some ES2015/ES6 code, right? But until now our browser is not fully adopted to ES6 syntax, so we need to at first transpile our ES6 code to ES5 and then we can use it in our production bundle. Babel is taking that responsibility for us. We just need to include babel-loader into our configuration through some easy steps.

Install babel-loader

> npm i -D babel-loader babel-core

Create .babelrc file in our project root to enable some babel-presets (We’ve already done it in project setup section. If you follow along with me, you’ll find a .babelrc file in your project root directory already)

Install babel-preset-env to use for environment dependent compilation

> npm i -D babel-preset-env

In order to enable the preset you have to define it in your .babelrc file, like this:

{"presets": ["env"]}

NOTE: If we add this into our _package.json > “scripts”_, then the _.babelrc_ file is not needed anymore.

"scripts": {"babel": {"presets": ["env"]}}

Include rule into the config file module

module: {rules: [{test: /\.js$/,include: /src/,exclude: /node_modules/,use: {loader: "babel-loader",options: {presets: ['env']}}}]}

From our loader section we know that:test : to let the loader know which file format it’s going to work oninclude : to let the loader know which directory it should work intoexclude : to let the loader know which directory should it avoid while parsinguse : to let the loader know which specific loader it’s using with use.loader and what’s it’s configuration options with use.options


Webpack config file basic setup — 4

Configuring .babelrc file

7.3. html-loader (LOADER) & html-webpack-plugin (PLUGIN)

Since we want to edit our index.html in src directory and want to see the changes in the output dist folder, we need to create and update index.html into dist every time webpack compile our project. Well, we should remove that painful job!

We need to use a loader and a plugin together to solve our problem. Because -html-loader : Exports HTML as string. HTML is minimized when the compiler demands.html-webpack-plugin : Simplifies creation of HTML files to serve your webpack bundles.

Install dependencies

> npm i -D html-loader html-webpack-plugin

Configuring html-loader

{ test: /\.html$/, use: ['html-loader']

Importing html-webpack-plugin

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

Using our plugin

plugins: [new HtmlWebpackPlugin({template: 'index.html'})]

Webpack config file basic setup — 5

Now, we’ve setup every thing. In your src/index.html write something and then run some build commandsnpm run dev : You’ll see our app now works and you can see the html element in the browser. The bundled js file has been injected into the html before the end of body tagnpm run build:prod : Watch yourself the process of building the output index.html and the changes applied in the dist/index.html

Resources:html-loader : webpack-doc , github-dochtml-webpack-plugin : webpack-doc , github-doc

7.4. css-loader (LOADER), style-loader (LOADER), sass-loader (LOADER), extract-text-webpack-plugin (PLUGIN)

Using CSS and SASS with webpack may look like some extra headaches with some extra steps. Webpack compiles css and pushes the code into the bundled js. But we need to extract it from the bundle, and then create a identical .css file, and then push it into our dist/index.html and then add the css to DOM. A lot of work, right? Not literally..

I’ve combined 3 loaders and 1 plugin to see them work together for our required output:style-loader : Adds CSS to the DOM by injecting a <style> tagcss-loader : Interprets [@]( "Twitter profile for @import")[i]( "Twitter profile for @import")[mport]( "Twitter profile for @import") and url() like import/require() and will resolve them (stay on the article, don’t go to twitter’s “@ import”. medium’s mistake, not mine 😒)sass-loader : Loads a SASS/SCSS file and compiles it to CSSnode-sass : Provides binding for Node.js to LibSass. The sass-loader requires node-sass and webpack as peerDependency. Thus you are able to control the versions accurately.extract-text-webpack-plugin : Extract text from a bundle, or bundles, into a separate file

Now install the dependencies

> npm i -D sass-loader node-sass css-loader style-loader extract-text-webpack-plugin

We need to import our app.scss into our app.js to work to let webpack know about dependencies. So in our app.js we’re going to write:

import './assets/scss/app.scss';

Additionally to check that our sass modules work fine, add one more .scss file in our src/assets/scss directory via terminal

> touch src/assets/scss/_colors.scss

Import the newly created _color.scss file into app.scss and add some styling with:

@import '_colors';body {background: $bgcolor;}

And define $bgcolor into _color.scss file:

$bgcolor : #e2e2e2;

Import extract-text-webpack-plugin into config file

const ExtractTextPlugin = require('extract-text-webpack-plugin');

We need to import webpack itself into our webpack.config.js to use the webpack’s built-in plugins into our project

const webpack = require('webpack');

Now our workflow splits into two ways for two type of requirements.(1) We want to have just a single .css file into our output(2) We want more than one .css files as output

For a single stylesheet (we’re working on this):First, we need to create an instance of ExtractTextPlugin into which we’ll define our output filename:

const extractPlugin = new ExtractTextPlugin({filename: './assets/css/app.css'});

Secondly, while configuring our css/sass loaders we need to use the previously created instance with it’s extract() method (i.e. extractPlugin.extract()) and inside the method we pass the required loaders as an argument and in a form of an object

So our configuration of these loaders is going to be:

{test: /\.scss$/,include: [path.resolve(__dirname, 'src', 'assets', 'scss')],use: extractPlugin.extract({use: ['css-loader', 'sass-loader'],fallback: 'style-loader'})}

And now add the instance of ExtractTextPlugin (which is extractPlugin) into the plugins section:

plugins: [extractPlugin]

NOTE: If you are not using any _html-loader_ then, include a index.html file in the dist folder and link the output stylesheet and js urls into that file like:

<link rel="stylesheet" href="./assets/app.css"><script src="./assets/main.bundle.js"></script>

For multiple stylesheets (just for giving you example):

If you’re following the previous direction for creating a single extracted stylesheet, then there’s nothing new for creating multiple stylesheets.

Just create as much instances of ExtractTextPlugin as you want your stylesheets to have. We’re creating here two instances, one for just css and one for sass compiled

const extractCSS = new ExtractTextPlugin('./assets/css/[name]-one.css');const extractSASS = new ExtractTextPlugin('./assets/css/[name]-two.css');

NOTE: _ExtractTextPlugin_ generates a file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.

Now our loaders configuration looks like:

{ test: /\.css$/, use: extractCSS.extract([ 'css-loader', 'style-loader' ]) },{ test: /\.scss$/, use: extractSASS.extract([ 'css-loader', 'sass-loader' ], fallback: 'style-loader') }

Now add the instances into the plugins:

plugins: [extractCSS,extractSASS]

Now run the npm run dev to see it action in your browser.

If you’re working for single stylesheet like mine, you should see that the background changes to #e2e2e2 😂

If you see the view-source from the output app, you can see the stylesheet injected into the head of our html and app.bundle.js file injected to before the end of the body tag

Now What?? Well, we need to debug things from our browser, right? We just need a source map to see the actual line number from the source code rather than being lost into the minified stylesheets!

In the options property for loader, you can switch ON the source map with sourceMap: true

{test: /\.scss$/,include: [path.resolve(__dirname, 'src', 'assets', 'scss')],use: extractPlugin.extract({use: [{loader: 'css-loader',options: {sourceMap: true}},{loader: 'sass-loader',options: {sourceMap: true}}],fallback: 'style-loader'})}

Check your styling changes and inspect it in your browser with inspect element. You’ll find the actual line number showing where you made your changes!

Here’s my configuration:

Webpack config file basic setup — 6

References:extract-text-webpack-plugin : webpack , githubcss-loader : webpack , githubsass-loader : webpack , githubstyle-loader : webpack , github

7.5. file-loader (LOADER)

Well, we’ve setup configuration for every thing except static files like images, fonts. Now, we’re going to setup for static files with very useful loader file-loader

Install file-loader

> npm i -D file-loader

Configuring file-loader

{test: /\.(jpg|png|gif|svg)$/,use: [{loader: 'file-loader',options: {name: '[name].[ext]',outputPath: './assets/media/',publicPath: './assets/media/'}}]}

NOTE: BE VERY VERY CAREFUL ABOUT _outputPath_ and _publicPath_ in the file-loader configuration. You need to add a ‘/’ at the end of the _outputPath_, so that it will get the directory address rather than concatenating the specified string with the file name. VERY CAREFUL! And we don’t need to add _publicPath_(I guess), since we’ve already defined it in our output path

//file-loader(for images){test: /\.(jpg|png|gif|svg)$/,use: [{loader: 'file-loader',options: {name: '[name].[ext]',outputPath: './assets/media/'}}]},

//file-loader(for fonts){test: /\.(woff|woff2|eot|ttf|otf)$/,use: ['file-loader']}

With the loader configured and fonts in place, you can import them via an [@font]( "Twitter profile for @font")-face declaration. The local url(…) directive will be picked up by webpack just as it was with the image

Adding font-face to stylesheet

@font-face {font-family: 'MyFont';src: url('./my-font.woff2') format('woff2'),url('./my-font.woff') format('woff');font-weight: 600;font-style: normal;}

Now add a sample image in your src/assets/media directory and create an img element into your src/index.html to see it works

Webpack config file basic setup — 7

Run npm run dev and npm run build:prod to see everything’s working fine and clear.

That’s it! Now you should find everything in place and working just fine. :)

We have come to the end of this guide, that’s not everything about webpack though. But it’s the starting point that you have to understand deeply and correctly to get the the working procedure of webpack philosophy. In the upcoming blogs, I’ll try to simplify the actual powers/features of webpack like - Hot Module Replacement, Tree-shaking, Output management for development and production environment, Code splitting, Lazy loading and other stuffs.

And I highly recommend to follow this awesome article rajaraodv wrote to save our lives :

Since I promised you to give you the simplest cheat-sheet for you. Here it is:

You can simply clone this repo in your project root to get everything in place or follow the next steps to setup your project in just 5 minutes

Don’t hesitate to fork on this repo. I’d love to see others contributing on this boilerplate to make this configuration more robust and usable for everyone who has suffered a lot like me..


1. Run these commands one after another in the terminal to create project folders and install all dependencies

> mkdir project_name && cd project_name> npm init> mkdir src dist src/assets src/assets/media src/assets/js src/assets/scss> touch webpack.config.js .babelrc src/index.html src/app.js src/assets/scss/app.scss> npm i -D webpack> npm i -D webpack-dev-server clean-webpack-plugin babel-loader babel-core babel-preset-env html-loader html-webpack-plugin sass-loader node-sass css-loader style-loader extract-text-webpack-plugin file-loader

2. Add this snippet into .babelrc

{"presets": ["env"]}

3. Configure package.json > scripts with this snippet

"scripts": {"build": "./node_modules/.bin/webpack","build:prod": "./node_modules/.bin/webpack -p","watch": "./node_modules/.bin/webpack --watch","dev": "./node_modules/.bin/webpack-dev-server"}

4. Import app.scss into your app.js

import './assets/scss/app.scss';

5. Populate your src/index.html (with an image too) and src/assets/scss/app.scss and add the image into src/assets/media

6. Copy and paste this configuration file into your webpack.config.js (make sure that project folders hierarchy to be same)

Webpack Quickstarter Template — Final

7. Run npm scripts to see your application in action in browser and in production format. Don’t forget to inspect element in the browser console to make sure everything’s working great without any error.

🎉🎉🎉🎉 End of this long exhaustive guide 🎉🎉🎉🎉

If you find something that’s not right in this guide, mention it into the comment section. I’d love to get your feedback on this write up.

If you like it, give some 👏 💓 and share it on medium and twitter.

Thank You for your patience 🙇