HomeNewsMoving from Gulp to Webpack – Stratajet Tech – Medium

Moving from Gulp to Webpack – Stratajet Tech – Medium

medium bookmark / Raindrop.io |

1*edAfkVSJWOhdR0bXtvFHpw.jpeg<img class=”progressiveMedia-noscript js-progressiveMedia-inner” src=”https://cdn-images-1.medium.com/max/1600/1*edAfkVSJWOhdR0bXtvFHpw.jpeg”>

I’ve been avoiding learning Webpack for a while now as I never thought I needed to learn another build tool, Gulp does everything I’d ever need from a build tool now or in the future. However, ever since we’ve moved from AngularJS to Angular (or Angular 2+) as well as introducing standards such as; TypeScript instead of Javascript and a Jasmine /Karma combo for UI testing, but also Webpack as an initial build tool. I’ve avoided it for long enough and now, in September 2017, I thought it’s time to finally move on from my old friend Gulp.

If you’re interested, I’ve written this same post with syntax highlighting here.

Good Old Gulpfile

If you’ve never heard of Gulp before, this isn’t the post to learn, there are plenty of good tutorials out there a Google search away. Then again, you don’t really need to know Gulp to understand what’s going on so feel free to continue reading nevertheless.

Here’s what my old Gulpfile looks like. I’ve decided against putting it all into this post as it’s quite long. It essentially does 5 things;
– Starts a webserver
– Preprocesses `scss` to `css`
– Merges and compresses js files
– Moves and minifies html files
– And compresses images

It’s a pretty standard set of tasks for creating a basic static site. Although it’s pretty unlikely that someone will go through the effort of applying webpack to a simple site, I will go through how to do all of this in said build tool as a kind of beginners guide to webpack, or a designers guide, however, you see fit. I wouldn’t advise running this, a lot of the plugins are very old and not only will you get a bunch of messages asking you to upgrade them, the file probably wouldn’t work 😞.

Same post, with syntax highlighting here

1. Create blank folders

Let’s start from a blank slate here. Create six new folders in the hierarchy specified below.

gulp-to-webpack
├── src
│ ├── app
│ ├── assets
| │ ├── img
| │ ├── styles

I found out after writing this that the `app` folder is pretty pointless but it’s not that big of a deal.

Create a file called `index.html` in the `src` folder with the following code;

<!-- gulp-to-webpack/src/index.html -->
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8">
<title>Test Document</title>
</head>
<body>
<h1>Test Doc</h1>
</body>
</html>

Create a file called `app.js` in the `app` file and add some simple code like;

 // gulp-to-webpack/src/app/app.js
document.write(“It works.”);

2. Run Webpack dev Server

I remember listening to ShopTalk show a while ago and one of the hosts(Dave Rupert) joked it took around a day to set webpack up. Luckily nowadays it doesn’t take that long and you should have it up and running in just a few minutes.

Open up a terminal/command prompt, cd into the `gulp-to-webpack` directory and run;

$ npm init -y

The `-y` answers yes to all the questions npm asks during setup. This creates a `package.json` file in the root directory.

Now install `webpack` and `webpack-dev-server`;

$ npm i — save-dev webpack webpack-dev-server

`webpack-dev-server` is similar to `gulp-webserver` in the sense that it creates a server to test on. It has a bunch of other advantages.

Open the package.json file and if it’s not there already, add a new line in the scripts section to run the `webpack-dev-server`;

“scripts”: {
“test”: “echo \”Error: no test specified\” && exit 1",
“start”: “webpack-dev-server”,
},

This will allow us to start the server by typing `npm start` in the terminal, or `yarn start` if you have Yarn installed.

Create a file in the root directory called `webpack.config.js` and open it up. There are four main things a webpack config file should have; entry, output, module and plugins.
Entry is the main JS file that webpack will use.
Output is where what it will output all the content to.
Module all the rules that will be applied to your files.
Plugins where all the plugins get loaded.

In our case we’ll just need Entry and Output from the four.

const path = require(‘path’);
module.exports = {
entry: ‘./src/app/app.js’,
output: {
path: path.resolve(__dirname, ‘dist’),
filename: ‘bundle.js’
}
};

Okay I’ll go through things line-by-line.
1. `const path = require(‘path’);` We add a constant variable called *path* which comes default with Node.js. This is used to specify the the root folder in line 6.
2. blank
3. `module.exports = {` Is the way to export modules in Node.js so it can be used by other files. I’m not sure exaclty why webpack needs an export but I guess that’s what makes it so magical.
4. `entry: ‘./src/app/app.js’,` Our main js file. Most files in webpack go through this file so as you’ll see later on, our css and any other js will need to be imported here.
5. `output: {` Creates the output object.
6. `path: path.resolve(__dirname, ‘dist’),` The path we want our used assets and code to be go to. We use the path import from line 1 for `path.resolve` the we refer to the root directory with `__dirname` and we export our processed code to a file called `dist`.
7. `filename: ‘bundle.js’` The filename to export all the bundled JS to.

