1. 为什么需要按需加载?

对于vue单页应用来讲,我们常见的做法把页面上所有的代码都打包到一个bundle.js文件内,但是随着项目越来越大,文件越来越多的情况下,那么bundle.js文件也会越来越大,文件大的时候会导致打开页面用户体验相对来说会变慢。因此按需加载代码是很有必要的,每次打开某一个页面的时候,只按需加载那个页面的代码,这样的话,项目中其他代码就不会被加载,这样的话,bundle.js文件也不会把所有项目页面文件代码打包进去,文件也不会很大。其他的页面对应的代码第一次都是按需加载的,加载完成后,就会在浏览器缓存中了。

2. 如何使用webpack+vue+router 实现vue页面按需加载?

还是和之前一样,在实现功能之前,我们还是看下我们项目中的整个目录架构如下:

  1. ### 目录结构如下:
  2. demo1 # 工程名
  3. | |--- dist # 打包后生成的目录文件
  4. | |--- node_modules # 所有的依赖包
  5. | |--- app
  6. | | |---index
  7. | | | |-- views # 存放所有vue页面文件
  8. | | | | |-- home.vue
  9. | | | | |-- index.vue
  10. | | | | |-- xxx.vue
  11. | | | |-- components # 存放vue公用的组件
  12. | | | |-- app.js # vue入口配置文件
  13. | | | |-- router.js # 路由配置文件
  14. | |--- views
  15. | | |-- index.html # html文件
  16. | |--- webpack.config.js # webpack配置文件
  17. | |--- .gitignore
  18. | |--- README.md
  19. | |--- package.json
  20. | |--- .babelrc # babel转码文件

webpack中提供了 require.ensure()来实现页面按需加载。以前我们引入路由的时候都是通过 import 这样的方式引入的,但是使用import引入vue文件它是不会进行页面按需加载的。首先可以看下我们路由页面。如下:

app/index/router.js 之前代码使用import引入如下:

  1. import Vue from 'vue';
  2. import VueRouter from 'vue-router';
  3.  
  4. // 引入组件
  5. import home from './views/home';
  6.  
  7. import xxx from './views/xxx';
  8.  
  9. // 告诉 vue 使用 vueRouter
  10.  
  11. Vue.use(VueRouter);
  12.  
  13. const routes = [
  14. {
  15. path: '/home',
  16. component: home
  17. },
  18. {
  19. path: '/xxx',
  20. component: xxx
  21. },
  22. {
  23. path: '*', // 其他没有的页面都重定向到 home页面去
  24. redirect: '/home'
  25. }
  26. ]
  27.  
  28. var router = new VueRouter({
  29. routes: routes
  30. });
  31.  
  32. export default router;

如上代码,每一个vue单页面都是使用import引用进来的,它不会进行页面懒加载的,所以在打包的时候都会打包到bundle.js文件内,因此文件会变得越来越大。因此我们需要使用 require.ensure()实现按需加载。

2.1、学习使用 require.ensure()

webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。这个新的 chunk 会被 webpack 通过 jsonp 来按需加载。

基本使用语法如下:require.ensure(dependencies: String[], callback: function(require), chunkName: String);

参数dependencies:该参数是一个字符串数组,通过这个参数,在所有的回调函数的代码被执行前,我们可以将所有需要用到的模块进行声明。

参数callback: 当所有的依赖都加载完成后,webpack会执行这个回调函数。require 对象的一个实现会作为一个参数传递给这个回调函数。因此,我们可以进一步 require() 依赖和其它模块提供下一步的执行。

参数chunkName: chunkName 是提供给这个特定的 require.ensure() 的 chunk 的名称。

下面我们来看一个demo,在app/index 下新建一个文件夹为js。在js文件夹内分别新建a.js和b.js,代码分别如下:

a.js 代码如下:

alert('aaaaaa');

b.js 代码如下

alert('bbbbbbb');

然后入口文件app.js 代码如下:

  1. require('./js/a');
  2. require.ensure([], function(require) {
  3. require('./js/b');
  4. });

webpack.config.js 打包如下:

  1. module.exports = {
  2. // 入口文件
  3. entry: {
  4. main: './app/index/app.js'
  5. },
  6. output: {
  7. filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash].js' : 'bundle.js',
  8. // 将输出的文件都放在dist目录下
  9. path: path.resolve(__dirname, 'dist')
  10. }
  11. }

通过执行这个项目的 webpack 构建,我们发现 webpack 创建了2个新的文件束, bundle.js 和 0.bundle.js。如下图所示:

app.js 和 a.js 被打包进 bundle.js.

其中 0.bundle.js 代码如下:

  1. (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{"./app/index/js/b.js":function(b,n){alert("bbbbbbb")}}]);

