Vue.js中用webpack合并打包多个组件并实现按需加载
前言
随着移动设备的升级、网络速度的提高,用户对于web应用的要求越来越高,web应用要提供的功能越来越。功能的增加导致的最直观的后果就是资源文件越来越大。为了维护越来越庞大的客户端代码,提出了模块化的概念来组织代码。webpack作为一种模块化打包工具,随着react的流行也越来越流行。
使用 Vue 开发项目时,如果要使用其单文件组件特性,必然要使用 webpack 或者 browserify 进行打包,对于大型应用,为了提升加载速度,可以使用 webpack 的 code split 功能进行分割打包,生成较小的模块并按需加载,这在 Vue 文档及 vue-router 文档中均有介绍:Async Components、Lazy Loading。
webpack 的 code split 可以使用 webpack 的 require.ensure 特殊语法或者使用 AMD 风格的 callback-require 语法,以 AMD 风格的 callback-require 语法为例——
全局注册 Async Component:
1
2
3
4
|
let myAsyncComponent = resolve => { require([ './my-async-component' ], resolve) } Vue.component( 'async-webpack-example' , myAsyncComponent) |
局部注册 Async Component,单文件组件中 script 块内容:
1
2
3
4
5
6
7
8
9
10
|
let myAsyncComponent = resolve => { require([ './my-async-component' ], resolve) } // Vue 扩展实例选项,其他选项略 export default { components: { 'async-webpack-example' : myAsyncComponent } } |
在使用 vue-router 时,为实现不同路由下的组件异步加载,在路由映射中可以使用同样的方式来设置路由项的 component 属性。
这里的 myAsyncComponent 被定义为一个工厂函数,在需要时才会以 Vue 或者 vue-router 定义的用于解析组件选项的 resolve 回调函数(是的,在 Vue 和 vue-router 中有两个不同的解析组件选项的函数)为参数执行 callback-require 函数(resolve 回调函数的参数是组件选项),这样,在执行打包脚本时,my-async-component.vue 文件会被单独打包成一个文件,并且仅当该组件被使用时才会加载。
当要求异步加载的组件较多时,将会生成更多的单个文件,对于前端性能而言,虽然每个文件更小了,但可能意味着更多的网络连接建立和关闭的开销,因此在前端优化的实践中,通常需要在文件数量和单个文件大小之间取得平衡。
本文介绍如何将多个组件合并打包成一个单独的文件,一方面可以减少代码块的数量,另一方面,如果合并打包的这些组件在不同地方多次重复使用,由于 Vue 的缓存机制,可以加快后续组件的加载速度,并且如果这些通用组件长时间不会变化(如 UI 相关的组件),打包生成的文件也长期不会变化,可以充分利用浏览器的缓存功能,实现前端加载速度的优化。
先上效果图,在使用 vue-router 的 SPA 应用中,将除根路由之外的路由项对应的 ComponentA、ComponentB、ComponentC 等三个组件合并打包成一个文件。初次加载页面时,从开发者工具的 Network 面板上可以看到,此时未加载包含 ComponentA、ComponentB、ComponentC 这三个组件的 0.a5a1bae6addad442ac82.js 文件,当点击 Page A 链接时,加载了该文件,然后再点击 Page B、Page C 链接时,没有重新加载该文件。
我们首先通过 vue-cli 命令行工具使用 webpack 项目模板创建一个包含 vue-router 的项目,在其 src/components 目录下创建一个 CommonComponents 目录,在该目录中创建 ComponentA、ComponentB、ComponentC 这三个组件。
同时在 CommonComponents 目录下创建 index.js,其内容如下:
1
2
3
|
exports.ComponentA = require( './ComponentA' ) exports.ComponentB = require( './ComponentB' ) exports.ComponentC = require( './ComponentC' ) |
这样,我们只需要使用 webpack 的 require.ensure 特殊语法或者使用 AMD 风格的 callback-require 语法异步加载 CommonComponents 目录下的 index.js,在使用 webpack 进行打包时,就可以实现将 ComponentA、ComponentB、ComponentC 这三个组件合并打包。以 AMD 风格的 callback-require 语法为例示范如下,这里的 callback 回调函数的形式没有任何特殊要求。
1
2
3
|
require([ 'component/CommonComponents' ], function (CommonComponents) { // do whatever you want with CommonComponents }) |
component/CommonComponents 模块加载成功时,这里的回调函数中的 CommonComponents 参数将会是一个包含 ComponentA、ComponentB、ComponentC 这三个组件选项的对象。
在定义异步解析组件时,我们使用的是一个工厂函数 resolve => {require(['./my-async-component'], resolve)},如果需要在路由配置文件中添加 component 属性为 ComponentA 组件的路由项,应该定义什么样的工厂函数呢?记住这里的 resolve 是一个用于解析组件选项的回调函数,其参数是所获取的组件选项,而上一段代码中的 CommonComponents 恰好是包含若干个组件选项的对象,因此我们可以将 CommonComponents 的子属性作为参数用于 resolve 调用,我们编写一个函数 getCommonComponent,用于根据组件名称返回获取相应的组件选项的工厂函数。
1
|
let getCommonComponent = componentName => resolve => require([ 'components/CommonComponents' ], components => resolve(components[componentName])) |
在组件模板或者路由映射等使用其中某一个组件的地方,可以使用类似于 getCommonComponent('ComponentA') 这样的函数调用进行组件设置,在路由映射中的使用示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
routes: [ { path: '/' , name: 'Hello' , component: Hello }, { path: '/a' , name: 'A' , component: getCommonComponent( 'ComponentA' ) }, { path: '/b' , name: 'B' , component: getCommonComponent( 'ComponentB' ) }, { path: '/c' , name: 'C' , component: getCommonComponent( 'ComponentC' ) } ] |
最终打包生成的文件列表如下图所示,其中的 0.a5a1bae6addad442ac82.js 包含了 ComponentA、ComponentB、ComponentC 这三个组件。
Vue.js中用webpack合并打包多个组件并实现按需加载的更多相关文章
- 优雅的写好Vue项目代码 — 路由拆分、Vuex模块拆分、element按需加载
目录 路由的拆分 VUEX模块拆分 Element UI库按需加载的优雅写法 路由的拆分 项目较大路由较多时,路由拆分是一个不错的代码优化方案,按不同业务分为多个模块,结构清晰便于统一管理. requ ...
- webpack v3 结合 react-router v4 做 dynamic import — 按需加载(懒加载)
为什么要做dynamic import? dynamic import不知道为什么有很多叫法,什么按需加载,懒加载,Code Splitting,代码分页等.总之,就是在SPA,把JS代码分成N个页面 ...
- Vue.js:轻量高效的前端组件化方案
转发一篇尤老师对vue.js的介绍,了解vue.js的来龙去脉.不过现在已经是2.0了,也有添加一些新的东西,当然有些东西也改了. Vue.js:轻量高效的前端组件化方案 Vue.js 是我在2014 ...
- Vue.js:轻量高效的前端组件化方案(转载)
摘要:Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue ...
- 【转】Vue.js:轻量高效的前端组件化方案
摘要:Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue ...
- 原创《分享(Angular 和 Vue)按需加载的项目实践优化方案》
针对前端优化的点有很多,例如:图片压缩,雪碧图,js/css/html 文件的压缩合并, cdn缓存, 减少重定向, 按需加载 等等 最近有心想针对 ionic项目 和 vue项目,做一个比较大的优 ...
- vue 动态路由按需加载的三种方式
在Vue项目中,一般使用vue-cli构建项目后,我们会在Router文件夹下面的index.js里面引入相关的路由组件,如: import Hello from '@/components/Hell ...
- Vue.js 在 webpack 脚手架中使用 cssnext
Vue.js 的 webpack脚手架默认已经使用了 PostCSS 的 autoprefixer 的功能. 如果想使用下一代 css语法,即cssnext: 1. 安装依赖 npm install ...
- vue.js中用npm安装vue-router时报错处理办法
当在使用npm安装东西的时候,最怕遇到的就是,电脑并不想和你说话,只向你抛出一大堆错误...比如在vue.js中用npm安装vue-router的时候,我就遇到 一脸蒙逼的我默默的念了一句:卧..槽. ...
随机推荐
- shell 无限循环输出时间
#!/bin/bash while(true) do date >> /home/k/a.log sleep done 查看 tail -f /home/k/a.log
- 01_DllZZ.cpp
1. // DllZZ.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" ...
- [设计模式][C++]单例模式
参考:http://blog.csdn.net/hackbuteer1/article/details/7460019 单例模式意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有 ...
- elementUI和iview兼容么
听说iview的作者居然是91年的,我要赶快加油了. https://zhuanlan.zhihu.com/p/25739512
- mount ntfs-3g , fstab里的配置没有效果
把ntfs-3g配置在 fstab 里,mount 时会报 No such device 网上也有在嵌入式系统里发生的类似例子. 没有解决方法,也不准备再研究了. 准备在机器启动之后,手动下面的命令 ...
- 20170814xlVBA部分代号收盘价转置
原始数据: 转置效果: Sub TransformData() Dim Rng As Range Dim Arr As Variant Dim Dic As Object Dim dCode As O ...
- 请求和响应:类ActionController::Base ; 类ActionDispatch::Request
扩展:ActionController::Base < Metal 2个基本主题: Get and Show do and redirect Requests 每个请求,由router决定了co ...
- CF1083B The Fair Nut and String
题意 给出两个长度为n的01字符串S和T. 选出k个字典序在S和T之间的长度为n的01字符串,使得尽可能多的字符串满足其是所选字符串中至少一个串的前缀. 这是一道思路比较奇怪的类似计数dp的题. 首先 ...
- JDBC连接SqlServer数据库(非默认实例)方法
一般我们在连接数据库的时候都是用的默认实例名,今天遇到了用非默认是实例名:连接代码如下(Java): URL=jdbc:microsoft:sqlserver://192.168.1.85//DEMO ...
- CISC, RISC 探究
iPhone Simulator Intel iPhone ARM 区别很大, Intel目前的处理器主要为IA架构, IA-32即俗称x86,包括桌面处理器系列(赛扬,奔腾,酷睿等)以及服务器处 ...