使用webpack提升vue应用的4种方式

时间: 2017-11-27阅读: 1913标签: vue
译者注:本篇文章所提到的几个措施大家可能都曾经在项目里用过,但是就如作者所言:你只是在用,并不知道为什么用,本文最大的价值在于提供了系统的优化方案并解释了原因

webpack是开发vue单页应用必不可少的工具,它能管理复杂的构建步骤,并且优化你的应用大小和性能, 使你的开发工作流更加简单。在这篇文章中,我将解释使用webpack提升你的vue应用的4种方式,包括:

单文件组件
优化Vue构建过程
浏览器缓存管理
代码分离


关于vue-cli

如果你在使用 vue-cli 提供的模板来构建你的应用,那么webpack的相关配置已经提供好了,这些配置已经经过很好地优化,我也给不了你其他的优化建议了。

不过因为配置是开箱即用的,所以你很有可能并不知道这些配置真正在做什么,由于 vue-cli 里提供了我将要讨论的优化措施,所以,你可以把这篇文章当做模板里webpack配置的概述。

1.单文件组件

Vue的特点之一就是使用了基于html的模板组件,这带来了一个本质问题:要么html标记使用丑陋的Java字符串,要么将模板内容和组件定义写在不同的文件中。这带来了一些困难。

Vue提供了一种叫做Single File Components(SFCs)的方式来解决这个问题,将模板、组件定义、css写在一个 .vue 文件里。

MyComponent.vue

<template>
<div id="my-component">...</div>
</template>
<>
exportdefault{...}
</>
<style>
#my-component {...}
</style>


Vue-loader 使得 SFCs成为可能,这个 webpack loader 将SFCs分隔成不同语言块,然后输出到合适的loader,例如 块 输出到babel-loader, 模板块输出到Vue自己的vue-template-loader,该loader能够将模板转换成Java的render函数

vue-loader的最终输出是一个将要包含在 Webpack bundle 中的Java模块。

典型的vue-loader配置如下所示:

module:{
rules:[
{
test:/.vue$/,
loader:'vue-loader',
options:{
loaders:{
// Override the default loaders
}
}
},
]
}


2.优化Vue构建

运行时构建

如果在你的应用中仅仅使用 render函数,不需要HTML模板,那你不需要使用Vue的模板编译器,通过去掉模板编译器,可以让你在Webpack构建过程中,减少bundle 的体积。

记住单文件组件在开发模式中使用了预编译

Vue的运行时构建版本包含了Vue的所有特点,除了模板编译器,被称为vue.runtime.js,体积比全功能版本小了20KB,所以这值得你尝试一下。

默认情况下使用的是运行时构建版本,所以当你使用 import vue from 'vue' 来引用Vue的时候,你得到的是运行时构建版本,不过你能通过 alias 配置项来改变。

resolve:{
 alias:{
  'vue$':'vue/dist/vue.esm.js'// Use the full build
 }
}


译者注:在Vue模块中包含8个文件,各文件的区别可以参考:官方文档,在需要使用完整版时使用了运行时版本会报warn:

You are using the runtime-only build of Vue where the template option is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

production环境中去掉 warn 和 error 信息

另外一个减少Vue构建体积的方式是在 production环境中去掉所有 error 和 warn信息,这些不必要的代码导致你打包后的体积膨胀,而且增加了运行时耗时,你最好避免这些消耗。

如果你调试Vue的源代码,你会发现这些提示信息都是通过环境变量 process.env.NODE_ENV 的值来判断的,例如:

if(process.env.NODE_ENV !=='production'){
 warn(("Error in "+info +": ""+(err.toString())+"""),vm);
}


如果 process.env.NODE_ENV 的值设置成 production ,那么提示信息在构架过程中就会自动被剔出去。

可以通过使用 DefinePlugin 去设置 process.env.NODE_ENV 的值,同时使用 UglifyJsPlugin 去减小代码体积并且去掉不需要的代码块。