bundle.js 代码如下:

  1. !function(u){function e(e){for(var n,t,r=e[0],o=e[1],a=0,i=[];a<r.length;a++)t=r[a],p[t]&&i.push(p[t][0]),p[t]=0;for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(u[n]=o[n]);for(l&&l(e);i.length;)i.shift()()}var t={},p={main:0};function c(e){if(t[e])return t[e].exports;var n=t[e]={i:e,l:!1,exports:{}};return u[e].call(n.exports,n,n.exports,c),n.l=!0,n.exports}c.e=function(a){var e=[],t=p[a];if(0!==t)if(t)e.push(t[2]);else{var n=new Promise(function(e,n){t=p[a]=[e,n]});e.push(t[2]=n);var r,o=document.getElementsByTagName("head")[0],i=document.createElement("script");i.charset="utf-8",i.timeout=120,c.nc&&i.setAttribute("nonce",c.nc),i.src=c.p+""+a+".bundle.js",r=function(e){i.onerror=i.onload=null,clearTimeout(u);var n=p[a];if(0!==n){if(n){var t=e&&("load"===e.type?"missing":e.type),r=e&&e.target&&e.target.src,o=new Error("Loading chunk "+a+" failed.\n("+t+": "+r+")");o.type=t,o.request=r,n[1](o)}p[a]=void 0}};var u=setTimeout(function(){r({type:"timeout",target:i})},12e4);i.onerror=i.onload=r,o.appendChild(i)}return Promise.all(e)},c.m=u,c.c=t,c.d=function(e,n,t){c.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},c.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.t=function(n,e){if(1&e&&(n=c(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var t=Object.create(null);if(c.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var r in n)c.d(t,r,function(e){return n[e]}.bind(null,r));return t},c.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return c.d(n,"a",n),n},c.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},c.p="",c.oe=function(e){throw e};var n=window.webpackJsonp=window.webpackJsonp||[],r=n.push.bind(n);n.push=e,n=n.slice();for(var o=0;o<n.length;o++)e(n[o]);var l=r;c(c.s="./app/index/app.js")}({"./app/index/app.js":function(e,n,t){t("./app/index/js/a.js"),t.e(0).then(function(e){t("./app/index/js/b.js")}.bind(null,t)).catch(t.oe)},"./app/index/js/a.js":function(e,n){alert("aaaaaa")}});

如上代码分析可以看到,通过 require.ensure([], function(require) { require('./js/b'); }) 动态加载的b函数代码会单独生成一个0.bundle.js文件,如果页面有多个 require.ensure 这个动态加载文件的话,它就会生成多个xx.bundle.js文件了,因此对于vue路由页面来讲可以使用这种方法来动态加载vue页面了。

如上webpack.config.js 文件,我们可以再加个配置项 chunkFilename,该配置项,可以指定chunk的名字,如下配置:

  1. module.exports = {
  2. // 入口文件
  3. entry: {
  4. main: './app/index/app.js'
  5. },
  6. output: {
  7. filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash].js' : 'bundle.js',
  8. // 将输出的文件都放在dist目录下
  9. path: path.resolve(__dirname, 'dist'),
  10. chunkFilename: 'chunks/[name].chunk.js'
  11. }
  12. }

app/index/app.js 代码如下,加了第三个参数, 名字为b:

  1. require('./js/a');
  2. require.ensure([], function(require) {
  3. require('./js/b');
  4. }, 'b');

然后会在 dist/chunks 下生成 b.chunk.js, 如下图所示:

2.2. 在vue-router中使用require.ensure() 方法动态加载不同的vue页面。

因此我们现在可以在 app/index/router.js 里面如下对vue页面文件进行按需加载了,如下代码:

  1. import Vue from 'vue';
  2. import VueRouter from 'vue-router';
  3.  
  4. // 告诉 vue 使用 vueRouter
  5. Vue.use(VueRouter);
  6.  
  7. const routes = [
  8. {
  9. path: '/home',
  10. name: 'home',
  11. component: resolve => require.ensure([], () => resolve(require('./views/home')), 'home')
  12. },
  13. {
  14. path: '/xxx',
  15. name: 'xxx',
  16. // component: resolve => require(['./views/xxx'], resolve)
  17. component: resolve => require.ensure([], () => resolve(require('./views/xxx')), 'xxx')
  18. },
  19. {
  20. path: '*', // 其他没有的页面都重定向到 home页面去
  21. redirect: '/home'
  22. }
  23. ]
  24.  
  25. var router = new VueRouter({
  26. base: '/app/index', // 配置单页应用的基路径
  27. routes: routes
  28. });
  29.  
  30. export default router;

webpack.config.js 代码配置如下:

  1. module.exports = {
  2. // 入口文件
  3. entry: {
  4. main: './app/index/app.js'
  5. },
  6. output: {
  7. filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash].js' : 'bundle.js',
  8. // 将输出的文件都放在dist目录下
  9. path: path.resolve(__dirname, 'dist'),
  10. chunkFilename: 'chunks/[name].chunk.js'
  11. }
  12. }

在dist/chunks 目录下会生成如下文件,如下图所示

github源码

