1. Introduction
2. Quickstart
2.1. no config
using webpack without
webpack.config.js
filemkdir starter-no-config
cd starter-no-config/
mkdir src dist
echo "console.log('hey!');" >> src/index.js
echo "<script src='./main.js'></script>" >> dist/index.html
npm init -y
npm i -g webpack webpack-cli
#npm i -DE webpack webpack-cli
webpack --mode=development
webpack --mode production
2.2. basic config
using webpack with basic config file:
config/webpack.dev.js
const { resolve } = require('path');
module.exports = {
entry: {
main: './src/index.js'
},
mode: 'development',
output: {
filename: '[name]-bundle.js',
path: resolve(__dirname, '../dist'),
},
};
2.3. add HTML plugin
install html-webpack-plugin
npm i -DE html-webpack-plugin
update webpack condig
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
favicon: './src/favicon.ico',
}),
],
};
2.4. add webpack-dev-server
update webpack condig
const { resolve, join } = require('path');
module.exports = {
// ...
devServer: {
contentBase: join(__dirname, '../dist'),
// show / overlay errors in browser
overlay: true,
},
};
install and run webpack-dev-server
npm i -DE webpack-dev-server
webpack-dev-server --config config/webpack.dev.js
2.5. add css-loader and style-loader
add some css styles
body {
margin: 0;
background-color: #444;
}
/* lets centred content using flex */
#app {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* font styling */
h1 {
color: white;
font-size: 3em;
font-family: Helvetica, sans-serif, 'DejaVu Sans', Arial;
text-shadow: 0 0 25px white;
}
These loaders will apply in reverse order: first, css-loader , next: style-loader
|
install css-loader and style-loader
npm i -DE css-loader style-loader
update webpack condig
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
],
},
],
},
};
2.6. process html and using html / file loaders
prepare
./src/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack | Examples</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app"></div>
<script src="main-bundle.js"></script>
</body>
</html>
Few thinks are happening here:
First, html-loader will do necessary linting of *.html files.
Then extract-loader will tell webpack do not include it in result bundle.js file.
And finally file-loader will put extracted content in output dir accordingly
|
remove useless plugin and install requires loaders:
html-loader
, extract-loader
and file-loader
npm rm -DE html-webpack-plugin
npm i -DE html-loader extract-loader file-loader
update webpack condig
// const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
/*
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
favicon: './src/favicon.ico',
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
],
},
],
},
*/
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
{ loader: 'extract-loader' },
{ loader: 'css-loader' },
],
},
{
test: /\.html$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
{ loader: 'extract-loader' },
{ loader: 'html-loader' },
],
},
{
test: /\.(ico)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
],
},
};
finally combine all together in
./src/index.js
require('./index.html');
require('./styles.css');
require('./favicon.ico');
I wont use that approach,
I prefer HtmlWebpackPlugin and ExtractTextWebpackPlugin
|
2.7. using extract-text-webpack-plugin
install
npm rm -ED style-loader
npm i -DE extract-text-webpack-plugin@next css-loader
# also add less support
npm i -DE less-loader less
update webpack condig
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssContent = new ExtractTextPlugin('[name]-[hash:8].css');
const lessContent = new ExtractTextPlugin('[name].less-[hash:8].css');
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i,
use: cssContent.extract([
'css-loader',
]),
},
{
test: /\.less$/i,
use: cssContent.extract([
'css-loader',
'less-loader',
]),
},
],
},
plugins: [
cssContent,
lessContent,
],
};
There are better option available for using instead of extract text plugin:
mini-css-extract-plugin
|
2.8. using mini-css-extract-plugin
install
npm rm extract-text-webpack-plugin
npm i -DE mini-css-extract-plugin
update webpack condig
const mode = process.env.NODE_ENV || 'production';
const isProduction = mode === 'production';
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode,
// ...
module: {
rules: [
{
test: /\.css$/i,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: isProduction,
},
},
// 'postcss-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]-[hash:8].css',
}),
],
};
update package.json
{
"scripts": {
"dev": "cross-env NODE_ENV=development webpack",
"build": "cross-env NODE_ENV=production webpack",
"start": "cross-env NODE_ENV=development webpack-dev-server --open"
}
}
2.9. using optimize-css-assets-webpack-plugin
THis plugin solves extract-text-webpack-plugin CSS duplication problem |
install
npm i -DE optimize-css-assets-webpack-plugin
update webpack condig
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
// ...
plugins: [
isProduction ? new OptimizeCssPlugin() : undefined,
].filter(p => !!p),
};
2.10. using webpack config as a function
remove useless packages
npm rm cross-env
update webpack condig
const safety = env => env || process.env || {};
const mode = env => safety(env).NODE_ENV || 'production';
const isProduction = env => 'production' === mode(env);
module.exports = env => ({
mode: mode(env),
module: {
rules: [
{
test: /\.css$/i,
use: [
isProduction(env) ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 },
},
'postcss-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
},
},
],
},
],
},
plugins: [
isProduction(env) ? new OptimizeCssPlugin() : undefined,
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(mode(env)),
},
})
].filter(p => !!p),
});
2.11. babel setup (compare babel minify with uglifyjs)
install required packages
npm i -ED babel-core babel-loader babel-preset-env babel-preset-stage-0 babel-minify-webpack-plugin babel-plugin-transform-runtime babel-polyfill uglifyjs-webpack-plugin
prepare .babelrc
{
"presets": [
"stage-0",
[
"env",
{
"debug": false,
"targets": {
"browsers": [
"last 2 versions",
"safari >= 7",
"chrome >= 52",
"firefox >= 48"
]
}
}
]
],
"plugins": [
"transform-runtime",
"syntax-dynamic-import"
]
}
update webpack condig
const BabelMinifyPlugin = require('babel-minify-webpack-plugin');
// const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = env => ({
entry: {
main: [
// 'babel-polyfill',
'./src/index.js',
],
},
{
test: /\.css$/i,
use: [
isProduction(env) ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 },
},
'postcss-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
},
},
],
},
],
},
plugins: [
// you decide with one is better:
isProduction(env) ? new BabelMinifyPlugin() : undefined,
// isProduction(env) ? new UglifyJsPlugin() : undefined,
].filter(p => !!p),
});
2.12. compression files
install required packages
npm i -ED compression-webpack-plugin
npm i -ED brotli-webpack-plugin
update webpack condig
const CompressionPlugin = require('compression-webpack-plugin');
const BrotliPlugin = require('brotli-webpack-plugin');
module.exports = env => ({
// ...
plugins: [
isProduction(env) ? new CompressionPlugin({ algorithm: 'gzip' }) : undefined,
isProduction(env) ? new BrotliPlugin() : undefined,
].filter(p => !!p),
});
2.13. react (basic webpack setup)
install required packages
npm i -E react react-dom react-router react-router-dom
npm i -ED babel-preset-react babel-runtime babel-register webpack-hot-middleware babel-plugin-syntax-dynamic-import
prepare .babelrc
{
"presets": [
"react",
"stage-0",
[
"env",
{
"debug": false,
"targets": {
"browsers": [
"last 2 versions",
"safari >= 7",
"chrome >= 52",
"firefox >= 48"
]
}
}
]
],
"plugins": [
"transform-runtime",
"syntax-dynamic-import"
]
}
update webpack condig
module.exports = env => ({
module: {
rules: [
{
test: /\.jsx?$/i,
use: [
'babel-loader',
],
include: resolve(__dirname, 'src'),
},
{
test: /\.(ico|jpe?g|png|gif)$/i,
use: [
{
loader: 'file-loader',
options: {
name: isProduction(env) ? '[hash].[ext]' : '[path][name].[ext]',
},
},
],
},
],
},
// ...
});