- 1. Webpack 4 course – part one. Entry, output and ES6 modules
- 2. Webpack 4 course – part two. Using loaders to handle scss, image files and transpile JS
- 3. Webpack 4 course – part three. Working with plugins
- 4. Webpack 4 course – part four. Code splitting with SplitChunksPlugin
- 5. Webpack 4 course – part five. Built-in optimization for production
- 6. Webpack 4 course – part six. Increasing development experience
- 7. Webpack 4 course – part seven. Decreasing the bundle size with tree shaking
- 8. Webpack 4 course – part eight. Dynamic imports with prefetch and preload
Hello! Today we begin a webpack 4 course. We will start with the basic concepts of Webpack, with every part of the course going deeper. This time we will learn the basics of module bundling using ES6 modules. Webpack 4 provide default configuration, which we will go through. Let’s go!
Webpack 4 course begins – but what is Webpack?
Before considering using any kind of tool, you need to ask yourself a very important question. The question is, what problem of yours does the tool solve. Webpack is a module bundler. It means, that its purpose is to merge a group of modules (with their dependencies). The output might be one, or more files. Aside from bundling modules, webpack can do all sorts of things with your files: for example transpile scss to css, or typescript to javascript. It can even compress all of your image files! But why would you want to bundle modules at all?
The purpose of module bundling
Way back in the days, we didn’t have any way of splitting our JavaScript code served for browsers into multiple files other than using many <script> tags. We needed to write a source of every file that we would like to use into the HTML code. It isn’t really convenient. The community came up with some workarounds: CommonJS (implemented into Node.js) and AMD. For an explanation of them, check out an article on the Auth0 blog. Finally, the ES6 came with a brand new import/export syntax.
ES6 modules
With the ES6, the syntax of modules was defined. Thanks to that, we finally got a standard format for modules, built into the JavaScript language specification. It does not mean that it is well implemented in browsers, but it is improving. Even with native support for ES6 modules, you still might want to bundle your modules into fewer files. For the purpose of the course providing all the information that you need to start using Webpack, let’s briefly go through the syntax of ES6 modules.
export
The export statement is used to create JavaScript modules. You can use it to export both objects (including functions) and primitive values. An important thing to notice is that exported modules are in strict mode. There are two types of export: named and default.
Named exports
You can have multiple named exports per module.
lib.js
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export function sum(a, b) { return a + b; } export function substract(a, b) { return a - b; } function divide(a, b) { return a / b; } export { divide }; |
Note that if you would like to export something after its declaration, you need to wrap it in curly brackets (like the divide function in the example above).
Default exports
You can only have one default export per module.
dog.js
1 2 3 4 5 |
export default class Dog { bark() { console.log('bark!'); } } |
import
The import statement is used to import from other modules.
whole module’s content
index.js
1 2 3 4 5 |
import * as lib from './lib.js'; console.log(lib.sum(1,2)); console.log(lib.substract(3,1)); console.log(lib.divide(6,3)); |
You can set any name you want for the imported module. If you are importing whole content from a module, that has a default export, it will be placed into a default property.
index.js
1 2 3 4 |
import * as Dog from './dog.js'; const dog = new Dog.default(); dog.bark(); // 'bark!' |
importing one, or more named exports
index.js
1 2 3 4 5 |
import { sum, substract, divide } from './lib'; console.log(sum(1,2)); console.log(substract(3,1)); console.log(divide(6,3)); |
An important note is that the names of corresponding values must match.
importing a default export
index.js
1 2 3 4 |
import Dog from './dog.js'; const dog = new Dog(); dog.bark(); // 'bark!' |
Note, that the default export can be imported with any name, so we could do something like that:
index.js
1 2 3 4 |
import Cat from './dog.js'; const dog = new Cat(); dog.bark(); // 'bark!' |
The ES6 modules feature also dynamic imports, which we will get to in the future parts of the course.
Check out the MDN web docs for more examples of exports and imports.
Basic concepts of webpack
Since version 4, webpack does not require any configuration. It has a set of defaults. If you want to create a configuration file, you need to name it webpack.config.js. We will now mimic its default configuration to explain the basic concepts connected to Webpack.
webpack.config.js
Note that we write the webpack configuration file in Node.js, therefore it uses CommonJS type of modules.
The webpack.config.js exports a single object. If you run webpack through the console, it is going to look for that file and use it.
Entry
Webpack needs an entry point. It indicates which module webpack should use to begin the module bundling. The default is as follows:
webpack.config.js
1 2 3 |
module.exports = { entry: './src/index.js' }; |
It means that webpack will go to the './src/index.js' file and start the bundling from that. If you use any imports in the index.js file, webpack will handle them.
You can have more than one entry point, but with single page applications, it is common to have only one.
Output
The output is a configuration of where webpack should output your bundle. It defaults to the './dist/main.js' file.
webpack.config.js
1 2 3 4 5 6 7 8 9 |
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' } }; |
Running webpack
In the sections before, we created the index.js file that imports functions from lib.js. Let’s finally run webpack! Remember to put those files into the src directory, so that it would match the default configuration.
The first thing you need to do is to install Webpack. I will be using npm for that. Fire up your terminal and write:
1 2 |
npm init -y npm install webpack |
This will create a directory node_modules with webpack in it, and two files: package.json and package-lock.json.
If you would like to know more about dependencies in npm and the package-lock.json file, check out Keeping you dependencies in order when using npm
Now open the package.json file and modify your scripts:
1 2 3 |
"scripts": { "build": "webpack" } |
Thanks to that, running npm run build will use webpack from the node_modules directory.
You can see that a file main.js was created in the dist directory. It contains all your code both from the index.js and lib.js files
Multiple entry points
You can achieve all of the above without any config file. If you would like to do some more, now it is a time to create it.
entries
The entry property of our configuration does not have to be a string. If you would like to have multiple entry points, you can use an object.
webpack.config.js
1 2 3 4 5 6 |
module.exports = { entry: { first: './src/one.js', second: './src/two.js', } }; |
With that code, we’ve created two entry points. It might be needed if you are developing a multi-page application.
outputs
There is an issue though: by default, there is only one output file specified. We can easily fix that:
webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 |
const path = require('path'); module.exports = { entry: { first: './src/one.js', second: './src/two.js', }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') } } |
With the code above, we indicate that there might be more than one file as the output. All files will have a distinct name now and will be called first.bundle.js and second.bundle.js, just like our entry points.
If you run webpack the same way as before, it will find the webpack.config.js file and apply the configuration.
Summary
Today we’ve learned the basics of module bundling with webpack using the ES6 modules. Webpack 4 provides default configuration, which we went through today while explaining the core concepts like the entry and output. Of course, Webpack can do much more than that. In the upcoming parts of the course, we will cover loaders, and even write one ourselves. Stay tuned!
Good read. A bit basic for some of us with experience in the space but this did clarify a few points, especially for us who have left webpack and are thinking about returning for v4
The webpack.config.js file doesn’t seem to meet the spec.
This line:
path: path.resolve(__dirname, ‘dist’)
… yields this error:
ReferenceError: path is not defined
path is a built in nodejs module you have to import it at the top of the file
const path = require(“path”)
You’re right. I added it to the code snippet, thanks.
Multiple entry points -> I have variables and functions in first.bundle.js – loaded in my root page – I call these functions in my second.bundle.js on another PAGE … I am getting errors … concerning my functions -> this is no function – cause second.bundle.js does not communicate with first.bundle.js … If I compile all js/css code in ONE bundle – all functions are working fine … HOW can I solve this?
Thank you in advance!
I hope you know a solution!
TC John
I love your content, very useful, thanks a lot !
I believe that one must install
webpack-cli
first.Good!