翻译它主要是用于学习Webpack,原地址为github.com/ruanyf/webp…javascript
首先,全局安装Webpack和webpack-dev-servercss
$ npm i -g webpack webpack-dev-server
复制代码
而后克隆clone阮一峰的仓库html
$ git clone https://github.com/ruanyf/webpack-demos.git
复制代码
安装依赖前端
$ cd webpack-demos
$ npm install
复制代码
如今开始进入demo*目录而且运行它们java
$ cd demo01
$ npm run dev
复制代码
上面的代码不会自动的打开你的浏览器,须要手动访问http://127.0.0.1:8080node
Webpack用于构建Javascript模块脚原本给浏览器使用的前端工具。
它和Browserify很像,可是能作更多的事~react
$ browserify main.js > bundle.js
# 上下代码做用相同
$ webpack main.js bundle.js
复制代码
Webpack须要一个名为webpack.config.js
的配置文件,这个文件就是一个CommonJS的模块(module)jquery
// webpack.config.js的内容
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
复制代码
当建好webpack.config.js
后就能直接运行Webpack,而不加参数webpack
$ webpack
复制代码
有一些必须知道的参数选项以下git
webpack
——开发时的构建命令webpack -p
——发布产品时的构建命令webpack --watch
——用于增量开发的构建webpack -d
——包括source mapswebpack --colors
——让构建输出更好看能够在定制webpack.config.js
中的scripts
选项,以下所示
// package.json
{
// ...
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
// ...
}
复制代码
入口文件用来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 dev
复制代码
Webpack
容许多个入口文件存在,在多页面的app中颇有用,每一个页面有不一样的入口文件。
// 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'
}
};
复制代码
加载器(Loaders)是一些预处理器,用于在Webpack的构建过程前,将你app里的一些资源文件进行转换。
例如,Babel-loader可以将JSX/ES6文件转为普通的JS文件,以后Webpack可以开始构建它们。Webpack官方文档有一个加载器的列表地址 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-preset-es2015和babel-preset-react来转换ES6和React(翻译:如今为废弃了,详情)
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用来往HTML中插入<style>
标签。
而后打开server
$ cd demo04
$ npm run dev
复制代码
事实上,Webpack将CSS文件的内容直接插入到index.html
<head>
<script type="text/javascript" src="bundle.js"></script>
<style type="text/css">
body {
background-color: blue;
}
</style>
</head>
复制代码
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
将image文件转为<img>
标签,若是图片大小小鱼8192字节,它将转换为Data url(翻译:图片变为Base64编码,减小请求次数),不然,他将转为普通文件URL。
<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">
复制代码
css-loader?modules
(请求参数为modules)可以使用CSS Module,CSS Module带给你的JS文件模块中的CSS一个局部做用域,也可使用:global(selector)
让CSS变为全局做用。
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
}
}
]
}
]
}
};
复制代码
访问 http://127.0.0.1:8080会看到只有h1
是红色的,由于他的CSS是局部做用域,而后因此h2
都是蓝色的,由于它是全局做用域。
Webpack用插件系统来扩展他的功能。例如,UglifyJs Plugin,它用来压缩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>")
复制代码
(翻译:是在bundle.js
的最后几个代码那,是这些代码)
这个demo用来展现如何加载第三方插件 html-webpack-plugin
能为你建立index.html
,open-browser-webpack-plugin
可以在Webpack加载时打开一个新的浏览器标签(tab)
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'
})
]
};
复制代码
如今你不用手动建立index.html
也不用手动打开浏览器了。
使用环境变量让一些代码只能在开发环境时使用。
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",
},
// ...
}
复制代码
在大型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
中
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
复制代码
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
复制代码
访问服务器后,你感受不到任何不一样。实际上,Webpack将构建main.js
和a.js
到不一样的块中(bundle.js
和0.bundle.js
),而后从bundle.js
中按需加载0.bundle.js
另外一个代码分割的方式是bundle-loader
// main.js
// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');
// To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
复制代码
require('bundle-loader!./a.js')
告诉Webpack从其余块加载a.js
如今main.js
构建为bundle.js
,a.js
构建为0.bundle.js
在多个JS脚本中有通用块,经过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",
// (the commons chunk name)
filename: "commons.js",
// (the filename of the commons chunk)
})
]
}
复制代码
经过CommonsChunkPlugin
,你能从JS脚本提取官方库到单独的文件中
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
,它可以自动加载模块而不须要处处import
或者是require
// 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'
})
]
};
复制代码
固然,在Demo13中,你须要本身全局加载jquery.js
若是你想用一些全局变量,不须要在Webpack包中包含他们,你可使用webpack.config.js里的externals
字段
例如,咱们有一个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') is external and available
// on the global var data
'data': 'data'
}
};
复制代码
此时,你能够require('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
的时间和文件大小
这个Demo使用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>
复制代码