SegmentFault Primo Javascript最新的文章
2017-10-30T20:42:06+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
使用Echarts3实现渐变仪表盘需求
https://segmentfault.com/a/1190000011783585
2017-10-30T20:42:06+08:00
2017-10-30T20:42:06+08:00
primo
https://segmentfault.com/u/zpdongdong93
17
<h2>Echarts 仪表盘实践</h2>
<p>项目过程中遇到一个这样的需求:</p>
<p><img src="/img/bVXBAU?w=249&h=153" alt="图片描述" title="图片描述"></p>
<p>这明显是一个仪表盘类型的图表,打开echarts的官方文档,可以看到有一个默认的实现,如下:</p>
<p><img src="/img/bVXBAZ?w=337&h=262" alt="图片描述" title="图片描述"></p>
<p>使用了默认的参数</p>
<pre><code class="javascript">option = {
tooltip : {
formatter: "{a} <br/>{b} : {c}%"
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '业务指标',
type: 'gauge',
detail: {formatter:'{value}%'},
data: [{value: 50, name: '完成率'}]
}
]
};</code></pre>
<p>分析需求后,我们从以下几个方面入手</p>
<h3>轴线类别</h3>
<p>从第一张图我们可以看出,需求中的轴线不是连续的,而是被分割成了一个个的长条形状。</p>
<p>从官方示例来看,轴线被白色的刻度分成了很多小段,如果刻度的宽度变大,刻度变密集的话是可以达到我们想要的效果的</p>
<pre><code class="javascript">option = {
...
series: [
{
name: '业务指标',
type: 'gauge',
// 去掉多余的分段
splitNumber: 1,
axisLine: {
lineStyle: {
width: 20
}
},
splitLine: {
show: false
},
axisTick: {
// 刻度长度与轴线宽度一致,达到分隔的效果
length: 20,
// 增加刻度密度
splitNumber: 100,
lineStyle: {
// 增加刻度宽度
width: 3
}
},
detail: {formatter:'{value}%'},
data: [{value: 50, name: '完成率'}]
}
]
};</code></pre>
<p>经过这样修改的话,确实初步达到了我们要的效果。</p>
<p><img src="/img/bVXBA4?w=293&h=260" alt="图片描述" title="图片描述"></p>
<p>但是仔细看的话,会发现一个问题,指针的指向是空白处。原因就是空白的地方是刻度,而有颜色的地方是轴线。<br>这样的话最终指针指向的数据是不准确的,而且这个方案还有一个问题就是渐变颜色的处理。</p>
<pre><code class="javascript">[[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']]</code></pre>
<p>官方提供的接口是分段颜色,想要做成渐变还不是很好处理。</p>
<p>接下来呢,考虑第二种实现方式</p>
<p>首先,轴线肯定是连续的,那我先把轴线隐藏掉,然后刻度加粗,拉长</p>
<pre><code class="javascript">option = {
...
series: [
{
name: '业务指标',
type: 'gauge',
splitNumber: 1,
axisLine: {
lineStyle: {
width: 20,
// 透明度设置为0
opacity: 0
}
},
splitLine: {
show: false
},
axisTick: {
length: 20,
splitNumber: 100,
lineStyle: {
width: 3,
// 给点颜色
color: '#555'
}
},
detail: {formatter:'{value}%'},
data: [{value: 50, name: '完成率'}]
}
]
};</code></pre>
<p><img src="/img/bVXBA6?w=305&h=242" alt="图片描述" title="图片描述"></p>
<p>可以看到效果有了,而且指针位置正确。</p>
<h3>渐变颜色</h3>
<p>需求中轴线的颜色是渐变的,但是文档中给定的接口是分段式的颜色,没有办法使用,再者轴线透明度已经被设置为0了。</p>
<p>所以只能从刻度的颜色入手。</p>
<p>官方文档中,刻度的颜色是如下这样的:</p>
<pre><code class="javascript">// 线性渐变,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,如果 globalCoord 为 `true`,则该四个值是绝对的像素位置
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'red' // 0% 处的颜色
}, {
offset: 1, color: 'blue' // 100% 处的颜色
}],
globalCoord: false // 缺省为 false
}
// 径向渐变,前三个参数分别是圆心 x, y 和半径,取值同线性渐变
color: {
type: 'radial',
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0, color: 'red' // 0% 处的颜色
}, {
offset: 1, color: 'blue' // 100% 处的颜色
}],
globalCoord: false // 缺省为 false
}
// 纹理填充
color: {
image: imageDom, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
repeat: 'repeat' // 是否平铺, 可以是 'repeat-x', 'repeat-y', 'no-repeat'
}</code></pre>
<p>默认支持两种渐变,线性和径向渐变,从效果上看都不符合我们的要求:线性是直线方向的渐变,而径向渐变是由内而外的。即使可以勉强实现,效果肯定不好。<br>所以可以尝试一下使用图片纹理。</p>
<p>首先用PS画一个和画布一样大小的渐图案</p>
<p><img src="/img/bVXBBb?w=240&h=240" alt="图片描述" title="图片描述"></p>
<p>在配置中使用image选项</p>
<pre><code class="javascript">option = {
...
series:[{
...
axisTick: {
length: 20,
splitNumber: 100,
lineStyle: {
color: {
image: document.getElementById('linear-pic'),
repeat: 'no-repeat'
},
width: 3
}
}
}]</code></pre>
<p>这样项目中的需求就可以完美解决了</p>
<p><img src="/img/bVXBBf?w=202&h=157" alt="图片描述" title="图片描述"></p>
<h3>颜色分段</h3>
<p>颜色渐变完成了,看一下效果的话,会发现有一个明显的问题。需求中指针指向的位置之前的刻度是有渐变颜色的,后面一段则都是灰色。<br>而我们现在仪表盘无论指向哪里,刻度都是有颜色的。</p>
<p>在解决这个问题的过程中,想了很多方案,使用遮罩、修改渐变图片等等,都不能很好的解决问题。最后突然想起来一个配置项中可以使用多个仪表盘的,<br>我只要在数据前半段使用带渐变色的仪表盘,后半段全部用灰色的仪表盘补充,这样就可以解决问题。</p>
<p>这里还需要注意以下两点:</p>
<ol>
<li>由于仪表盘的值是动态的,所以每个仪表盘的开始结束位置、刻度的个数都要根据值来计算</li>
<li>由于有两个仪表盘,最好把内容部分全部都写在一个上,另外一个确保只有轴线部分,避免出现重叠等问题</li>
</ol>
<p>代码如下:</p>
<pre><code class="javascript">calculateOption: function (params) {
var offsetAngle = -35;
var totalAngle = 250;
var split = 75;
var series = [];
var asisWidth = 11;
var fontSize = 30;
// Defaults
params = $.extend({
min: 0,
max: 100,
value: 0,
name: 'DOWNLOAD SPEED',
type: 'gauge',
data: [{
value: 0,
name: ''
}]
}, params);
var startAngle = totalAngle + offsetAngle;
var endAngle = startAngle - Math.floor((parseInt(params.value, 10) / (params.max - params.min)) * totalAngle);
series.push({
name: params.name,
type: params.type,
startAngle: startAngle,
endAngle: endAngle,
splitNumber: 1,
// 轴线样式
axisLine: {
show: false,
lineStyle: {
width: asisWidth,
opacity: 0
}
},
// 分段样式
splitLine: { show: false },
// 刻度样式
axisTick: {
length: asisWidth,
splitNumber: Math.floor((params.value / (params.max - params.min)) * split),
lineStyle: {
color: {
image: $('#xx')[0],
repeat: 'no-repeat'
},
width: 2
}
},
axisLabel: { show: false },
pointer: { show: false },
// 指针样式
itemStyle: {},
title: {
fontSize: 8,
offsetCenter: [0, '-35%'],
color: '#999'
},
detail: {
color: '#36444b',
fontSize: fontSize,
offsetCenter: [0, '20%'],
formatter: function (val) {
return val.toFixed(2) + '\n{unit|Mbps}'
},
rich: {
unit: {
fontSize: 10,
color: '#999',
lineHeight: 30
}
}
},
data: [{
value: params.value,
name: params.name
}]
});
series.push({
name: '',
type: params.type,
startAngle: endAngle,
endAngle: offsetAngle,
splitNumber: 1,
axisLine: {
show: false,
lineStyle: {
width: asisWidth,
opacity: 0
}
},
splitLine: { show: false },
axisTick: {
length: asisWidth,
splitNumber: split - Math.floor((params.value / (params.max - params.min)) * 80),
lineStyle: {
color: '#999',
width: 2
}
},
axisLabel: { show: false },
pointer: { show: false },
// 指针样式
itemStyle: {},
title: { show: false },
detail: { show: false }
});
return series;
}</code></pre>
<p>效果如下:</p>
<p><img src="/img/bVXBBi?w=202&h=165" alt="图片描述" title="图片描述"></p>
<h3>指针类型</h3>
<p>最后,我们需要做的就是把指针改为需求中的样子,本来我以为这个应该是最简单的部分,看完官方文档后发现并没有修改指针的接口。</p>
<pre><code class="javascript">{
color: 'auto',
borderColor: '#000',
borderWidth: 0,
borderType: 'solid',
shadowBlur: ...,
shadowColor: ...,
shadowOffsetX: 0,
shadowOffsetY: 0,
opacity: ...
}</code></pre>
<p>如上,指针配置项应该是没有办法实现类似刻度的样子。</p>
<p>目前还在实验中,考虑使用<code>markline</code>画一条指针,是否可行还有待验证。</p>
Javascript内置对象新增接口列表
https://segmentfault.com/a/1190000011551722
2017-10-14T10:54:52+08:00
2017-10-14T10:54:52+08:00
primo
https://segmentfault.com/u/zpdongdong93
0
<p>网上很少有提供不同版本接口对比的文章,所以自己总结一下。</p>
<h2>Array</h2>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Modify</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>concat</td>
<td>连接多个数组,返回数组副本,参数可以为值或数组</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>join</td>
<td>把数组元素组合为字符串</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>pop</td>
<td>删除并返回最后一个元素</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>push</td>
<td>向数组末尾添加一个或多个值,返回数组长度</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>reverse</td>
<td>反转数组元素,修改原数组</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>shift</td>
<td>删除并返回第一个元素</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>slice</td>
<td>返回某一个范围的新数组,包含开始不包含结束</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>sort</td>
<td>对原数组排序</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>splice</td>
<td>从指定位置添加或删除元素</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>toString</td>
<td>与join无参数返回值一致(逗号分隔)</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>toLocaleString</td>
<td>返回本地字符串</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>unshift</td>
<td>向数组头部添加一个或多个值,返回数组长度</td>
<td align="center">是</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>valueOf</td>
<td>返回数组对象的原始值</td>
<td align="center">否</td>
<td align="center">ES3</td>
</tr>
</tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Modify</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>every</td>
<td>所有项符合条件</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>filter</td>
<td>过滤数组</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>forEach</td>
<td>遍历数组,回调参数为va lue,index,array</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>indexOf</td>
<td>返回索引值</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>lastIndexOf</td>
<td>返回索引值,从末尾查找</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>map</td>
<td>映射为新数组,回调参数为value,index,array</td>
<td align="center">是</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>reduce</td>
<td>对数组进行化简</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>reduceRight</td>
<td>反向化简数组</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
<tr>
<td>some</td>
<td>某些项符合条件</td>
<td align="center">否</td>
<td align="center">ES5</td>
</tr>
</tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Modify</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>copyWithin</td>
<td>在数组内部,将指定位置的成员复制到其他位置</td>
<td align="center">是</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>fill</td>
<td>使用给定的值填充数组</td>
<td align="center">是</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>find</td>
<td>返回第一个符合条件的值</td>
<td align="center">否</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>findIndex</td>
<td>返回第一个符合条件的值的索引</td>
<td align="center">否</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>Array.from</td>
<td>把类数组对象和可遍历对象转化为数组</td>
<td align="center">-</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>Array.of</td>
<td>将一组值转化为数组</td>
<td align="center">-</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>keys</td>
<td>遍历数组的索引</td>
<td align="center">否</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>values</td>
<td>遍历数组的值</td>
<td align="center">否</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>entries</td>
<td>遍历数组的键值对</td>
<td align="center">否</td>
<td align="center">ES6</td>
</tr>
</tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Modify</th>
<th align="center">Version</th>
</tr></thead>
<tbody><tr>
<td>includes</td>
<td>判断数组中是否包含某个值</td>
<td align="center">否</td>
<td align="center">ES7</td>
</tr></tbody>
</table>
<h2>String</h2>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>charAt</td>
<td>返回在指定位置的字符</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>charCodeAt</td>
<td>返回在指定的位置的字符的 Unicode 编码</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>concat</td>
<td>连接字符串</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>fromCharCode</td>
<td>从字符编码创建一个字符串</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>indexOf</td>
<td>检索字符串的索引</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>lastIndexOf</td>
<td>反向检索字符串的索引</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>match</td>
<td>找到一个或多个正则表达式的匹配</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>replace</td>
<td>替换字符串</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>search</td>
<td>检索字符串</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>slice</td>
<td>提取字符串的片断</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>split</td>
<td>把字符串分割为字符串数组</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>substr</td>
<td>从起始索引号提取字符串中指定数目的字符</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>substring</td>
<td>提取字符串中两个指定的索引号之间的字符</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>toLowerCase</td>
<td>把字符串转换为小写</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>toUpperCase</td>
<td>把字符串转换为大写</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>toString</td>
<td>返回字符串</td>
<td align="center">ES3</td>
</tr>
<tr>
<td>valueOf</td>
<td>返回原始值</td>
<td align="center">ES3</td>
</tr>
</tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Version</th>
</tr></thead>
<tbody><tr>
<td>trim</td>
<td>去除字符串前后的空格</td>
<td align="center">ES5</td>
</tr></tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>codePointAt</td>
<td>返回对应字符的码点(能正确处理4个字节存储的字符,对应charCodeAt)</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>fromCodePoint</td>
<td>从码点返回对应字符</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>at</td>
<td>返回对应位置的字符(能正确处理大于0xFFFF的字符,对应charAt)</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>normalize</td>
<td>将字符的不同表示方法统一为同样的形式</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>includes</td>
<td>查找字符串</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>startsWith</td>
<td>判断查询字符串是否在头部</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>endsWith</td>
<td>判断查询字符串是否在结尾</td>
<td align="center">ES6</td>
</tr>
<tr>
<td>repeat</td>
<td>重复n次原字符串</td>
<td align="center">ES6</td>
</tr>
</tbody>
</table>
<table>
<thead><tr>
<th>Method</th>
<th>Description</th>
<th align="center">Version</th>
</tr></thead>
<tbody>
<tr>
<td>padStart</td>
<td>头部补全字符串</td>
<td align="center">ES8</td>
</tr>
<tr>
<td>padEnd</td>
<td>尾部补全字符串</td>
<td align="center">ES8</td>
</tr>
</tbody>
</table>
Webpack CommonsChunkPlugin 理解
https://segmentfault.com/a/1190000011526050
2017-10-12T15:38:34+08:00
2017-10-12T15:38:34+08:00
primo
https://segmentfault.com/u/zpdongdong93
7
<h2>CommonsChunkPlugin配置简介</h2>
<p>最近读了一下webpack的文档,读到CommonsChunkPlugin这个插件,深深折服于webpack的强大,同时也产生了一些自己的疑问。</p>
<p>首先,CommonsChunkPlugin这个插件是用来提取公共代码的,通过将公共模块提取出来,只在页面加载的时候引入一次,提升应用的加载效率。</p>
<p>顺便提一下,chunk其实就是代码块的意思,可能是一个或多个模块,一般提取后就是一个js文件。</p>
<p>CommonsChunkPlugin有中文翻译的文档,但是感觉并不是很通顺,英文文档看完也有一些疑惑,比如minChunks到底是做什么用的,怎么用?chunks是什么?</p>
<h3>配置项</h3>
<p>首先贴一下文档。</p>
<pre><code>{
name: "string",
names: "string[]",
filename: "string",
minChunks: "number|Infinity|function(module, count) -> boolean",
chunks: "string[]",
children: "boolean",
async: "boolean|string",
minSize: "number"
}</code></pre>
<ul>
<li>name和names:chunk的名称,如果这个chunk已经在<code>entry</code>中定义,该chunk会被直接提取;如果没有定义,则生成一个空的chunk来提取其他所有chunk的公共代码。</li>
<li>filename:可以指定提取出的公共代码的文件名称,可以使用<code>output</code>配置项中文件名的占位符。未定义时使用<code>name</code>作为文件名。</li>
<li>chunks:可以指定要提取公共模块的源chunks,指定的chunk必须是公共chunk的子模块,如果没有指定则使用所有<code>entry</code>中定义的入口chunk。</li>
<li>
<p>minChunks:在一个模块被提取到公共chunk之前,它必须被最少<code>minChunks</code>个chunk所包含(通俗的说就是一个模块至少要被<code>minChunks</code>个模块所引用,才能被提取到公共模块。)。minChunks参数有三点需要说明:</p>
<ol>
<li>该数字必须不小于2或者不大于chunks的个数。默认值等于chunks的个数。</li>
<li>如果指定了<code>Infinity</code>,则创建一个公共chunk,但是不包含任何模块,内部是一些webpack生成的runtime代码和chunk自身包含的模块(如果chunk存在的话)。</li>
<li>用户也可以定制自己的逻辑去生成代码。</li>
</ol>
</li>
<li>minSize:表示公共chunk创建所需要的所有模块的最小体积。</li>
<li>async:如果设置为true,一个异步的公共chunk将会作为<code>options.name</code>的子块和<code>options.chunks</code>的兄弟块被创建。该chunk会与<code>options.chunks</code>并行加载。你也可以使用该参数指定输出的文件名。</li>
<li>children:如果设置为true,公共chunk的所有子模块将会被选中。</li>
</ul>
<h3>例子</h3>
<p>我们看一个简单的例子。</p>
<pre><code class="javascript">module.exports = {
entry: {
app: './src/index.js',
vender: [
'lodash',
'otherlib'
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vender'
})
],
output: {
// 使用Hash来命名文件,实现文件缓存的功能。当文件内容发生变化,文件名会随之改变。
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};</code></pre>
<p>上面的代码中定义了两个入口,app和vender(公共库),plugins中使用CommonsChunkPlugin提取vender。</p>
<p>vender是我们提取出来的公共chunk,通常不会被修改,所以理应在每次编译后文件名保持一致。然而,我们尝试修改入口文件index.js会发现,vender的文件名会发生变化。</p>
<p>原因呢上面提到过,由于每次编译会导致vender的module.id发生变化,内部的runtime代码随之发生改变。</p>
<p>解决方案有以下几种:</p>
<ol>
<li>使用NamedModulesPlugin插件,用文件路径而非默认的数字ID来作为模块标识。</li>
<li>使用HashedModuleIdsPlugin插件,用相对路径的Hash值来作为模块标识。推荐在生产环境中使用。</li>
<li>将runtime部分的代码提取到一个单独的文件中,代码如下。</li>
</ol>
<pre><code class="javascript">module.exports = {
entry: {
app: './src/index.js',
vender: [
'lodash'
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vender',
minChunks: Infinity
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vender']
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};</code></pre>
<p>代码中再次使用了CommonsChunkPlugin,从vender中提取出了名为manifest的运行时代码。</p>
<h2>分析Vue的使用方式</h2>
<p>Vue在production模式中使用如下配置</p>
<pre><code class="javascript">// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
})</code></pre>
<h4>自定义minChunks</h4>
<p>minChunks配置项有两个参数,module为当前要提取的源chunk中所包含的模块,count表示模块的个数。<br>自定义函数会被循环调用,直到遍历完所有模块。</p>
<p>module.resource为模块的绝对路径,所以这段代码判断了模块是否在node_modules下,是的话则打包到vender中。</p>
<p>后面一个CommonsChunkPlugin从vender中提取了运行时代码,避免每次打包vender的Hash值都发生变化导致缓存无效。</p>
<p>如有问题,欢迎指正。</p>