This repo is a collection of simple demos of Webpack.
These demos are purposely written in a simple and clear style. You will find no difficulty in following them to learn the powerful tool.
First, install Webpack and webpack-dev-server globally.
$ npm i -g webpack webpack-dev-server
Then, clone the repo.
$ git clone https://github.com/ruanyf/webpack-demos.git
Install the dependencies.
$ cd webpack-demos
$ npm install
Now, play with the source files under the repo's demo* directories.
$ cd demo01
$ npm run dev
If the above command doesn't open your browser automatically, you have to visit http://127.0.0.1:8080 by yourself.
Webpack is a front-end tool to build JavaScript module scripts for browsers.
It can be used similar to Browserify, and do much more.
$ browserify main.js > bundle.js
# be equivalent to
$ webpack main.js bundle.js
Webpack needs a configuration file called webpack.config.js which is just a CommonJS module.
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
After having webpack.config.js, you can invoke Webpack without any arguments.
$ webpack
Some command-line options you should know.
webpack – building for developmentwebpack -p – building for production (minification)webpack --watch – for continuous incremental buildingwebpack -d – including source mapswebpack --colors – making building output prettyYou could customize scripts field in your package.json file as following.
// package.json
{
// ...
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
// ...
}
Entry file is a file which Webpack reads to build bundle.js.
For example, main.js is an entry file.
// main.js
document.write('<h1>Hello World</h1>');
index.html
<html>
<body>
<script type="text/javascript" src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
Webpack follows webpack.config.js to build bundle.js.
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
Launch the server, visit http://127.0.0.1:8080 .
$ cd demo01
$ npm run dev
Multiple entry files are allowed. It is useful for a multi-page app which has different entry file for each page.
// main1.js
document.write('<h1>Hello World</h1>');
// main2.js
document.write('<h2>Hello Webpack</h2>');
index.html
<html>
<body>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle1.js"></script>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle2.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: {
bundle1: './main1.js',
bundle2: './main2.js'
},
output: {
filename: '[name].js'
}
};
Loaders are preprocessors which transform a resource file of your app (more info) before Webpack's building process.
For example, Babel-loader can transform JSX/ES6 file into normal JS files,after which Webpack will begin to build these JS files. Webpack's official doc has a complete list of loaders.
main.jsx is a JSX file.
// main.jsx
const React = require('react');
const ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.querySelector('#wrapper')
);
index.html
<html>
<body>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
}
]
}
};
The above snippet uses babel-loader which needs Babel's preset plugins babel-preset-es2015 and babel-preset-react to transpile ES6 and React.
Webpack allows you to include CSS in JS file, then preprocessed CSS file with CSS-loader.
main.js
require('./app.css');
app.css
body {
background-color: blue;
}
index.html
<html>
<head>
<script type="text/javascript" src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
]
}
};
Attention, you have to use two loaders to transform CSS file. First is CSS-loader to read CSS file, and another one is Style-loader to insert <style> tag into HTML page.
Then, launch the server.
$ cd demo04
$ npm run dev
Actually, Webpack inserts an internal style sheet into index.html.
<head>
<script type="text/javascript" src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
<style type="text/css">
body {
background-color: blue;
}
</style>
</head>
Webpack could also include images in JS files.
main.js
var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);
var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);
index.html
<html>
<body>
<script type="text/javascript" src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
};
url-loader transforms image files into <img> tag. If the image size is smaller than 8192 bytes, it will be transformed into Data URL; otherwise, it will be transformed into normal URL.
After launching the server, small.png and big.png have the following URLs.
<img src="https://github.com/ruanyf/webpack-demos/raw/main/data:image/png;base64,iVBOR...uQmCC">
<img src="https://github.com/ruanyf/webpack-demos/raw/main/4853ca667a2b8b8844eb2693ac1b2578.png">
css-loader?modules (the query parameter modules) enables the CSS Module which gives a local scoped CSS to your JS module's CSS. You can switch it off with :global(selector) (more info).
index.html
<html>
<body>
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hello Webpack</h2>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
app.css
/* local scope */
.h1 {
color:red;
}
/* global scope */
:global(.h2) {
color: blue;
}
main.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');
ReactDOM.render(
<h1 className={style.h1}>Hello World</h1>
<h2 className="h2">Hello Webpack</h2>
,
document.getElementById('example')
);
webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
rules:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
};
Launch the server.
$ cd demo06
$ npm run dev
Visiting http://127.0.0.1:8080 , you'll find that only second h1 is red, because its CSS is local scoped, and both h2 is blue, because its CSS is global scoped.
Webpack has a plugin system to expand its functions. For example, UglifyJs Plugin will minify output(bundle.js) JS codes.
main.js
var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');
index.html
<html>
<body>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new UglifyJsPlugin()
]
};
After launching the server, main.js will be minified into following.
var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")
This demo shows you how to load 3rd-party plugins.
html-webpack-plugin could create index.html for you, and open-browser-webpack-plugin could open a new browser tab when Webpack loads.
main.js
document.write('<h1>Hello World</h1>');
webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
};
Launch the server.
$ cd demo08
$ npm run dev
Now you don't need to write index.html by hand and don't have to open browser by yourself. Webpack did all these things for you.
You can enable some codes only in development environment with environment flags.
main.js
document.write('<h1>Hello World</h1>');
if (__DEV__) {
document.write(new Date());
}
index.html
<html>
<body>
<script src="https://github.com/ruanyf/webpack-demos/raw/main/bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require('webpack');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [devFlagPlugin]
};
Now pass environment variable into webpack. Opening demo09/package.json, you should find scripts field as following.
// package.json
{
// ...
"scripts": {
"dev": "cross-env DEBUG=true webpack-dev-server --open",
},
// ...
}
Launch the server.
$ cd demo09
$ npm run dev
For big web apps, it’s not efficient to put all code into a single file. Webpack allows you to split a large JS file into several chunks. Especially, if some blocks of code are only required under some circumstances, these chunks could be loaded on demand.
Webpack uses require.ensure to define a split point (official document).
// main.js
require.ensure(['./a'], function (require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
require.ensure tells Webpack that ./a.js should be separated from bundle.js and built into a single chunk file.
// a.js
module.exports = 'Hello World';
Now Webpack takes
$ claude mcp add webpack-demos \
-- python -m otcore.mcp_server <graph>