Webpack is an open-source JavaScript module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset. Webpack takes modules with dependencies and generates static assets representing those modules. It is a module bundler primarily for JavaScript, but it can transform front-end assets like HTML, CSS, even images if the corresponding plugins are included. (WIKI)
Always take care about webpack version you use and a guide or video you lead. Webpack significantly differs from version to version!
To install the latest release or a specific version, run one of the following commands:
npm install --save-dev webpack
npm install --save-dev webpack@<version>
If you're using webpack v4 or later, you'll need to install the CLI.
npm install --save-dev webpack-cli
Installing locally is what webpack official page recommend for most projects. This makes it easier to upgrade projects individually when breaking changes are introduced.
When webpack installed, let's run
npx webpack
which will take our script at src/index.js as the entry point, and will generate dist/main.js as the output. The npx command, which ships with Node 8.2/npm 5.2.0 or higher, runs the webpack binary (./node_modules/.bin/webpack) of the webpack package we installed in the beginning
The import and export statements have been standardized in ES2015 and are supported in most browsers. Some older browsers still lag behind but webpack supports modules out of the box.
Behind the scenes, webpack actually "transpiles" the code so that older browsers can also run it. If you inspect dist/main.js, you might be able to see how webpack does this, it's quite ingenious! Besides import and export, webpack supports various other module syntaxes as well, see Module API for more information.
Note that webpack will not alter any code other than import and export statements. If you are using other ES2015 features, make sure to use a transpiler such as Babel via webpack's loader system.
As of version 4, webpack doesn't require any configuration, but most projects will need a more complex setup, which is why webpack supports a configuration file. This is much more efficient than having to manually type in a lot of commands in the terminal, so let's create one:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
};
Now, let's run the build again but instead using our new configuration file:
npx webpack --config webpack.config.js
If a webpack.config.js is present, the webpack command picks it up by default. We use the --config option here only to show that you can pass a config of any name. This will be useful for more complex configurations that need to be split into multiple files.
A configuration file allows far more flexibility than simple CLI usage. We can specify loader rules, plugins, resolve options and many other enhancements this way. See the configuration documentation to learn more.
Given it's not particularly fun to run a local copy of webpack from the CLI, we can set up a little shortcut. Let's adjust our package.json by adding an npm script:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2"
},
"dependencies": {
"lodash": "^4.17.5"
}
}
Now the npm run build command can be used in place of the npx command we used earlier. Note that within scripts we can reference locally installed npm packages by name the same way we did with npx. This convention is the standard in most npm-based projects because it allows all contributors to use the same set of common scripts (each with flags like --config if necessary).
npm run build
Now run the following command and see if your script alias works:
In order to import a CSS file from within a JavaScript module, you need to install and add the style-loader and css-loader to your module configuration:
npm install --save-dev style-loader css-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: [
+ 'style-loader',
+ 'css-loader'
+ ]
+ }
+ ]
+ }
};
This enables you to import './style.css' into the file that depends on that styling. Now, when that module is run, a <style> tag with the stringified css will be inserted into the <head> of your html file.
import './style.css';
Note that you can, and in most cases should, minimize css for better load times in production. On top of that, loaders exist for pretty much any flavor of CSS you can think of -- postcss, sass, and less to name a few.
Using the file-loader we can easily incorporate those in our system as well:
npm install --save-dev file-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
+ {
+ test: /\.(png|svg|jpg|gif)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
A logical next step from here is minifying and optimizing your images. Check out the image-webpack-loader and url-loader for more on how you can enhance your image loading process.
import Icon from './icon.png';
var myIcon = new Image();
myIcon.src = Icon;
document.body.appendChild(myIcon);
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
+ @font-face {
+ font-family: 'MyFont';
+ src: url('./my-font.woff2') format('woff2'),
+ url('./my-font.woff') format('woff');
+ font-weight: 600;
+ font-style: normal;
+ }
Usage:
npm install --save-dev html-webpack-plugin
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// previous code base
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'Output Management'
+ })
+ ]
};
webpack.config.js
npm install --save-dev clean-webpack-plugin
webpack.config.js
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
// previous code base
plugins: [
// ...
+ new CleanWebpackPlugin(),
]
};
The tools in this guide are only meant for development, please avoid using them in production!
module.exports = {
+ mode: 'development',
// previous code base
};
There are a lot of different options available when it comes to source maps. Be sure to check them out so you can configure them to your needs.
For this guide, let's use the inline-source-map option, which is good for illustrative purposes (though not for production):
webpack.config.js
module.exports = {
// previous code base
+ devtool: 'inline-source-map',
};
It quickly becomes a hassle to manually run npm run build every time you want to compile your code.
There are a couple of different options available in webpack that help you automatically compile your code whenever it changes:
In most cases, you probably would want to use
webpack-dev-server, but let's explore all of the above options.
You can instruct webpack to "watch" all files within your dependency graph for changes. If one of these files is updated, the code will be recompiled so you don't have to run the full build manually.
package.json
{
"name": "demo-app",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "webpack --watch",
"build": "webpack"
},
/* previous code base */
}
The webpack-dev-server provides you with a simple web server and the ability to use live reloading.
package.json
{
"name": "demo-app",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "webpack-dev-server",
"build": "webpack"
},
/* previous code base */
}
npm install --save-dev webpack-dev-server
Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways:
HMR is not intended for use in production, meaning it should only be used in development. See the building for production guide for more information.
This feature is great for productivity. All we need to do is update our webpack-dev-server configuration, and use webpack's built in HMR plugin.
+ const webpack = require('webpack');
module.exports = {
devServer: {
contentBase: './dist',
+ hot: true
},
plugins: [
+ new webpack.HotModuleReplacementPlugin()
]
};
In this guide we'll dive into some of the best practices and utilities for building a production site or application.
The goals of development and production builds differ greatly. In development, we want strong source mapping and a localhost server with live reloading or hot module replacement. In production, our goals shift to a focus on minified bundles, lighter weight source maps, and optimized assets to improve load time. With this logical separation at hand, we typically recommend writing separate webpack configurations for each environment.
npm install --save-dev webpack-merge
webpack-demo
|- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
|- /dist
|- /src
|- index.js
|- math.js
|- /node_modules
project structure
Now move common code into the webpack.common.js, then use merge to merge two parts of common and custom code.