- 这个repo是一个简单的Webpack演示的集合。
这些演示故意写成简单明了的风格。 你会发现在学习强大工具方面没有任何困难。
首先,全局安装Webpack和webpack-dev-server。
$ npm i -g webpack webpack-dev-server然后,克隆repo。
$ git clone https://github.com/ruanyf/webpack-demos.git安装依赖关系。
$ cd webpack-demos
$ npm install现在,使用repo的demo *目录下的源文件。
$ cd demo01
$ npm run dev如果上述命令不能自动打开浏览器,则必须自己访问http://127.0.0.1:8080。
Webpack是为浏览器构建JavaScript模块脚本的前端工具。
它可以使用类似于Browserify,并做更多。
$ browserify main.js > bundle.js
# be equivalent to
$ webpack main.js bundle.jsWebpack需要一个名为webpack.config.js的配置文件,它只是一个CommonJS模块。
// webpack.config.js
module.exports = {
entry: "./main.js",
output: {
filename: "bundle.js"
}
};拥有webpack.config.js后,您可以在不带任何参数的情况下调用Webpack。
$ webpack一些你应该知道的命令行选项。
webpack– building for developmentwebpack -p– building for production (minification)webpack --watch– for continuous incremental buildingwebpack -d– including source mapswebpack --colors– making building output pretty
你可以在你的package.json文件中定制scripts字段,如下所示。
// package.json
{
// ...
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
// ...
}- Entry file
- Multiple entry files
- Babel-loader
- CSS-loader
- Image loader
- CSS Module
- UglifyJs Plugin
- HTML Webpack Plugin and Open Browser Webpack Plugin
- Environment flags
- Code splitting
- Code splitting with bundle-loader
- Common chunk
- Vendor chunk
- Exposing Global Variables
- React router
Demo01: Entry file (source)
入口文件是Webpack用来读取以 bundle.js 构建的文件。
例如,main.js是一个入口文件
// main.js
document.write('<h1>Hello World</h1>');index.html
<html>
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>Webpack遵循webpack.config.js来构建bundle.js。
// webpack.config.js
module.exports = {
entry: "./main.js",
output: {
filename: "bundle.js"
}
};启动服务器,请访问http://127.0.0.1:8080。
$ cd demo01
$ npm run devDemo02: Multiple entry files (source)
多个入口文件是允许的。 对于每个页面具有不同入口文件的多页面应用程序非常有用
// main1.js
document.write("<h1>Hello World</h1>");
// main2.js
document.write("<h2>Hello Webpack</h2>");index.html
<html>
<body>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>webpack.config.js
module.exports = {
entry: {
bundle1: "./main1.js",
bundle2: "./main2.js"
},
output: {
filename: "[name].js"
}
};Demo03: Babel-loader (source)
装载机是预处理程序,它在Webpack构建过程之前转换应用程序的资源文件([更多信息](http://webpack.github.io/docs/using-loaders.html))。
例如,Babel-loader可以将JSX / ES6文件转换为正常的JS文件,之后Webpack将开始构建这些JS文件。 Webpack的官方文档有一个完整的loader列表。
main.jsx是一个JSX文件。
// main.jsx
const React = require("react");
const ReactDOM = require("react-dom");
ReactDOM.render(
<h1>Hello, world!</h1>,
document.querySelector("#wrapper")
);index.html
<html>
<body>
<div id="wrapper"></div>
<script src="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"]
}
}
}
]
}
};上面的代码片段使用babel-loader,它需要Babel的预设插件babel-preset-es2015和[babel-preset-react](https ://www.npmjs.com/package/babel-preset-react)来转储ES6和React。
Demo04: CSS-loader (source)
Webpack允许你在JS文件中包含CSS,然后用CSS-loader预处理CSS文件。
main.js
require("./app.css");app.css
body {
background-color: blue;
}index.html
<html>
<head>
<script type="text/javascript" src="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" ]
},
]
}
};注意,你必须使用两个加载器来转换CSS文件。 首先是CSS-loader读取CSS文件,另一个是Style-loader将<style>标签插入HTML页面。
然后,启动服务器。
$ cd demo04
$ npm run dev实际上,Webpack将一个内部样式表插入index.html中。
<head>
<script type="text/javascript" src="bundle.js"></script>
<style type="text/css">
body {
background-color: blue;
}
</style>
</head>Demo05: Image loader (source)
Webpack也可以在JS文件中包含图像。
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="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将图像文件转换为<img>标签。 如果图像大小小于8192字节,则会转换为数据URL; 否则,它将被转换成正常的URL。
启动服务器后,small.png和big.png具有以下URL。
<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">Demo06: CSS Module (source)
css-loader?modules(查询参数模块)启用CSS模块,它将本地范围的CSS提供给您的JS模块的CSS。 你可以用:global(selector)(更多信息))将其关闭。
index.html
<html>
<body>
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hello Webpack</h2>
<div id="example"></div>
<script src="./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(
<div>
<h1 className={style.h1}>Hello World</h1>
<h2 className="h2">Hello Webpack</h2>
</div>,
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
}
}
]
}
]
}
};启动服务器。
$ cd demo06
$ npm run dev访问http://127.0.0.1:8080,
你会发现只有第二个h1是红色的,因为它的CSS是局部范围的,并且h2都是蓝色的,因为它的CSS是全局范围的。
Demo07: UglifyJs Plugin (source)
Webpack有一个插件系统来扩展它的功能。 例如,UglifyJs Plugin将缩小输出(bundle.js)JS代码。
main.js
var longVariableName = "Hello";
longVariableName += " World";
document.write("<h1>" + longVariableName + "</h1>");index.html
<html>
<body>
<script src="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()
]
};启动服务器后,main.js将被缩小为以下内容。
var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")Demo08:HTML Webpack插件和开放浏览器Webpack插件(source)
本演示向您展示了如何加载第三方插件。
html-webpack-plugin可以为你创建index.html,并且[open-browser-webpack-plugin](https:// github .com / baldore / open-browser-webpack-plugin)可以在Webpack加载时打开一个新的浏览器选项卡。
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"
})
]
};启动服务器。
$ cd demo08
$ npm run dev现在你不需要手动编写index.html,也不需要自己打开浏览器。 Webpack为你做了所有这些事情。
Demo09: Environment flags (source)
您只能在具有环境标志的开发环境中启用一些代码。
main.js
document.write("<h1>Hello World</h1>");
if (__DEV__) {
document.write(new Date());
}index.html
<html>
<body>
<script src="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]
};现在将环境变量传递给webpack。 打开demo09 / package.json,你应该找到scripts字段,如下所示。
// package.json
{
// ...
"scripts": {
"dev": "cross-env DEBUG=true webpack-dev-server --open",
},
// ...
}启动服务器。
$ cd demo09
$ npm run devDemo10: Code splitting (source)
对于大型Web应用程序,将所有代码放入单个文件是无效的。 Webpack允许你将一个大的JS文件分成几个块。 尤其是,如果在某些情况下只需要某些代码块,则可以根据需要加载这些块。
Webpack使用require.ensure来定义分割点(官方文档)。
// main.js
require.ensure(["./a"], function (require) {
var content = require("./a");
document.open();
document.write("<h1>" + content + "</h1>");
document.close();
});require.ensure告诉Webpack.a.js应该从bundle.js中分离出来并且构建成一个块文件。
// a.js
module.exports = "Hello World";现在,Webpack负责处理依赖关系,输出文件和运行时间。 你不必在你的index.html和webpack.config.js中放入任何冗余。
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>webpack.config.js
module.exports = {
entry: "./main.js",
output: {
filename: "bundle.js"
}
};启动服务器。
$ cd demo10
$ npm run dev表面上,你不会感觉到任何差异。 然而,Webpack实际上将main.js和a.js构建为不同的块(bundle.js和0.bundle.js),当需要时从bundle.js加载0.bundle.js 。
Demo11: Code splitting with bundle-loader (source)
另一种代码拆分方式是使用bundle-loader。
// main.js
//现在请求a.js,它将被捆绑到另一个文件中
var load = require("bundle-loader!./a.js");
//要等到a.js可用(并获得导出),您需要异步等待它。
load(function(file) {
document.open();
document.write("<h1>" + file + "</h1>");
document.close();
});require("bundle-loader!./a.js")告诉Webpack从另一个块加载a.js。
现在,Webpack将把main.js构建成bundle.js,将a.js构建成0.bundle.js。
Demo12: Common chunk (source)
当多脚本具有常用块时,可以使用CommonsChunkPlugin将公共部分提取到单独的文件中,这对浏览器缓存和节省带宽很有用。
// main1.jsx
var React = require("react");
var ReactDOM = require("react-dom");
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById("a")
);
// main2.jsx
var React = require("react");
var ReactDOM = require("react-dom");
ReactDOM.render(
<h2>Hello Webpack</h2>,
document.getElementById("b")
);index.html
<html>
<body>
<div id="a"></div>
<div id="b"></div>
<script src="commons.js"></script>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>上面的commons.js是main1.jsx和main2.jsx的常见块。 你可以想象,commons.js包含了"react"和"react-dom"。
webpack.config.js
var webpack = require("webpack");
module.exports = {
entry: {
bundle1: "./main1.jsx",
bundle2: "./main2.jsx"
},
output: {
filename: "[name].js"
},
module: {
rules:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015", "react"]
}
}
},
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
// (公用块名称)
filename: "commons.js",
// (公用块的文件名)
})
]
}Demo13: Vendor chunk (source)
您还可以将脚本中的供应商库从CommonsChunkPlugin中提取到单独的文件中。
main.js
var $ = require("jquery");
$("h1").text("Hello World");index.html
<html>
<body>
<h1></h1>
<script src="vendor.js"></script>
<script src="bundle.js"></script>
</body>
</html>webpack.config.js
var webpack = require("webpack");
module.exports = {
entry: {
app: "./main.js",
vendor: ["jquery"],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor.js"
})
]
};在上面的代码中,entry.vendor:["jquery"]告诉Webpack, jquery应该包含在公共块vendor.js中。
如果你想在每个模块中使用一个模块作为全局变量,比如在没有写入require("jquery")的情况下在每个模块中都可以使用$和jQuery。 你应该使用ProvidePlugin(官方文档),它可以自动加载模块,而不必在任何地方导入或需要它们。
// main.js
$("h1").text("Hello World");
// webpack.config.js
var webpack = require("webpack");
module.exports = {
entry: {
app: "./main.js"
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
};当然,在这种情况下,您应该自己在全局加载jquery.js。
Demo14: Exposing global variables (source)
如果你想使用一些全局变量,并且不想将它们包含在Webpack包中,你可以在webpack.config.js中启用externals字段(official document)。
例如,我们有一个data.js。
// data.js
var data = "Hello World";index.html
<html>
<body>
<script src="data.js"></script>
<script src="bundle.js"></script>
</body>
</html>注意,Webpack只会建立bundle.js,但不会data.js。
我们可以将data暴露为全局变量。
// 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"]
}
}
},
]
},
externals: {
// require("data")是外部的,可用于全局变量数据
data: "data"
}
};现在,您需要data作为脚本中的模块变量。 但它实际上是一个全局变量。
// main.jsx
var data = require("data");
var React = require("react");
var ReactDOM = require("react-dom");
ReactDOM.render(
<h1>{data}</h1>,
document.body
);你也可以把react和react-dom放到externals中,这会大大减少bundle.js的建造时间和建筑尺寸。
Demo15: React router (source)
本演示使用webpack构建React-router的官方示例。
让我们想象一下带有仪表板,收件箱和日历的小应用程序。
+---------------------------------------------------------+
| +---------+ +-------+ +--------+ |
| |Dashboard| | Inbox | |Calendar| Logged in as Jane |
| +---------+ +-------+ +--------+ |
+---------------------------------------------------------+
| |
| Dashboard |
| |
| |
| +---------------------+ +----------------------+ |
| | | | | |
| | + + | +---------> | |
| | | | | | | |
| | | + | | +-------------> | |
| | | | + | | | | |
| | | | | | | | | |
| +-+---+----+-----+----+ +----------------------+ |
| |
+---------------------------------------------------------+
webpack.config.js
module.exports = {
entry: "./index.js",
output: {
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
use: [ "style-loader", "css-loader" ]
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015", "react"]
}
}
},
]
}
};index.js
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Switch, Route, Link } from "react-router-dom";
import "./app.css";
class App extends React.Component {
render() {
return (
<div>
<header>
<ul>
<li><Link to="/app">Dashboard</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
<li><Link to="/calendar">Calendar</Link></li>
</ul>
Logged in as Jane
</header>
<main>
<Switch>
<Route exact path="/" component={Dashboard}/>
<Route path="/app" component={Dashboard}/>
<Route path="/inbox" component={Inbox}/>
<Route path="/calendar" component={Calendar}/>
<Route path="*" component={Dashboard}/>
</Switch>
</main>
</div>
);
}
};
class Dashboard extends React.Component {
render() {
return (
<div>
<p>Dashboard</p>
</div>
);
}
};
class Inbox extends React.Component {
render() {
return (
<div>
<p>Inbox</p>
</div>
);
}
};
class Calendar extends React.Component {
render() {
return (
<div>
<p>Calendar</p>
</div>
);
}
};
render((
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
), document.querySelector('#app'));index.html
<html>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</htmL>启动服务器。
$ cd demo15
$ npm run dev- Webpack docs
- webpack-howto, by Pete Hunt
- SurviveJS Webpack book, by Juho Vepsäläinen
- Diving into Webpack, by Web Design Weekly
- Webpack and React is awesome, by Christian Alfoni
- Browserify vs Webpack, by Cory House
MIT