@hpp157
2016-09-29T07:35:36.000000Z
字数 16135
阅读 3235
react
上一章,我们看了Virtual DOM,它是告诉React怎么创建react元素的一系列说明,由被叫做React element的js 对象组成。目前为止,我们学了两种创建react元素的方法:React.createElement
和factories
.本章,我们讲怎么使用JSX。
用来代替写起来比较复杂冗长的React.createElement
的另一种写法是使用JSX,它是一个Javascript扩展,允许使用类似HTML的语法来定义React element。(a javascript extension that allows us to define React elements using syntax that looks similar to HTML)
Facebook团队发布JSX用来创建复杂的DOM tree,当然他们也想让React和HTML那样更有可读性。
在JSX中,一个元素(element)的类型由标签(tag)来明确。标签的属性代表元素属性。元素(element)的children可以添加在标签的开始和结束之间。
你也可以添加其它的JSX元素作为children。如果你有一个无序列表<ul>
.你可以用JSX标签给里面添加子元素<li>
,看起来和html非常像。
<ul>
<li>lb Samon</li>
<li>cup Pine Nuts</li>
<li>cups Butter Letuce</li>
<li>1 Yellow Squash</li>
<li>1/2 cup Olive Oil</li>
<li>3 cloves of Garlic</li>
</ul>
JSX也能和组件一起使用。只需要用className定义组件就可以。在本例中,我们传递ingredients数组到IngredientsList中作为组件属性。
当传递ingredients数组到组件IngredientsList中时,要用花括号{}
裹住,这叫做Javascript表达式,并且我们要传javascript的值作为属性到组件中的时候必须要用花括号(we must use these when passing Javascript values to components as properties
), 组件属性要有两个类型:或者string或者是js表达式,表达式可以时数组 ,对象,甚至是函数-任何js类型都可以。
JSX看起来和HTML非常相似,但是,在使用JSX的时候还是有几点需要你注意的。
JSX允许你把其它组件拿来作为children,比如在IngredientsList组件中,我们渲染多次渲染另一个组件-Ingredient
<IngredientsList>
<Ingredient />
<Ingredient />
<Ingredient />
</IngredientsList>
className
由于class
在js中是一个保留字,咱们是不能再使用它了,所以我们用className来代替class,
<h1 className="fancy"> Baked Salmon </h1>
Js表达式
(Javascript Expression)Javascript 表达式被包裹在{}
中,它表示变量的值是需要计算的,比如,如果我们想在一个element中显示标题属性,我们就可以插入一个Javascript表达式,这个变量将计算后返回值。
<h1 >{this.props.title} </h1>
映射数组到JSX
(Mapping Arrays to JSX)JSX是Javascript,所以你可以在js函数中直接使用JSX,举个例子,你可以映射一个数组到JSX元素中去。
<ul>
{this.props.ingredients.map((ingredient, i) =>
<li key={i}>{ingredient}</li>
)}
</ul>
JSX看起来更舒服,但是不能被浏览器解释执行,所有的JSX必须被转换成createElement
或者factories
,幸运的是,这儿有一个非常优秀的工具来帮我们处理这个步骤:Babel
许多编程语言都允许用户编译自己的源码,js是一个解释性语言,不需要编译。可是现在许多浏览器还不支持ES6和ES7语法,并且没有一个浏览器支持JSX语法。因此,如果我们想使用js最新的特性和JSX,就需要一种方法来将ES6和JSX转换成低版本的语法,这个转换过程叫做transpiling,Babel就是用来干这种活的。
Babel是澳大利亚的一个叫做Sebastian McKenzie
的小伙子在高中的时候鼓捣出来的。第一个版本Babel的名字非常土,叫做6 to 5
,意思是把ES6的语法转换成ES5,后来随着项目的发展壮大,它目标是能够成为一个支持js全部的最新变化的一个平台platform。2015年2月项目改名为Babel后,更加的受人们欢迎了。
使用Babel的方法有许多,最方便的是直接在HTML中link
它。它会transpile那些含有text/babel
的js代码块。Babel会在运行时转换。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React Examples</title>
</head>
<body>
<div class="react-container"></div>
<script src="//fb.me/react-15.1.0.js"></script>
<script src="//fb.me/react-dom-15.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.29/browser.js"></script>
<script type="text/babel">
// JSX code here. Or link to separate JavaScript file that contains JSX.
</script>
</body>
</html>
To transpile code in the browser, use Babel v. 5.8. Using Babel 6.0+ will not work as an in-browser transformer.
这里还使用上一章的recipe的例子。下面的数组包含两个recipes,它们代表当前应用的状态。
var data=[
{
"name":"Baked Salmon",
"ingredients":[
{"name":"Salmon","amount":1,"measurement":"l lb"},
{"name":"Pine Nuts","amount":1,"measurement":"cup"},
{"name":"Butter Lettuce","amount":2,"measurement":"cups"},
{"name":"Yellow Squash","amount":1,"measurement":"med"},
{"name":"Olive Oil","amount":0.5,"measurement":"cup"},
{"name":"Garlic","amount":3,"measurement":"cloves"},
],
"steps":[
"Preheat the oven to 350 degrees.",
"Spread the olive oil around a glass baking dish.",
"Add the salmon, Garlic, and pine nuts to the dish",
"Bake for 15 minutes.",
"Add the Butternut Squash and put back in the oven for 30 mins.",
"Remove from oven and let cool for 15 minutes. Add the lettuce and serve."
],
},
{
"name":"Fish Tacos",
"ingredients":[
{"name":"Salmon","amount":1,"measurement":"l lb"},
{"name":"Pine Nuts","amount":1,"measurement":"cup"},
{"name":"Butter Lettuce","amount":2,"measurement":"cups"},
{"name":"Yellow Squash","amount":1,"measurement":"med"},
{"name":"Olive Oil","amount":0.5,"measurement":"cup"},
{"name":"Garlic","amount":3,"measurement":"cloves"},
],
"steps":[
"Cook the Fish on the Grill until Hot",
"Place the fish on the 3 tortillas",
"Top them with lettuce, tomatoes, and cheese"
]
}
];
数据the data被包含在两个js对象中的数组里面,每个对象包含recipe的名字,需要的ingredients列表,还有制作的步骤steps。
代码结构
//the Data,recipe中的一个数组
var data=[ ... ];
//为每个Recipe准备的一个无状态函数式组件
const Menu=(props)=>(
...
);
//ReactDOM.render,把Menu渲染到当前的DOM树中。
ReactDOM.render( <Menu recipes={data} title="Delicious Recipes" />,
document.getElementById('react-container'));
我们可以为两个组件创建一个UI,一个Menu组件来列出recipes,一个Recipe组件,展示每个recipe的UI。我们会传递数据到Menu组件中作为属性,属性名叫recipes。<Menu recipes={data} title="Delicious Recipes" />,
这个文件中,我们也使用ES6语法,所以当transipile转换的时候,Babel也会把ES6转换成浏览器可以解释执行的ES5语法。
const Menu= (props) =>
<article>
<header>
<h1>{props.title}</h1>
</header>
<div className="recipes">
</div>
</article>
Menu组件中直接用了JSX语法。这里一个文章的所有元素都是齐备的。一个标题element,一个<h1>
element,还有一个属性为recipes的div,在这个div中,我们要为每个recipe添加一个组件。
接下来把recipe data映射下
<div className="recipes">
{props.recipes.map((recipe,i)=>
<Recipe key={i} name={recipe.name}
ingredients={recipe.ingredients}
steps={recipe.steps} />
)}
</div>
为了显示出div中的元素,我们要用花括号添加js表达式,这个表达式会返回对应children的值,需要主要的是,我们要用这个唯一的key来识别每个元素
使用JSX扩展操作符
可以改进我们的代码,JSX扩展操作符
和ES7中的扩展操作符很像:
{props.recipes.map(recipe,i)=>
<Recipe key={i} {...recipe} />
)}
另一个可以用ES6改进Menu组件的地方是接收props参数。我们可以用对象的解构赋值来scope这个函数的properties variables.它可以让我们直接访问title和recipes variables,不用再给它们添加前缀了。
const Menu =({title,recipes})=>(
<article>
<header>
<h1>{title}<h1>
</header>
<div className="recipes">
{recipes.map((recipe,i)=>
<Recipe key={i} { ...recipe} />
)}
</div>
</article>
);
现在,为每个独立的recipe编写组件代码
const Recipe =({name,ingredients,steps})=>
<section id={name.toLowerCase().replace(//g,"-")}>
<h1>{name}</h1>
<ul className="ingredients">
{ingredients.map(ingredient,i)=>
<li key={i}> {ingredient.name}</li>
)}
<section className="Instructions">
<h2>Cooking Instructions</h2>
{steps.map(step,i)=>
<p key={i}> {step}</p>
)}
</section>
</section>
本例中,使用了函数参数解构赋值,它告诉函数,我们只使用对象的name,ingredients,steps这三个属性,可以让我们不用给这仨属性前面加props前缀了。
我们看到第一个js表达式被用来为root section设置id属性,它将recipes的name首字母转换为小写,并且用连字符连接,“Baked Salmon"会被换成“baked-salmon”.
这个应用的所有代码如下:
var data=[
{
"name":"Baked Salmon",
"ingredients":[
{"name":"Salmon","amount":1,"measurement":"l lb"},
{"name":"Pine Nuts","amount":1,"measurement":"cup"},
{"name":"Butter Lettuce","amount":2,"measurement":"cups"},
{"name":"Yellow Squash","amount":1,"measurement":"med"},
{"name":"Olive Oil","amount":0.5,"measurement":"cup"},
{"name":"Garlic","amount":3,"measurement":"cloves"},
],
"steps":[
"Preheat the oven to 350 degrees.",
"Spread the olive oil around a glass baking dish.",
"Add the salmon, Garlic, and pine nuts to the dish",
"Bake for 15 minutes.",
"Add the Butternut Squash and put back in the oven for 30 mins.",
"Remove from oven and let cool for 15 minutes. Add the lettuce and serve."
],
},
{
"name":"Fish Tacos",
"ingredients":[
{"name":"Salmon","amount":1,"measurement":"l lb"},
{"name":"Pine Nuts","amount":1,"measurement":"cup"},
{"name":"Butter Lettuce","amount":2,"measurement":"cups"},
{"name":"Yellow Squash","amount":1,"measurement":"med"},
{"name":"Olive Oil","amount":0.5,"measurement":"cup"},
{"name":"Garlic","amount":3,"measurement":"cloves"},
],
"steps":[
"Cook the Fish on the Grill until Hot",
"Place the fish on the 3 tortillas",
"Top them with lettuce, tomatoes, and cheese"
]
}
];
const Recipe = ({ name, ingredients, steps }) =>
<section id={name.toLowerCase().replace(/ /g, "-")}>
<h1>{name}</h1>
<ul className="ingredients">
{ingredients.map((ingredient, i) =>
<li key={i}>{ingredient.name}</li>
)}
</ul>
<section className="instructions">
<h2>Cooking Instructions</h2>
{steps.map((step, i) =>
<p key={i}>{step}</p>
)}
</section>
</section>
const Menu = ({ title, recipes }) => <article>
<header>
<h1>{title}</h1>
</header>
<div className="recipes">
{recipes.map((recipe, i) =>
<Recipe key={i} {...recipe} />
)}
</div>
</article>
ReactDOM.render(
<Menu recipes={data}
title="Delicious Recipes" />,
document.getElementById("react-container")
)
当运行这段代码的时候,浏览器会用我们的instructions和recipe data构建一个UI:
如果你使用的是谷歌的chrome浏览器,你可以装一个叫做React developer tools
的插件,可以让你看到目前的virtualDOM,方法就是打开js工具,选择React标签来查看VirtualDOM。
Babel 6把transformation分成几个叫做presets的模块,它要求工程师明确定义该transformation应该被哪个preset执行。目标就是让一切变得更加的模块化,以允许开发者自己决定哪些语法应该被转换,这个插件分成了几个类别,根据应用的需要选择使用。
bable-preset-es2015
把ES6弄成ES5
bable-preset-react
把JSX转换成React.createElement calls
Stage Presets
如果一个新特性准备放入ECMAScript规范的时候,它就从stage0变到stage4,Babel为每个stage准备了preset,你可以自由选择你应用中需要的stage
一旦我们决定在产品中使用React,有许多问题是需要你考虑的:怎么处理JSX和ES6+transformation?怎样管理我们的依赖?怎么优化image和css?
市面上有许多的工具来帮助我们处理这些问题,Browserify,Gulp,和Grunt,用的最多的是webpack。
除了处理transpiling ,它还可以处理:
代码分离
Code Spliting:可以把代码拆成几个部分,可以让你按需加载。它有的时候也叫rollups或者layers,目标是用来为不同的页面或者设备准备各自需求的代码压缩
Minification:删除代码中的空格,分割线,以减少代码体积。模块热替换
Hot Module Replacement(HMR):监视源代码的变动,只要模块更新,就立即做出变动。功能控制
Feature Flagging:当测试功能的时候,只把代码发送给部分,而不是全部。加载器是一个可以处理我们在构建程序过程中的代码的函数。假如你的程序中使用了ES6,JSX,CoffeeScript等这些不能被浏览器执行的语法时,我们通常会在webpack.config.js
文件中指明必要的loaders,来转换成浏览器可以使用的代码。
webpack有非常多的loaders,它们被分成了几个类别。其中最常用的一个情况是用加载器loader,从一种方言dialet转换成另一种。比如,bebel-loader把ES6和React代码进行transpiring。我们只需要在运行前指明文件的类型,剩下的webpack会处理。
另一类流行的loader是styling,对css文件进行处理。sass-loader会对.scss
后缀结尾的文件进行转换,把它转换为css文件,css-loader
用来在你的bundle中引入css模块,当css模块引入后会自动的去添加css文件,不需要使用连接元素包括样式表(No need to use link elements to include stylesheets.)
本章前面的recipes app还是有些不好的地方,我们在这儿用webpack来改善它。使用webpack的模块管理器(module bundler)有下面几点好处:
模块化(Modularity)
把程序中的一部分导出为commonJS的模块可以在以后让应用中的其它部分使用。它可以让开发者在开发时创建各自的独立文件进行开发,运行时合并为一个单独的文件从而使开发团队在大型应用的开发协作上变的更容易。
组合(composing)
通过模块,我们可以创建小的,简单,可复用的React组件,从而使后面在将模块组合到应用中时变的更为方便,小的组件让人易于理解,易于测试,易于复用,在需要改进应用时也易于替换。
快捷(Speed)
把应用所需的模块和依赖都打包进一个bundle会减少页面加载时间,多个文件会增加http请求。把所有的文件都打包到一个文件意味着客户端只需要发起一个请求就可以了,这样大大减少加载时间。
一致性(consistency)
因为webpack会把JSX ,React和ES6,甚至ES7,都transpiling
成统一的js代码,意味着我们今天可以使用明天的js语法,Babel
支持ES6和ES7,我们不用担心浏览器是否支持我们的代码,Webpack
会最终让我们的代码变成浏览器支持的代码,我们可以使用最前沿的js语法。
先看下目前的Recipe 组件:
const Recipe=({name,ingredients,steps}) =>
<section id ="baked-salmon">
<h1>{name}</h1>
<ul className="ingredients">
{ingredients.map((ingredient,i)=>
<li key={i}>{ingredient.name}</li>
)}
</ul>
<section className="instructions">
<h2>Cooking instructions</h2>
{steps.map((step,i)=>
<p key={i}>{step}</p>
)}
</section>
</section>
这个组件还是有点复杂的(doing quite a bit),我们显示(display)了recipe的名称(name),构建了一个ingredient
无序列表,以及在自己的paragraphp元素上display出每个step的说明(instruction)。
我们现在要做的就是把这个大的组件拆分为小的无状态函数式组件,然后在重新组合到一起。首先,把instructions变成无状态函数式组件,并且在一个单独的文件中创建一个模块来达到复用的目的。
const Instructions=({title,steps}) =>
<section className="ingredients">
<h2>{title}</h2>
{steps.map((s,i))=>
<p key={i}>{s}</p>
)}
</section>
module.exports=Instructions
这里我们创建了一个新的组件叫做instruction
,我们会把instruction
的title和steps传入组件中,这种方法可以让其它诸如Cooking Instructions","Baking Instructions"复用。
考虑下recipe中的ingredients组件,我们只是显示了ingredients的名称,但是data中每个ingredient还有amount,measurement这些className。我们可以创建一个无状态的函数式组件来表示单独的ingredient。
const Ingredient =({amount,measurement,name}) =>
<li>
<span className="amount">{amount}</span>
<span className="measurement">{measurement}</span>
<span className="nam">{name</span>
</li>
module.exports = Ingredient
这样的话,我们可以随时创建一个IngredientsList组件来显示我们需要的ingredient。
import Ingredient from './Ingredient'
const IngredientsList=({ list })=>
<ul className="ingredients">
{list.map((ingredient,i)=>
<Ingredient key={i} { ...ingredient} />
)}
</ul>
module.exports=IngredientsList
在这个文件中,我们导入了Ingredient组件,因为我们将在每个ingredient上使用它(because we are going to use it for each in。ingredients被传入一个叫做list的array中作为属性用,list数组中的每个ingredient都会被map映射到ingredient组件。JSX扩展操作符用来把ingredient的所有data传入组件,作为props。
给出一个有下面这些字段的ingredient
let ingredient ={
amount:1,
measurement:'cup',
name:'sugar'
}
扩展操作符
<Ingredient {...ingredient} />
和下面这两个是等价的
第一种:
<Ingredient amount={ingredient.amount}
measurement={ingredient.measurement}
name={ingrement.name} />
第二种:
<Ingredient amount={1}
measurement="cup"
name="sure" />
既然有了Ingredients组件和Instructions组件,我们可以把它们组合称recipe app 了
import IngredientsList from './IngredientsList'
import Instruction from './Instruction'
const Recipe =({name,ingredients,steps})=>
<section id={name.toLowerCase().replace(/ /g, '-')}>
<h1>{name}</h1>
<IngredientsList list={ingredients} />
<Instructions title="Cooking Instructions"
steps={steps} />
</section>
module.exports = Recipe
接下来的Menu组件和上面的写法差不多,
import Recipe from './Recipe'
export const Menu =({ recipes})=>
<article>
<header>
<h1>Delicious Recipes</h1>
</header>
<div className="recipes">
{recipes.map((recipe,i)=>
<Recipe key={i} {...recipe} />
)}
</div>
</article>
module.exports=Menu
我们还需要使用ReactDOM来渲染menu组件,因此要再创建一个main.js文件,
import React from 'react'
import {render} from 'react-dom'
import Menu from './components/Menu'
import data from './data/recipes'
window.React =React
render(
<Menu recipes={data}/>
document.getElementById('react-container')
)
上面代码头四条,是app工作的必须模块。这里不用标签引入,而是准备导入模块后用webpack来进行打包,我们也需要Menu组件,还有已经被移到独立模块内的sample 数据。它包两个recipe:Baked Salmon和Fash Tacos
我们所有的variable
对于Main.js
文件来说是局部变量,设置window.react
可以让React这个js库在浏览器中是全局的(expose the React library globally in the browser),这个调用方法可以保证React.createElement
能够正常工作。
当我们在渲染Menu组件的时候,我们传入recipe data这个数组到组件中作为属性.
既然我们已经把代码分离成单独的模块和文件了,现在就用webpack来处理下,把它们打包成单一文件吧,
首先,使用nodeJS的包管理工具npm来全局安装webpack
$ sudo npm install -g webpack
webpack还要使用Babel来转换JSX和ES6的语法,我们将会使用几个预置的加载器来完成这个工作。
$ sudo install babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
我们的程序使用React和ReactDOM,我们已经用script标签加载了这些依赖,现在,我们准备让webpack来添加它们,我们需要本地安装:
$ sudo npm install react react-dom
这两个文件会在存放当前目录下的node_nodules
文件夹中。现在一切已经准备的差不多了。
要让这个模块话的recipe app运行的话,我们需要告诉webpack怎么把我们的源代码打包成一个单独的文件,需要在webpack.config.js
中进行设置。
app的入口文件是main.js
,它导入react,ReactDOM,和Menu.js。这些正是我们想要在浏览器中运行的文件,webpack一旦发现import语句时,就会从电脑上寻找这个文件,并把它打包。Main.js导入Menu.js,Menu.js导入Recipe.js,Recipe.js导入Instructions.js和IngredientsList.js。webpack会沿着导入语句把这些必需的模块打包。
ES6 import语句
我们使用的import语句目前并不被大多数浏览器支持,它之所以可以工作是因为Bable会把它转换为require("module")
语句。
webpack开始bundle打包时,我们需要告诉webpack把JSX,ES6转换下,我们的build过程需要3个步骤:
webpack像另一个模块一样,exports为js的literal object,告诉webpack怎么做。这个文件应保存在root目录。
module.exports={
entry:"./main.js",
output:{
path:"dist/assets",
filename:"bundle.js",
},
module:{
loaders:[
{
test:/\.js$/,
exclude:/(node_module)/,
loader:['babel'],
query:{
preset:['es2015','react']
}
}
]
}
}
注意到loader字段是一个数组,这是因为webpack有非常多的加载器,这里我们只用了babel。
在app部署到server之前创建打包文件,因为webpack是全局安装的,所以你可以在命令行运行:
$ webpack
成功后会出现一个bundle.js文件,失败的话会有错误提示,一般情况下失败都是import语句有问题,如果你出现问题了,看下import语句和路径是否有问题。
现在有了Bundle
文件了,在dist
目录下。这个文件夹包含我们想要在web服务上运行的所有文件,dist
文件夹也是index.html
放的地方。这个index.html
应该有一个div元素,存放React Menu组件,还需要一个<script>
引入我们的bundle.js
文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <title>React Flux Recipes</title> </head>
<body>
<div id="react-container"></div>
<script src="/assets/bundle.js"></script> </body>
</html>
这就是app的首页,它会从一个文件中加载所需要的一切(will load everything it needs from one file):一个HTTP请求,一个bundle.js。你需要把这些文件部署到web服务器上。web服务器可以是node或者ruby on rails搭建的。
把我们的代码打包成一个文件的过程中可能会产生很多问题,在浏览器中调试bug的话,我们可以通过提供一个source map
来排除问题。source map把bundle和原始的source文件映射起来。只需要在webpack.config.js
中添加几行代码就行了:
module.exports={
entry:"./main.js",
output:{
path:"dist/assets",
filename:"bundle.js",
//add sourceMapFilename:'bundle.map'
sourceMapFilename:'bundle.map'
},
//add '#source-map'
devtool:'#source-map',
module:{
loaders:[
{
test:/\.js$/,
exclude:/(node_module)/,
loader:['babel'],
query:{
preset:['es2015','react']
}
}
]
}
}
给‘#source-map'设置devtool属性可以告诉webpack我们想要使用source-mapping
, sourceMapFilename
也是必须要有的,通常在依赖设置好以后指定这个source map
文件,webpack会在export的时候把bundle文件
和source map
关联起来。
再次运行webpack,你就会发现导出了两个文件:原始的bundle.js
和bundle.map
source.map可以让我们使用原始的source文件进行调试bug,在浏览器开发中工具面板的source面板中,你会发现一个名为webpack://
的文件夹,在这个文件夹中,你会看到在你bundle中的所有源文件
可以从这些文件中一个个的进行调试,在任一行添加一个breakpoint,刷新浏览器js会在你设置的断点处暂停一下,你可以在scopes面板中检查变量的作用域,或者在watch面板添加变量。
现在的bundle仍旧是一个简单的text文件,所以减少文件中的text就会缩小文件的size,从而使页面加载速度变快。去掉空格,把变量名缩短,去掉没用的空行都可以减少体积。
webpack有一个内置插件Uglify,可以用来处理这个过程,首先,要进行locally本地安装webpack:
$ npm install webpack
使用webpack的插件让我们可以添加额外的步骤来build process,在这个例子中,我们就准备添加一个步骤来压缩代码体积。
var webpack = require("webpack")
module.exports={
entry:"./main.js",
output:{
path:"dist/assets",
filename:"bundle.js",
//add sourceMapFilename:'bundle.map'
sourceMapFilename:'bundle.map'
},
//add '#source-map'
devtool:'#source-map',
module:{
loaders:[
{
test:/\.js$/,
exclude:/(node_module)/,
loader:['babel'],
query:{
preset:['es2015','react']
}
}
]
},
plugins:[
new webpack.optimize.UglifyJsPlugin({
sourceMap:true,
warnings:false,
mangle:true,
})
]
}
使用uglify
插件需要require这个webpack,这就是为什么我们局部安装webpack的原因,我们可以添加任意个步骤来用插件来处理简化代码体积。
UglifuJsPlugin
是一个函数,它从自己的参数中得到instruction
(gets instruction from it's arguments),一旦我们uglify代码之后,代码就会变得不可读了,我们需要一个source map
,所以source map
设置为true。把warnings
为false会在打包时忽略掉控制台错误,mangle:true
会把long variable names名称较长的变量比如recipe或者ingredients转成一个单字符的名称(to a single letter)
下次运行webpack的时候,你会发现bundle打包的文件体积已经减少了,并且不再能够识别(空格都去掉了嘛)。包含一个source map可以让你从source那里进行bug调试。