if(process.env.NODE_ENV ==='production'){
module.exports.plugins =(module.exports.plugins ||[]).concat([
newwebpack.DefinePlugin({
'process.env':{
NODE_ENV:'"production"'
}
}),
newwebpack.optimize.UglifyJsPlugin()
])
}


译者注:实际项目中使用的更多的方式是 production环境 和 其他环境 使用不同的webpack配置文件.

3.浏览器缓存管理

浏览器能够缓存你的站点文件,只有在你本地没有副本时或者副本已经过期时才会重新下载。

如果你所有的代码都在一个文件里,那一个微小的改动也会导致整个文件的下载,理想情况下,你想要你的用户尽可能少的下载文件,所以将频繁改动的代码和不怎么改动的代码分开是非常明智的。

Vendor file

Common Chunks插件能把你的Vendor代码(例如Vue.js这些不会经常改动的依赖包)和应用代码(每次开发过程中都会改动的代码)分离开。

你能配置插件检查一个依赖是否来自于node_modules,如果是,那就打包到vendor.js 文件。

newwebpack.optimize.CommonsChunkPlugin({
name:'vendor',
minChunks:function(module){
returnmodule.context &&module.context.indexOf('node_modules')!==-1;
}
})


这么做之后,在构建后的输出文件中,将有两个独立的文件,能够分别被浏览器缓存。

< src="vendor.js"charset="utf-8"></>
< src="app.js"charset="utf-8"></>


指纹

当构建后的文件改动了,我们该怎么丢弃缓存呢?

默认情况下,只有当一个缓存文件过期,或者用户手动清除缓存,浏览器才会重新从服务器请求文件,如果服务器提示文件已经改动,那文件才会重新被下载(如果返回304则不会)。

为了避免不必要的请求,我们可以在每次文件内容改动时,改变文件的名字,从而强制浏览器重新下载,通过在文件名称后面添加一个"指纹":hash,我们可以非常容易达到这个目的。


Common Chunks插件生成"chunkhash",能随着文件的改动而更新,Webpack能在输出时,将这个hash值添加到文件名称末尾。

output:{
filename:'[name].[chunkhash].js'
},


这样做的话,你会发现输出的文件名称类似于app.3b80b7c17398c31e4705.js。

译者注:chunkhash并不需要Common Chunks生成,而是webpack自动生成的,而且据官方文档,Common Chunks是无法生成chunkhash的,作者在这里这么写让我摸不着头脑, 另外,还有一种添加hash值的方式是使用

output:{
filename:'[name].[hash].js'
},


其中的区别主要在于chunkhash是基于内容生成的hash值,而hash值是基于模块标识(webpack打包时每个模块都有一个唯一标识),hash值的主要问题在于任何一个文件更新之后都会更新hash值,导致那些内容没有更新的文件的文件名也更新了,需要重新下载。具体区别可参考:webpack配置:缓存。

自动插入构建文件

当然了,增加了hash值之后,你就必须要在index文件里更新你的引用,否则浏览器是不会知道的。

< src="app.3b80b7c17398c31e4705.js"></>


手动去做这件事将是一件非常沉闷无聊的事情,可以使用HTML Webpack Plugin来做这件事。这个插件能在构建过程中自动在你的HTML文件里插入对构建文件的引用。

先来把构建文件中的引用去掉

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test-6</title>
</head>
<body>
<div id="app"></div>
<!--built files should go here,but will be auto injected -->
</body>
</html>


然后在Webpack配置里增加HTML Webpack Plugin 的配置。

newHtmlWebpackPlugin({
filename:'index.html'
template:'index.html',
inject:true,
chunksSortMode:'dependency'
})


现在带有hash值的构建文件将会自动增加到index文件,同时,你的index.html文件也会被包含在输出文件里,所以你可能需要将这一点告诉服务器。

4.代码分离

默认情况下,Webpack将把你的所有应用代码输出到一个大的构建文件中,但是如果你有多个页面,分隔代码将每个独立的页面输出到不同的文件中,只有在需要的时候才去加载。

Webpack有个功能 "code splitting",可以用来做这件事,在Vue.js中需要使用async components,配合Vue Router使用更简单。

Async componets

