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.
Last year I was perfectly happy with the build pipeline I had put together 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:
npm install --save-dev webpack
I create webpack.config.js at the project root:
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:
{
"scripts": {
"build": "webpack",
"watch": "webpack --watch"
}
}
Writing modular JavaScript
I can now organize JavaScript into modules:
// 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();
}
};
// 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:
npm install --save-dev css-loader style-loader
// Adding a loader inside webpack.config.js
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
}
// 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:
npm install --save-dev webpack-dev-server
{
"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.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.