三种方式分割VueJS及Webpack代码

原作者:Anthony Gore, https://medium.com/js-dojo/3-code-splitting-patterns-for-vuejs-and-webpack-b8fff1ea0ba4

代码分割 可以很好的提高单页面应用加载速度。用户不用等到所有代码一次加载完毕便可以很快的看到页面并与之交互。这尤其会提升移动端的用户体验,此外可以获得不错的SEO,因为Google会对加载慢的站点进行降权。

上周我写了关于如何使用Webpack分离Vue.js应用代码(注:相对简单亦无需梯子)。简单来说就是,所有包含在单文件组件里的都能很容易地被分离,因为在导入一个模块时,Webpack能创建分离点,Vue能够轻松愉快地异步读取组件。

我相信让代码分离跑起来并不难,难得是了解什么时候以及什么地方使用它。甚至可以说,在设计你的应用时,需要一种架构思想来对代码进行分离。

本文我将介绍三种用于Vue.js单页面应用的代码分离方法:

  • 按页面
  • 按折页
  • 按条件
注:原文发表在 http://vuejsdevelopers.com/2017/07/08/vue-js-3-ways-code-splitting-webpack/

1. 按页面

按页面分割是显而易见的,这个简单的例子中有三个页面:


一旦我们确定每个页面对应着它自己的单页面组件,例如:Home.vue, About.vue, Contact.vue等,那么我们就可以用Webpack的动态 import 方法逐一分离到独立的生成文件里。当用户访问不同页面时,Webpack会异步读取需要的页面文件。
如果你正使用vue-router,那么实现起来更加轻松,因为你的页面已经是独立的组件了。

const Home = () => import(/* webpackChunkName: "home" */ './Home.vue');
const About = () => import(/* webpackChunkName: "about" */ './About.vue');
const Contact = () => import(/* webpackChunkName: "contact" */ './Contact.vue');
const routes = [
  { path: '/', name: 'home', component: Home },
  { path: '/about', name: 'about', component: About },
  { path: '/contact', name: 'contact', component: Contact }
];

看一下生成统计,每个页面各居其位。但要留意有个叫做build_main.js的打包文件,它包含了所有的通用代码以及异步加载的其它文件逻辑,无论用户访问哪些路由它都需要被加载。


现在好比我通过http://localhost:8080/#/contact地址读取到Contact页面,当切换到Chrome Network标签页时会发现下面的文件已经加载:

注意那个build_main.js的initiator是index,这表示index.html需要该脚本,这也是我们希望的。但是build_1.js的initator是bootstrap_a877... 这是Webpack负责异步读取文件的脚本,当使用Webpack的动态import方法时该脚本会被自动生成。重点是build_1.js不会阻止初始页面加载。

2.折页之下

“折页”之下是说当页面一开始加载时该页面中那些在视窗中见不到的部分。因为用户通常会在下拉之前花上一到两秒阅读“折页”上面的内容,所以可以异步读取这些内容,特别是在他们初次访问该站时。


本例中我假设“折页”的“折线”位于报头下方,导航栏和报头会在页面一开始就加载,下面的所有内容都会在后面加载。现在创建一个叫BelowFold的组件并相应地做一些抽象标记:

Home.vue:

<template>
  <div>
    <div class="jumbotron">
        <h1>Jumbotron heading</h1>
        ...
    </div>
    <below-fold></below-fold>
    <!--All the code below here has been put into-->
    <!--into the above component-->
    <!--<div class="row marketing">
      <div class="col-lg-6">
        <h4>Subheading</h4>
        <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
        ...
      </div>
      ...
    </div>-->
  </div>
</template>
<script>
  
  const BelowFold = () => import(
    /* webpackChunkName: "below-fold" */ './BelowFold.vue'
  );
  export default {
    ...
    components: {
        BelowFold
    }
  }
</script>

BelowFold.vue:

<template>
  <div class="row marketing">
    <div class="col-lg-6">
      <h4>Subheading</h4>
      <p>Donec id elit non mi porta gravida at eget metus. Maecenas faucibus mollis interdum.</p>
      ...
    </div>
    ...
  </div>
</template>

我们发现,打包后below-fold块会有独立的文件:

注:below-fold块非常小(1.36kB)看起来不值得分离出来。这仅仅是因为这是个有着很少内容的demo,真正的应用,页面大量的内容会位于“折页”里,有可能会是大量包括CSS或者JS文件在内的子组件。

3.条件内容

代码分离另一个不错的选择是有条件地显示内容。例如modal窗口,tabs,下拉菜单等等。
下面的应用在点击“今日登陆”按钮后会有个modal窗口:



老惯例,我们先看看这个单文件组件的代码:

Home.vue:

<template>
  <div>
    <div class="jumbotron">...</div>
    <below-fold></below-fold>
    
    <home-modal v-if="show" :show="show"></home-modal>
  </div>
</template>
<script>
  const BelowFold = () => import(
    /* webpackChunkName: "below-fold" */ './BelowFold.vue'
  );
  const HomeModal = () => import(
    /* webpackChunkName: "modal" */ './HomeModal.vue'
  );
  
  export default {
    data() {
      return {
        show: false
      }
    },
    components: {
      HomeModal,
      BelowFold
    }
  }
</script>

HomeModal.vue:

<template>
    <modal v-model="show" effect="fade">...</modal>
</template>
<script>
  import Modal from 'vue-strap/src/Modal.vue';
  export default {
    props: ['show'],
    components: {
        Modal
    }
  }
</script>

注意我已经将v-if放在modal中了。布尔值show控制modal的开启/关闭状态,同时它也有条件的渲染modal组件。由于页面读到它为false,因此代码只会在modal是开启状态下加载。
这很酷不是吗?如果用户压根儿没有打开modal,他们就永远不会下载这些代码。只是有些小小的用户体验上的缺点:用户必须要等到他们按下按钮后代码才会加载进来。
再次生成后,会有下面这些输出信息:


另外的 ~5kB我们不必提前加载。

结论

这些就是在构建一个应用的时候代码分离的三种思想。相信利用你的想象力你还会发现其它方法。
获取最新Vue.js文章、教程以及酷炫项目点击http://vuejsdevelopers.com/newsletter/(貌似已经404了😓)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354