Okay, one more thing before we’re good to go. Let’s tell the dev server were our directory containing the `index.html` file is. Add this code to the bottom of the file above the last closing bracket `};`.

// gulp-to-webpack/webpack.config.js
devServer: {
contentBase: ‘./src’
}

Okay now run;

$ npm start

If everything went well, navigating to http://localhost:8080/ in your browser should show you this.

1*x0SObI3qzx1rdVrB6cYoVg.png<img class=”progressiveMedia-noscript js-progressiveMedia-inner” src=”https://cdn-images-1.medium.com/max/1600/1*x0SObI3qzx1rdVrB6cYoVg.png”>

3. Adding some CSS

First let’s create a CSS file. Make a new file in your `assets > styles` folder called `styles.css` and add the following code;

/* gulp-to-webpack/src/assets/styles/styles.css */
:root {
— grey: #ccc;
}
body {
background-color: var( — grey);
font-family: sans-serif;
font-size: 14px;
}
h1 {
font-size: 10em;
}

Now let’s import the css to our `app.js` file, add this line right to the top.

// gulp-to-webpack/src/app/app.js
import ‘../assets/styles/style.css’;

So there are several ways this can be done;
– Inlining css from your .css file to the head of your document using style-loader
– Or doing it the old fashioned way, using a <link> tag in the head using extract-text-webpack-plugin

I will run through both, but the latter takes a bit longer than the former.

a. Loading CSS with style-loader

Install both style-loader and css-loader

$ npm i — save-dev style-loader css-loader

Open up your webpack.config.js and create a module object with a rules array just below your output objct.

 // gulp-to-webpack/webpack.config.js
entry: ‘./src/app/app.js’,
output: {
path: path.resolve(__dirname, ‘dist’),
filename: ‘bundle.js’
},
module: {
rules: [
]
}

Luckily the github pages on most of the webpack plugins and loaders have good examples in their documentation so it’s simple to add a bunch in. I’ll simplify their example a bit.

 // gulp-to-webpack/webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: [‘style-loader’, ‘css-loader’]
}
]
}

And that’s it. It’s important to make suer you’re using arrays [] where they should be instead of objects {} I’ve made that mistake a few times before.

Webpack is esentially finding all the files in your code that end with `.css`, then executing actions from right to left on the next line. So in our case `[‘style-loader’, ‘css-loader’]` css-loader gets the css first, then style loader places it in the head of our code.

Run `npm start` to see it in action.

1*bobOpkJuW47x_tPTwVxS5w.png<img class=”progressiveMedia-noscript js-progressiveMedia-inner” src=”https://cdn-images-1.medium.com/max/1600/1*bobOpkJuW47x_tPTwVxS5w.png”>

b. Loading CSS with extract-text-webpack-plugin

So if you’ve followed the steps in part a please comment out or delete that code in the `webpack.config.js` file. We’ll keep the ‘css-loader’ as we’ll need that for this method as well, go ahead and install `extract-text-webpack-plugin`.

$ npm i — save-dev extract-text-webpack-plugin

Now in the `webpack.config.js` add the following code below your `const path` line;

 // gulp-to-webpack/webpack.config.js
const ExtractTextPlugin = require(‘extract-text-webpack-plugin’);

Now create a new rule, again for css but written like so;

 // gulp-to-webpack/webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [‘css-loader’]
})
}
]
}

Here it’s extracting all the code from files that end in .css using the css-loader. Now we need to tell it where to put all the code. Add a new plugins array above the devServer object, and below the module object.

plugins: [
new ExtractTextPlugin(‘style.css’),
],

Here we’re exporting all our code to a file named ‘style.css’. Once again, run `npm start` to see the changes.

c. Loading and minifying Scss

It’s pretty simple from this point to export sass. Let’s change our `style.css` to `style.scss`, remove all the code in the file and replace it with this;

 // gulp-to-webpack/src/assets/styles/style.scss
$grey: #ccc;
body {
background-color: $grey;
}
h1 {
font-size: 5em;
}

Now update the style import in `app.js` and install `sass-loader`.

$ npm i — save-dev sass-loader

Let’s add a new rule to our `webpack.config.js` file;

// gulp-to-webpack/webpack.config.js
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['css-loader']
})
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: ['css-loader', 'sass-loader']
})
}
]

Pretty simple right? Now let’s ammend that rule to minimise our css.

