Using loaders with webpack

VAMSI DEEPAK AMPOLU
4 min readApr 21, 2016

--

The objective of this post is help you understand more about loaders in webpack. If you have never used webpack before, this will help you get started.

Loaders are like build steps in grunt or gulp.They are special modules that perform transformations on your source code before webpack can start processing them.

To put it simply, a loader can help you load modules in a different format such as Coffeescript, ES6 or CSS. It can help you shim modules that use globals.

Loaders can be specified within the require statement loading the file. This is known as inline configuration. This is useful if a loader needs to be used in a few particular cases, if not it is advisable to specify loaders within the webpack configuration file instead.

Inline configuration example:

require(‘imports?angular=angular&$=jquery&moment=moment!angular-daterangepicker/js/angular-daterangepicker’);

You can specify the configuration within the webpack.config.js file like this:

The `module` can have three attributes, loaders, preLoaders and postLoaders. Here we focus only on the loaders.

From here on, when showing you the configuration for a module, I will either start with the module or with the configuration for an individual object within `module.loaders`.

Loaders can be chained together, this means the source of a module can pass through several modules before webpack bundles it.

require(‘style!css!sass!bootstrap.scss’);

It is important to note that chaining occurs from right to left, first the module is processed by the sass loader, followed by the css loader and finally the style loader.

We will look at a few common use cases where loaders can help us:

1. Shimming modules:

You can use the imports-loader and exports-loader loader to shim modules that require or export globals.

Installation

npm install imports-loader exports-loader — save-dev

Inline configuration:

require(‘imports?angular=angular&$=jquery&moment=moment!angular-daterangepicker/js/angular-daterangepicker’);require(exports?Backbone!imports?_=lodash&$=jquery!backbone.js);

Configuration in webpack.config.js:

The imports loader resolves global variables used by the module and the exports loader sets a variable to the value exported by the module.

2. Loading css or sass files:

Installation

npm install style-loader css-loader sass-loader — save-dev

Inline usage:

require(‘style!css!sass!bootstrap.scss’);

Configuration:

Load css files using the css and style loaders, if using a pre-processor, install the appropriate loader and add it to the config.

Another thing that comes up often when loading css framework is the associated icon font, in order to load that use the `url-loader`:

Installation:

npm install url-loader — save-dev

Configuration:

3. Transpiling ES6 or JSX using Babel:

It is rather common for a Javascript developer enjoying life on the bleeding of Javascript to assume that everyone uses babel. Some even go as far as to assume that everyone uses their favourite stage-0 proposals. If you have no clue what I just said, go here and here.

ES2015 is the latest version of Javascript(this statement is already a lie, they just released ES2016) and it contains many important additions to the language such as native Promises, block scoped variables and so on. It has become popular for developers to use these features using a tool known as a transpiler. Babel is a popular transpiler for Javascript that also handles the React JSX syntax.

It is very good to use babel if you use JSX or need to support multiple browsers. However, if you are just building something for fun,you can just use Chrome and Edge browsers, both of which support over 90% of Es2015 features.

Installation:

npm install babel babel-preset-es2015 babel-preset-react babel-loader

I usually also have babel-register and babel-node installed globally so that I can use them when debugging and executing node.js applications.

If you use babel, do not forget the `.babelrc` file. A simple one that I include always looks like this:

{
“presets”:[“es2015”,”react”]
}

Here, we ask the loader to avoid transpiling files in node_modules and the compiled output in build directory by specifying the `exclude` option. Conversely, you can ask it to only include the directories you specified in the `include` option. The query option is the same as the `url parameters` we passed to configure the loader.

Now that I have helped you develop a misconception that webpack loaders can do anything, let me tear it down. It is commonly believed that webpack can either directly load a script from a cdn or use a loader to accomplish the task.
This might be partly because of the wonderful async loader from requirejs:

define([‘async!http://maps.googleapis.com/maps/api/js?v=3.exp&sensor=true'],function(){return window.google.maps;});

However, this is not possible and it is advisable to use an asynchronous loader such as scriptjs. The example below will provide a way for loading the Google Maps API and the Google Client Library:

Installation:

npm install scriptjs — save
npm install expose-loader — save-dev

Usage:

import $script from ‘scriptjs’;require(‘expose?gapiCallback!./google-client-code’);
require(‘expose?gmapsCallback!./google-maps-code’);
$script(‘https://maps.googleapis.com/maps/api/js?onload=window.gapiCallback','google-maps');
$script(‘https://apis.google.com/js/client.js?callback=window.gmapsCallback','google-api');

The expose-loader can expose a variable on the global scope. This must be avoided at all possible costs. Instead, this would be handy:

$script.ready(‘google-maps’,function(){//do something with google maps here});

However, all your code should reside in the callback function. There are modules such as the google-maps-api which take this approach further by returning a promise.

I hope that you are now ready to create a webpack configuration of your own. I suggest that you start small, only use the loaders that you need and iterate the configuration and test as soon as you make a change to avoid pain.

--

--