@H_
404_0@这是React和ECMAScript2015系列
文章的最后一篇,我们将继续探索React 和 Webpack的使用。
@H_
404_0@下面是所有系列
文章章节的
链接:
@H_404_0@本篇文章Github源码
什么是Webpack?
@H_
404_0@就像
JSPM一样,
Webpack
是你的前端应用的模块管理的
解决方案。
@H_
404_0@使用
Webpack,你能够用一种方便的
方法完全控制你的应用资源。
@H_
404_0@为什么Webpack这么受欢迎?主要有以下几个原因:
- @H_404_0@Webpack使用npm作为外部模块源。如果你想添加React到你的项目中,只需要执行
npm install react
即可。这是一个附加的优势,因为你已经知道如何将你喜欢的库添加到你的项目中。
- @H_404_0@你几乎可以加载所有的东西,而不只是JavaScript。
Webpack
使用名字为loaders
的装载机来完成加载。这是对应的loaders清单
- @H_404_0@Webpack有一个很强大的开发工具生态系统。像热更新这样的东西将戏剧性的改变你的开发流程。
- @H_404_0@对于各种类型的任务有很多
Webpack plugins
。在大多数情况下,你可以使用已经存在的解决方案。
- @H_404_0@Webpack 有很漂亮的logo :)
Getting started
@H_
404_0@让我们开始从之前的系列
文章中调整我们的应用程序。
@H_
404_0@首先,我们将要安装初始的开发依赖。
npm install --save-dev webpack
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015 babel-preset-react babel-preset-stage-0
@H_
404_0@在上面的列表中,
webpack
是自解释型的。
Babel
是用于将ES6转换成ES5(如果你阅读了前面的
React and ES6
系列
文章,你应该对ES6和ES5非常熟悉)。自从babel 6后你必须为每一个额外的语言特征安装独立的包。这些包叫做
presets
。我们安装
es2015 preset
,
react preset
和
stage-0 preset
。对于更多关于
babel 6
的信息,你可以阅读
这篇文章。
@H_
404_0@下一步,安装非开发依赖(react和react-dom包):
@H_
404_0@
npm install --save react react-dom
@H_
404_0@现在在你的项目中基于Webpack最重要的一步。在你的项目根目录下面创建
webpack.config.dev.js
文件。这个
文件将用来打包你所有的在一个bundle(或者多个bundle)里面的JavaScript(在大多数项目中不只是JavaScript),打包完就可以在
用户的浏览器中正式运行。
@H_
404_0@
webpack.config.dev.js
的
内容如下:
var path = require('path');
var webpack = require('webpack');
var config = {
devtool: 'cheap-module-eval-source-map',entry: [
'./app.js'
],output: {
path: path.join(__dirname,'dist'),filename: 'bundle.js',publicPath: '/dist/'
},plugins: [
new webpack.NoEmitOnErrorsPlugin()
]
};
module.exports = config;
@H_
404_0@以上
代码的亮点:
- @H_404_0@Line 5. 在提高应用程序的各种调试策略中,我们有一个选择,你可以点击这里了解更多关于
cheap-module-eval-source-map
的内容。
- @H_404_0@Lines 6-8. 这里我们定义了
app.js
为应用程序的主入口。
- @H_404_0@Lines 9-13. 这个配置制定
Webpack
将打包所有的模块成文件bundle.js
,并且将bundle.js
文件放到dist/
路径下面。
Webpack loaders
@H_
404_0@用
Webpack
几乎可以加载所有的东西到你的
代码中(这里是
清单)。Webpack使用的名字叫做Webpack装载机。
@H_
404_0@你可以制定
文件扩展名关联到特别的装载机。
@H_
404_0@在我们的案例中,我们将使用
babel-loader
来将
ES2015 / ES6
的
代码转换成
ES5
.首先,我们需要安装
npm
依赖包。
npm install --save-dev babel-loader
@H_
404_0@然后,通过
添加一些新的装载机关键字到出口对象中来调整
webpack.config.dev.js
文件的配置。
var config = {
... add the below code as object key ...
module: {
loaders: [
{
test: /\.js$/,loaders: ['babel-loader'],exclude: /node_modules/
}
]
}
};
module.exports = config;
@H_
404_0@这里需要重点注意的是,我们通过
exclude
关键字的设置
禁止Webpack
解析
node_modules
文件夹里面的
文件。
@H_
404_0@接下来我们在项目的根目录下面
添加.babelrc
文件。
{
"presets": ["react","es2015","stage-0"]
}
@H_
404_0@这个
文件是配置
babel
以便能够使用前面我们
添加的
react
,
es2015
和
stage-0
presets。
@H_
404_0@现在,无论什么时候
Webpack
遇到,比如:
import CartItem from './cartItem.js'
,它将加载这个
文件并且将
ES6
转换成
ES5
。
添加Webpack
开发服务器
@H_
404_0@为了运行这个程序,我们需要在服务器上运行这些
文件。
@H_
404_0@幸运的是,
Webpack
生态系统已经提供所有你需要的东西。你可以使用
Webpack开发服务器或者
Webpack开发中间件,比如:Express.js。
@H_
404_0@我们将使用后者。优势是在内存中处理
文件时速度快。
@H_
404_0@让我们安装
npm
模块:
npm install --save-dev webpack-dev-middleware express
@H_
404_0@下一步,在根目录下面
添加server.js
文件:
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.config.dev');
var app = express();
var compiler = webpack(config);
var port = 3000;
app.use(require('webpack-dev-middleware')(compiler,{
noInfo: true,publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
app.get('*',function (req,res) {
res.sendFile(path.join(__dirname,'index.html'));
});
app.listen(port,function onAppListening(err) {
if (err) {
console.error(err);
} else {
console.info('==> Webpack development server listening on port');
}
});
@H_
404_0@这是典型的使用
Webpack Dev Middleware
的
express.js
服务器。
添加热刷新模块
@H_
404_0@
Webpack Dev Middleware
已经包含了热刷新的特性。无论什么时候,你的
代码发生变化,它都会立即刷新
页面。
@H_
404_0@如果想简单的看看热刷新的演示
效果,可以看看
Dan Abramov
的
视频。
@H_
404_0@为了激活
Hot Module Reloading
,你首先得安装必须得
npm
包。
npm install --save-dev webpack-hot-middleware
@H_
404_0@然后在
webpack.config.dev.js
文件中设置
entry
和
plugins
:
var config = {
entry: [
'./app.js','webpack-hot-middleware/client'
],...
plugins: [
new webpack.HotModuleReplacementPlugin(),new webpack.NoEmitOnErrorsPlugin()
]
};
module.exports = config;
@H_
404_0@如果想对React 应用更进一步使用模块刷新其实有很多种
方法。
@H_
404_0@其中一个简单的
方法就是安装
babel-preset-react-hmre
模块。
npm install --save-dev babel-preset-react-hmre
@H_
404_0@调整
.babelrc
文件的
内容:
{
"presets": ["react","stage-0"],"env": {
"development": {
"presets": ["react-hmre"]
}
}
}
@H_
404_0@到这一步,这个应用就具备热刷新的
功能。
最后几步
<!DOCTYPE html>
<html>
<head lang="en">
<Meta charset="UTF-8">
<title>React and ES6 Part 6</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.2/css/foundation.min.css">
</head>
<body>
<nav class="top-bar" data-topbar role="navigation">
<section class="top-bar-section">
<ul class="left">
<li class="active">
<a href="http://egorsmirnov.me/2016/04/11/react-and-es6-part6.html" target="_blank">
Blog post at egorsmirnov.me: React and ES6 - Part 6,React and ES6 Workflow with Webpack
</a>
</li>
</ul>
</section>
</nav>
<div class="root"></div>
<script src="/dist/bundle.js"></script>
</body>
</html>
import React from 'react';
import ReactDOM from 'react-dom';
import CartItem from './cartItem.js';
const order = {
title: 'Fresh fruits package',image: 'http://images.all-free-download.com/images/graphiclarge/citrus_fruit_184416.jpg',initialQty: 3,price: 8
};
ReactDOM.render(
< CartItem
title={order.title}
image={order.image}
initialQty={order.initialQty}
price={order.price
}
/>,document.querySelector('.root')
)
;
import React from 'react';
export default class CartItem extends React.Component {
static propTypes = {
title: React.PropTypes.string.isrequired,price: React.PropTypes.number.isrequired,initialQty: React.PropTypes.number
};
static defaultProps = {
title: 'Undefined Product',price: 100,initialQty: 0
};
state = {
qty: this.props.initialQty,total: 0
};
constructor(props) {
super(props);
}
componentWillMount() {
this.recalculateTotal();
}
increaseQty() {
this.setState({qty: this.state.qty + 1},this.recalculateTotal);
}
decreaseQty() {
let newQty = this.state.qty > 0 ? this.state.qty - 1 : 0;
this.setState({qty: newQty},this.recalculateTotal);
}
recalculateTotal() {
this.setState({total: this.state.qty * this.props.price});
}
render() {
return (
<article className="row large-4">
<figure className="text-center">
<p>
<img src={this.props.image}/>
</p>
<figcaption>
<h2>{this.props.title}</h2>
</figcaption>
</figure>
<p className="large-4 column"><strong>Quantity: {this.state.qty}</strong></p>
<p className="large-4 column">
<button onClick={this.increaseQty.bind(this)} className="button success">+</button>
<button onClick={this.decreaseQty.bind(this)} className="button alert">-</button>
</p>
<p className="large-4 column"><strong>Price per item:</strong> ${this.props.price}</p>
<h3 className="large-12 column text-center">
Total: ${this.state.total}
</h3>
</article>
);
}
}
修改package.json
@H_
404_0@现在已经将前面所有碎片化的
代码已经整合在一个项目中。
@H_
404_0@我们需要在
package.json
文件的
scripts
区域
添加一些脚本。
{
"name": "awesome-application","version": "1.0.0",...
"scripts": {
"start": "node server.js"
},...
}
运行项目
- @H_404_0@运行
npm start
- @H_404_0@在浏览器中打开
http://localhost:3000
- @H_404_0@项目运行效果图
Webpack生产环境配置
@H_
404_0@现在我们能够在服务器上运行我们的应用程序并且能够通过热模块更新刷新我们的
页面。
@H_
404_0@但是如果我们想要将产品部署到生产环境?没问题,
Webpack
有对应的
解决方案。
@H_
404_0@创建
webpack.config.prod.js
文件,
文件内容为:
var path = require('path');
var webpack = require('webpack');
var config = {
devtool: 'source-map',filename: 'bundle.js'
},plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
],module: {
loaders: [
{
test: /\.js$/,exclude: /node_modules/
}
]
}
};
module.exports = config;
@H_
404_0@它和开发模式下的
配置文件有点相似,但是有以下不同点:
- @H_404_0@热刷新的功能不再有,因为在生产环境中不需要这个功能。
- @H_404_0@
JavaScript bundle
被依赖于webpack.optimize.UglifyJsPlugin
的UglifyJs
压缩。
- @H_404_0@环境变量
NODE_ENV
被设置成production
。这需要屏蔽来自React开发环境中的警告。
@H_
404_0@下一步,更新
package.json
文件中的
scripts
:
{
...
"scripts": {
"start": "node server.js","clean": "rimraf dist","build:webpack": "NODE_ENV=production webpack --progress --colors --config webpack.config.prod.js","build": "npm run clean && npm run build:webpack"
},...
}
@H_
404_0@到现在为止,如果你在控制台运行
npm run build
,压缩
文件bundle.js
将被创建并且放在
dist/
路径下面。这个
文件准备在生产环境中使用。
这只是刚刚开始
@H_
404_0@我们刚才学到的东西只是
Webpack
的一些基础。
@H_
404_0@
Webpack
是一个很容易入门的工具,但是要想精通,需要点时间好好研究研究。
参考文档
@H_404_0@社群品牌:从零到壹全栈部落
定位:寻找共好,共同学习,持续输出全栈技术社群
业界荣誉:IT界的逻辑思维
文化:输出是最好的学习方式
官方公众号:全栈部落
社群发起人:春哥(从零到壹创始人,交流微信:liyc1215)
技术交流社区:全栈部落BBS
全栈部落完整系列教程:全栈部落完整电子书学习笔记
关注全栈部落官方公众号,每晚十点接收系列原创技术推送 |
|