An Introduction to Webpack

Diana

Diana

Software Engineer at Softvision
Diana is a Software Engineer at Softvision and is a part of the Web Community. She has been working as a Front-End Developer for the past three years focusing on both React JS and Angular JS. She is always looking for challenges and is interested in the latest technologies and trends in web development.
Diana

Latest posts by Diana

Webpack is a module bundler that allows us to organize our code, make it modular, therefore creating more maintainable applications. It has become one of the most popular tools for modern web development.

Using task runners and other tools, we had the ability to compile all the modules into a single source before. But webpack allows us to import a lot of other assets as modules beside JS, including CSS, HTML, images and fonts. It also adds the ability to easily use packages from npm.

How does it work?

Webpack basically takes modules with dependencies and generates static assets.

Webpack processes our application and builds a dependency graph recursively. This graph includes every module needed by our app. The modules are packaged into a small number of bundles – often only one – to be loaded by the browser.

Webpack can be configured by creating a JS file ‘webpack.config.js’ with configuration options which will be passed in webpack start command.

Why webpack?

If you ever encountered some of the following:

  • loading dependencies out of order,
  • including unused code in production,
  • loading the same library twice, scoping issues in JS or CSS,
  • needing to optimize packages and assets loading but fearing you will break something

…then you could probably benefit from using webpack. It handles all the above and you can stop worrying about dependencies and load order.

General Concepts

Entry

The starting point of the dependency graph built by webpack is known as an entry point. It tells webpack where to start and follows the imports to know what to include in the bundle. You can also think of the entry as the application root file or the first file to kick off your app.

The entry point is defined using webpack’s entry property in our webpack configuration object. You can define many entries and they will generate as many final bundles to use in different parts of your application.

For example, if we can have a web app with a client side and an admin side, we do not need all the dependencies used for the client side on the admin side as well. We can add two entries in the webpack configuration file and it will generate two separate bundles.

Output

After all the needed modules are bundled together, we still need to tell webpack where to emit them. For this, we use the webpack output property that sets the location for the new bundles.  

The output.filename and output.path properties are used to specify the name of our bundle and the location where we want it to be emitted. In our example, using [name].js as filename, the 2 output bundles will have the same names as the entries: ‘client.js’ and ‘admin.js’.

Loaders

webpack can natively load only JavaScript. But, using loaders, many other resources can be transformed into JS modules. Loaders are published and installed via npm.

Loaders can be chained, so we can have many loaders that are applied in a pipeline to the resources. Each loader processes the resource and returns it in arbitrary format, which is passed to the next loader. The final loader is expected to return JavaScript.                                                                                               

Loaders are processed in reverse array order, meaning that in our example css-loader will run before style-loader.

Below are some popular loaders classified by purpose:

  • Transpiling:

ts-loader or awesome-typescript-loader loads TypeScript as JS

babel-loaderloads ES2015+ code and transpiles it to ES5 using Babel

  • Files and Templating:

html-loader exports HTML as string and require to static resources

file-loader emits the file into the output folder and returns its corresponding URL

  • Style:

style-loader –  adds CSS to DOM by inserting a <style> tag

css-loader resolves CSS imports and returns CSS code

less-loader loads and compiles LESS files

sass-loader loads and compiles SASS/SCSS files

postcss-loader loads and transforms CSS using PostCSS

  • Linting and Testing:

mocha-loader loads tests that use mocha

eslint-loader preLoader using ESLint

jshint-loader preLoader using JSHint

Webpack provides 3 stages for running loaders: preLoaders, loaders and postLoaders, executed in this order. Code linting needs to be done before the file is processed and added to the bundle, so in this case we use preLoaders.

Plugins

The purpose of plugins is to do everything else that a loader cannot do. An interesting fact is that webpack is built on the same plugin system that you are using in your webpack configuration.

A very useful and popular plugin is ExtractTextPlugin, a plugin that extracts text from a bundle into a different file. It can be used for separating CSS from JS. As webpack builds the dependency graph, this plugin moves all the required *.css modules into a separate file. The benefit is that your styles are no longer inline into the JS bundle but in a separate CSS file. So, a complex application, with a lot of style modules will be faster using ExtractTextPlugin because the CSS bundle will be loaded in parallel to the JS bundle.

Plugins can be installed using npm. Below, you can find a webpack configuration example using ExtractTextPlugin to create a CSS bundle named ‘style.css’.

The plugin is required, instantiated in the plugins array and used in module.rules. You can specify the output file name, the loaders and fallback loaders to use and some other useful options.

Getting started with webpack

First we need to install webpack. From our project folder, we can open a terminal window and run the following npm command to install and save webpack in our local project packages:

npm install -–save-dev webpack      

webpack is started using:

npm run webpack

Then we will create a ‘webpack.config.js’ file in our project directory containing a basic webpack configuration like the example below.

With the above configuration, webpack will look for entry file names, in our case ‘app.js’. It will read the content and process every import or require dependency found, adding it to the bundle. It keeps doing so until the dependency graph is complete. In this way, webpack will only add to the bundle what is needed, leaving the unused resources aside.

Once the bundle is complete, webpack names the bundle using output.filename and adds it in the output.path folder. In our case, [name] is replaced with entry file name, resulting ‘app.bundle.js’.

resolve.extensions contains all the extensions that need to be processed by webpack. In this case, files other than *.css or *.js will be ignored.

webpack-dev-server

Webpack-dev-server is an easy to setup development server with live reload. We start by installing dev server with npm:

npm install –save-dev webpack-dev-server

After install, you can start dev server with:

npm webpack-dev-server –open

The simplest way to configure your server is by adding devServer with a set of options into ‘webpack.config.js’

The example above will compress and serve everything from “dist” directory at http://localhost:9000/.

Below you can find a list with some other useful configuration options:

–headers: adds headers to responses.

–host: used host, by default this is localhost.

–proxy: enable proxying URLs, uses http-proxy-middleware package that is highly configurable.

–hot: adds the HotModuleReplacementPlugin to switch the server to hot mode.

–lazy: no watching, compiles on request (cannot be combined with –hot).

–https: serves webpack-dev-server over HTTPS Protocol. Includes a self-signed certificate that is used when serving the requests.

–publicPath: the bundled files will be available in the browser under this path.

–watchContentBase: this tells the server to watch the files served in contentBase; in case of file change, it triggers full page reload

–watchOptions: specifies options related to watch content base

Hot Module Replacement

A development server with live reloading can be achieved using other tools too, but what is really interesting and powerful in webpack is the possibility to include Hot Module Replacement (HMR).

HMR replaces, changes, adds or removes modules while an application is running, without doing a full page reload. This is very useful because:

  • the application keeps its state, which would be lost in a full reload
  • we can save development time because code changes are applied immediately
  • it works with CSS also, so it becomes fast to do style fixes directly in source files instead of browser debugger console
  • HMR can be easily integrated with React to allow you to change components’ code without losing the states and properties
  • HMR can also be used with Angular and it enables module reloading for templates, controller methods and services

HMR – how does it work?

Hot module replacement runtime executes a series of steps in order to swap modules in and out of the running application:

  • The application asks HMR to check for updates
  • HMR downloads the updates asynchronously and notifies the application
  • The application asks HMR to apply the changes
  • HMR applies the updates synchronously

Below is an example on how to enable HMR using HotModuleReplacementPlugin and setting devServer.hot option to true.

Useful links

Read more on this subject by following the links below:

  • webpack official documentation

https://webpack.js.org/

  • Getting started with webpack 2

https://blog.madewithenvy.com/getting-started-with-webpack-2-ed2b86c68783

  • webpack – tips and tricks

https://github.com/rstacruz/webpack-tricks

https://medium.com/webpack/tips-and-tricks/home

Share This Article


Diana

Diana

Software Engineer at Softvision
Diana is a Software Engineer at Softvision and is a part of the Web Community. She has been working as a Front-End Developer for the past three years focusing on both React JS and Angular JS. She is always looking for challenges and is interested in the latest technologies and trends in web development.
Diana

Latest posts by Diana