// gulp-to-webpack/webpack.config.js
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
minimize: true
}
},
'sass-loader'
]
})

As you can see, we’ve applied the minimisation option to the `css-loader`, to it is possible to minimise the code from section 3.a and b in this exact same way.

4. Merges and compress JS files

This is possibly the simplest thing we can do, all it requires is the addition of a plugin, and webpack does the rest.

Let’s install the uglifyjs-webpack-plugin.

$ npm i — save-dev uglifyjs-webpack-plugin

Add it to the top of our `webpack.config.js` file, below the ExtractTextPlugin.

 // gulp-to-webpack/webpack.config.js
const UglifyJSPlugin = require(‘uglifyjs-webpack-plugin’);

And let’s scroll down to our plugins array and stick it in there too.

// gulp-to-webpack/webpack.config.js
plugins: [
new UglifyJSPlugin(),
new ExtractTextPlugin('style.css')
],

And that’s it. As any js you use will have to be imported through the `app.js` file it’ll compress right at the end.

5. Move and minifies HTML

I’ll have to admit, I haven’t yet tried this wth more than one Html file, but it shouldn’t be too hard to figure out if that’s a road you want to go down.

Again, it’s another plugin install, just in case you hadn’t figured it out. Let’s install the html-webpack-plugin.

$ npm i — save-dev html-webpack-plugin

Then the usual process for a plugin so a const at the top of the `webpack.config.js` file.

 // gulp-to-webpack/webpack.config.js
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

Now let’s add some options for it. Below all the constants let’s add a new object variable.

// gulp-to-webpack/webpack.config.js
let htmlOptions = {
template: 'src/index.html',
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true
}
};

The options should be pretty self explanatory so I won’t run through them, but there are a full list of minification options available on the HTML Minifier github page which you can look at if you would like more information.

As for the moving of Html files or files in general that happens in memory each time you run the webpack server so you probably haven’t noticed a physical file yet. That can be easily rectified. Let’s add a new script command to the `package.json` file just below ‘start’, add;

 “build”: “webpack”,

So now running `npm run build` will build a `dist` folder in your root directory with all your compiled code.

a. Remove dist folder on new build

This is optional but let’s say it provides, piece of mind. Whenever the `build` command is run you’ll notice the `dist` folder stays there, there’s no way of knowing if the files in it have been updated or not without manually checking it. One way to solve this is to delete the folder at the start of a build and replace it with the newly created file. That can be done with the clean-webpack-plugin.

The usually steps of installing the plugin and placing it at the opt of the `webpack.config.js` file apply here. However in the plugins array we’ll need to place the file we want to remove on build like so.

 // gulp-to-webpack/webpack.config.js
new CleanWebpackPlugin([‘dist’])

And that’s it, another simple plugin added. Now run a `build` and observe.

6. Compressing Images

Phew, we’ve got to the final point of this post, if you’ve gone through everything up to this point you’ve done incredibly well.

Compressing images will involve the installation of two loaders, file-loader and image-webpack-loader.

$ npm i — save-dev file-loader image-webpack-loader

Now let’s add a new rule to the `webpack.config.js` file;

// gulp-to-webpack/webpack.config.js
{
test: /\.(jpg|png|gif|svg)$/,
use: [ 'file-loader', 'image-webpack-loader']
}

And the final step is to include an image tag in our Html. Open up the `index.html` file and add the following code below the h1 tag.

 <h2>Extra Text</h2>
<img src=<%=require(“./assets/img/webpack.jpg”)%> />

As you can see instead of requiring the image file at the top of the `app.js` file like the css we’ve required it in a specific location in the html so webpack know where to place the image in markup once it’s done with it’s compression. Now let’s download an image and save it in the `assets > img` folder. Say this one save it as `webpack.jpg` and place it in the relevant folder.

Now if you run the dev server and view the source, you’ll notice the image isn’t called ‘webpack’ but instead has a random alphanumeric string. That’s because ‘file-loader’ by default will hash assets. To change that we’ll have to add some options;

// gulp-to-webpack/webpack.config.js
{
test: /\.(jpeg|png|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
}, 'image-webpack-loader'
]
}

So now well use the actual name of the file, then it’s extension. Run the dev server and you’ll see that the naming is as it should be.

And that’s it. Everyhting my gulp file could do, re-written in webpack. I hope this has been a helpful introduciton to those who have been wanting to move away from Gulp/Grunt and try webpack. The syntax is very different but once you get used to it, it makes sense. From this point onwards you can include a bunch of other loaders and plugins all with the same techniques listed above, and even go as far as having seperate `webpack.config.js` files for production, development, and tesitng. The possibilities are endless.

Featured articles on Prototypr: