# Migrating to Webpack: From Gulp to module bundling

> Why I abandoned the build pipeline I built with Gulp, and what I gained — and struggled with — when switching to Webpack.

- Published: 2016-06-05
- Category: Tools & Technologies
- Tags: JavaScript, Webpack
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/migrating-to-webpack-from-gulp-to-module-bundling/
- Language: en-US
- Author: Muhammet Şafak

---
[Last year I was perfectly happy with the build pipeline I had put together with Gulp](/en/blog/building-a-front-end-build-pipeline-with-gulp/). Sass compilation, JavaScript concatenation, minification, automatic browser reloading — everything in one place. Why change anything?

Then I started using `require()` on a project. Writing JavaScript in modules had become necessary to keep a growing codebase organized. I tried `browserify` to solve this with Gulp, and spent time wrestling with plugins to make them play nicely together. When I finally took a proper look at Webpack, I realized it already had exactly what I was looking for.

## What is the difference between Gulp and Webpack?

**Gulp** is a task runner. You define a flow: "take these files, apply these transforms, write them here." It operates on the filesystem.

**Webpack** is a module bundler. It tracks your application's dependency graph — "this file requires that one, which requires another" — and collects all dependencies into one (or a few) output files.

Both seem to "compile" things, but they solve different problems. Webpack genuinely solves the module dependency problem; Gulp could only patch it together, awkwardly, with plugins.

## Basic configuration

Installing Webpack via npm is all it takes:

```bash
npm install --save-dev webpack
```

I create `webpack.config.js` at the project root:

```javascript
var path = require('path');

module.exports = {
    entry: './src/js/app.js',

    output: {
        path: path.resolve(__dirname, 'public/js'),
        filename: 'bundle.js'
    },

    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                    presets: ['es2015']
                }
            }
        ]
    }
};
```

The `entry` point is where the application starts; Webpack traces the entire dependency tree from there. `output` specifies where the compiled file should be written.

Then I add the `npm run build` command to `package.json`:

```json
{
    "scripts": {
        "build": "webpack",
        "watch": "webpack --watch"
    }
}
```

## Writing modular JavaScript

I can now organize JavaScript into modules:

```javascript
// src/js/utils/format.js
module.exports = {
    para: function (miktar) {
        return miktar.toFixed(2) + ' TL';
    },
    tarih: function (timestamp) {
        var d = new Date(timestamp);
        return d.getDate() + '.' + (d.getMonth() + 1) + '.' + d.getFullYear();
    }
};
```

```javascript
// src/js/app.js
var format = require('./utils/format');

document.querySelectorAll('.fiyat').forEach(function (el) {
    el.textContent = format.para(parseFloat(el.dataset.miktar));
});
```

Webpack merges these two files into `bundle.js`. The browser downloads a single file; I can split the code however I like.

Before this, everything was tied to global variables and I had to carefully order `<script>` tags in the template because sequence mattered. If one library loaded before another, things broke. With Webpack, dependencies are baked into the code itself — I no longer think about load order.

## Managing CSS and images with Webpack

One interesting thing about Webpack is that it can handle non-JavaScript assets too. By installing the CSS loader, you can import stylesheets as modules:

```bash
npm install --save-dev css-loader style-loader
```

```javascript
// Adding a loader inside webpack.config.js
{
    test: /\.css$/,
    loaders: ['style-loader', 'css-loader']
}
```

```javascript
// You can require CSS directly in app.js
require('./styles/main.css');
```

Whether to use this feature is debatable — some people find managing CSS through JavaScript strange. For now I'm only using Webpack for JavaScript modules and keeping CSS separate.

## Development server

`webpack-dev-server` brings automatic reloading similar to BrowserSync in Gulp:

```bash
npm install --save-dev webpack-dev-server
```

```json
{
    "scripts": {
        "dev": "webpack-dev-server --inline --hot"
    }
}
```

The `--hot` flag updates only the changed module without a full page reload — this is called Hot Module Replacement (HMR). I haven't used it enough to fully grasp it yet, but I imagine it could be a huge speedup on larger projects.

## The initial hurdle

To be honest, Webpack's config file can feel overwhelming the first time you encounter it. In Gulp, every task read top-to-bottom in a straightforward sequence; in Webpack, loaders, resolve rules, the plugins array — holding all of that in your head at once is hard in the early days. I spent two days just reading the docs to understand the configuration.

The most practical way through this is to grab an existing `webpack.config.js` example and make small changes from there. Learning by understanding a working setup rather than writing from scratch was much faster.

## Have I dropped Gulp entirely?

No, not yet. Webpack is great for JavaScript modules, but I still use Gulp for some tasks: Sass compilation, image optimization, watching PHP files and triggering browser reloads. The two tools don't conflict; you can use them together.

On new projects I set up Webpack directly for JavaScript; there's less and less reason to reach for Gulp from scratch. Especially for any JavaScript project with module dependencies, Webpack feels like the right choice over Gulp.

The config file feels a bit complex at first — I'll admit that. But once it clicks, the comfort of writing modular JavaScript more than pays back that initial cost.