深入浅出的webpack4构建工具---webpack+vue+router 按需加载页面(十五)的更多相关文章

  1. vue router按需加载

    import Vue from 'vue' import Router from 'vue-router' Vue.use(Router); //按需加载,当渲染其他页面时才加载其组件,并缓存,减少首 ...

  2. Vue Router的懒加载路径

    单页应用产出的入口chunk大小随着业务的复杂度线性增加,导致后期加载速度越来越慢.后面就需要对不同路径下的模块进行拆分,打包到相应的chunk下,按需加载,找到chunk的大小.个数和页面加载速度的 ...

  3. React Router 4.0 + webpack 实现组件按需加载

    网上关于React Router 4.0的按需加载文章有很多,大致的思路都一样,但是其实具体实现起来却要根据自己的实际情况来定,这里主要介绍一下我的实现方式. 主要方式是通过Route组件的rende ...

  4. 原创《分享(Angular 和 Vue)按需加载的项目实践优化方案》

    针对前端优化的点有很多,例如:图片压缩,雪碧图,js/css/html 文件的压缩合并,  cdn缓存, 减少重定向, 按需加载 等等 最近有心想针对 ionic项目 和 vue项目,做一个比较大的优 ...

  5. webpack学习笔记--按需加载

    为什么需要按需加载 随着互联网的发展,一个网页需要承载的功能越来越多. 对于采用单页应用作为前端架构的网站来说,会面临着一个网页需要加载的代码量很大的问题,因为许多功能都集中的做到了一个 HTML 里 ...

  6. vue项目按需加载的3种方式

    本文重要是路由打包优化: 原理:利用webpack对代码进行分割是懒加载的前提,懒加载就是异步调用组件,需要时候才下载. 1.vue异步组件技术 vue-router配置路由,使用vue的异步组件技术 ...

  7. webpack中实现按需加载

    webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...

  8. 深入浅出的webpack4构建工具---浏览器前端资源缓存(十一)

    阅读目录 一. 理解使用hash 二:理解使用chunkhash 三:对第三方库打包后使用缓存 四:contenthash 回到顶部 一. 理解使用hash 一般情况下,对于前端静态资源,浏览器访问的 ...

  9. webpack require.ensure 按需加载

    使用 vue-cli构建的项目,在 默认情况下 ,会将所有的js代码打包为一个整体比如index.js.当使用存在多个路由代码的时候,index.js可能会超大,影响加载速度. 这个每个路由页面除了i ...

随机推荐

  1. Java学习第一篇 — 字符串

    package StringTest; public class TestString { public static void main(String[] args){ // String str= ...

  2. Archlinux/Manjaro使用笔记-使用makepkg安装软件 报错:未找到strip分割所需的二进制文件 的解决方法

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 使用archlinux或manjaro安装aurman时遇到如下报错 错误:未找到strip分割所需的二进制文件 原因:未安装g ...

  3. 前端面试整理——javascript算法和测试题

    (1)算法: 1.斐波那契数列:1.1.2.3.5.8.13.21.输入n,输出数列中第n位数的值. 方案一: function fn(n){ var num1 = 1, num2= 1, num3 ...

  4. 【读书笔记】iOS-优化iOS Web应用

    一,代码优化: 代码优化是任何优化技术的第一步,因为归根结底网页上的一切都是构建在代码之上的.优秀的代码可以节省宽带,减少渲染延迟,以及提高页面的可读性和长远的可维护性.下面列出了一些在Web应用中编 ...

  5. python小练习:用户三次登陆, 购物车

    2018.12.1 周末练习: 1.用户三次登陆 from random import randint i = 1 while i < 4: num = 0 verify_code = '' w ...

  6. Python 获取被调用函数名称,所处模块,被调用代码行

    获取被调用函数名称,所处模块,被调用代码行 by:授客 QQ:1033553122 module2.py: #!/usr/bin/env python # -*- coding:utf-8 -*- _ ...

  7. Oracle 11gR2_database在Linux下的安装

    Oracle 11gR2_database在Linux下的安装 by:授客 QQ:1033553122 由于篇幅问题,采用链接分享的形式,烦请复制以下网址,黏贴到浏览器中打开,下载 http://pa ...

  8. LyX使用中的一些问题

    编译开始产生的检查错误 试用LyX2.3,在2.15中能编译通过的文档,竟然提示错误 The user preamble of your document contains glyphs that a ...

  9. 如何修改redis配置

    相关内容: Redis的配置: 通过config set命令修改配置 查看配置 设置新配置 直接修改配置文件redis.conf 常见配置项: 服务端连接相关 日志记录相关 服务端保持相关 首发时间: ...

  10. 转 fiddler常见的应用场景

    fiddler常见的应用场景   在移动互联网时代,作为软件测试工程师,fiddler绝对是值得掌握并添加进技术栈里的工具之一. 那么,fiddler在日常的测试工作中,一般都有哪些常见的应用场景呢? ...