相比以一个定义对象作为第二个参数,Async components第二个参数是一个Promise函数,该函数将一个对象resolve,例如:

Vue.component('async-component',function(resolve,reject){
setTimeout(()=>{
resolve({
// Component definition including props, methods etc.
});
},1000)
})


Vue只有在这个组件需要被渲染时,才会调用这个函数,同时也会为以后的预渲染缓存返回结果。

如果我们将每个页面都当做一个组件,并且将定义对象放在服务器端,那在代码分离的路上,我们已经走了一半了。

require

为了从服务器上加载你的异步组件代码。使用Webpack的require语法,这将通知Webpack将async-component打包到一个分隔的bundle,更妙的是,Webpack将使用AJAX处理bundle的加载,所以你的代码可以像下面这样简单:

Vue.component('async-component',function(resolve){
require(['./AsyncComponent.vue'],resolve)
});


懒加载

在Vue.js应用中,vue-router是一个典型模块,你可以用它来将SPA转换成多页应用,懒加载是利用Vue和Webpack实现代码分离的官方推荐方式。

constHomePage =resolve =>require(['./HomePage.vue'],resolve);
constrounter =newVueRouter({
routes:[
{
path:'/',
name:'HomePage',
component:HomePage
}
]
})


关于本文

译者:@孙辉
作者:@ANTHONY GORE
原文:http://vuejsdevelopers.com/2017/06/18/vue-js-boost-your-app-with-webpack


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/174

vue 自定义指令

接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。但有一些是没有相对应的指令进行操作。在这里以progress(h5的新标签进度条)为例,向大家介绍Vue的一个用于指令扩展的方法:directive(自定义指令)。

Vue组件中prop属性使用说明

props 把数据传给子组件!prop是组件数据的一个字段,期望从父作用域传下来。子组件需要显式地用 props 选项。props的大小写、静态的和动态的 Prop、传入一个数字、传入一个布尔值、Vue的组件中的props属性单向数据流

vue中is的作用和用法

总所周知,ul里面嵌套li的写法是html语法的固定写法(还有如table,select等)。my-component是我们自己写的组件,但是html在渲染dom的时候,my-component对ul来说并不是有效的dom,甚至会报错。

Vue的href动态拼接绑定

:href前面要加“:”或者v-bind: 字符串要用单引号包住 加上了冒号是为了动态绑定数据,等号后面可以写变量。 如果不使用冒号,等号后面就可以写字符串等原始类型数据。这是就无法进行动态绑定数据了

Vue基于snabbdom做了哪些事

Snabbdom 核心代码大约只有 200 行。它提供了模块化架构,具有丰富的功能,可通过自定义模块进行扩展。在了解核心 patch 前,需要先了解 snabbdom 的模块化架构思想。

Vue高版本中一些新特性的使用

Vue高版本中一些新特性的使用:深度作用选择器、组件配置项inheritAttrs、组件实例属性$attrs和$listeners、组件选项 provide/inject、作用域插槽 slot-scope、Vue的错误捕获

Vue 3.0 将从头开始重写!

Vue.js 伦敦大会上,Vue.js 作者尤雨溪简要介绍了 Vue 下一个主要版本要发布的内容,不久前,尤雨溪在 medium 个人博客上发布了 Vue 3.0 的开发路线,我们不妨看看 Vue 3.0 将会有怎样的发展。

一点 Vue.observable 想法

Vue 2.6.0 新增了 Vue.observable api,但最近才去尝试使用它。这东西说新也不新,因为他就是 vue 本身的功能,只是暴露出来,成为新 api 了。在老版本中,直接用 new Vue({ data: {} }) 也一样。

对vue双向绑定的理解?

单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新,双向绑定就很容易联想到了,在单向绑定的基础,用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定

在 VueJS应用中管理用户权限

在需要身份验证的前端应用里,我们经常想通过用户角色来决定哪些内容可见。比如,游客身份可以阅读文章,但注册用户或管理员才能看到编辑按钮。在前端中管理权限可能会有点麻烦。你之前可能写过这样的代码

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!