在Laravel Mix里使用动态引入来实现Code Splitting效果

2,447 阅读6分钟

想要更好的阅读体验,请直接移步我的个人网站: www.pilishen.com/posts/using…

从Laravel Mix (4.0.16)起,开始默认支持动态引入了(dynamic imports)。动态引入是一种资源文件分割(code-splitting)技术,可以让我们将js组件、第三方库及其他模块分割到单独的文件里。比如一个项目里,你用到了好些个js组件,有很多的vuejs或react组件,那么你最终打包的app.js或bundle.js文件就会很大,超过1M+是常有的事儿。这个时候,势必就会降低你的网站加载速度,尤其当用户处于一个慢的连接条件下时。

资源文件分割(code-splitting),可以将原本一个大文件,切分成很多小的文件,这样每个就可能只有几十几百K,而不是多少M了,这样就能极大改善加载速度。由于都切分开了,你就可以一开始只加载最想要的那块js文件,只加载页面上用到的,那些暂时用不到的,或者在其他页面才用到的,可以在背后自动去下载,就不影响一开始的页面渲染时间了。

配置动态引入

{id="Configuring"}

首先你得升级Laravel Mix到4.0.16以上的版本,才能使用动态引入。

通过.babelrc文件来配置

然后呢,在你的项目根目录创建一个.babelrc文件,当然如果你已经有这个文件了,就在以前基础上更改即可。在这个文件里,将@babel/plugin-syntax-dynamic-import加到“plugins”这个array里面,这样呢就会启用laravel mix里已经带的自动引入插件。

{
  "plugins": [
    "@babel/plugin-syntax-dynamic-import"
  ]
}

通过webpack.mix.js文件来配置

当然了,如果你不想创建上面的.babelrc文件,你对babel及其配置并不熟悉,你也可以在mix配置文件,也即webpack.mix.js里做配置,可以加上下面的代码:

mix.babelConfig({
  plugins: ['@babel/plugin-syntax-dynamic-import'],
});

这样你就不用创建或更改.babelrc文件了

实际使用动态引入

{id="Using"}

原来我们引入一个js组件,经常是这样的:

// 标准的,或静态的引入
import Component from './components/ExampleComponent.vue';

现在,如果我们想着动态地引入一个组件,也即只有当这个组件在页面用到的时候,才去引入和加载,那么可以这样来写:

// 动态引入
const Component =
        () => import('./components/ExampleComponent.vue');

默认的,Webpack会将这些动态引入的组件切块,切成单独的文件,以0.js, 1.js这样的形式来命名。

Laravel Mix的在命名上,可以使用每个切块的名字,跟上这块内容的hash值,然后跟上.js扩展。如果你想着具体设定每个分块文件的名字,那么在动态引入的时候,可以在组件路径前面,加上下面这样的一段注释

const Component =
        () => import(/* webpackChunkName: "dynamically-imported-component" */ './components/ExampleComponent.vue');

可以看到这里,在vue组件具体路径前面,有一段/* webpackChunkName: "dynamically-imported-component" */的注释,这就告诉webpack,我想要这块文件用这么个名字。那么这样,最终产生的文件名就是dynamically-imported-component.[hash].js

在Vue-Router里使用动态引入

{id="router"}

如果你项目里用到了Vue-Router,那么也就可以用动态引入,来将每个页面切分成单独的文件,可以像下面这样做:

const routes = [
  {
    name: 'dashboard',
    path: '/dashboard',
    component:
      () => import(/* webpackChunkName: "dashboard" */ './pages/Dashboard.vue'),
  },
];

高级用法:脚本预加载

{id="prefetching"}

这样已经能够提升你不少页面的加载速度了,但是我们还不满足。现在假设有两个页面,分别是A页面和B页面,A页面是一个很轻量的、没啥组件的页面,而B页面假设用到了我们分离出来的一个my-component.js

那么这个时候,如果一个用户访问了页面A,然后他又点击了页面B,这个时候他就得等待my-component.js这个文件去下载和处理——也即我们加速了页面A的加载,但是却降低了B页面的时间。因为之前不分离js文件的时候,当访问了A时,app.js文件就已经完全下载了,再访问B页面时就不需要请求了,就一般从浏览器缓存直接加载了。

如果怎么样,我们能让浏览器更智能一些就好了,比如说访问了A页面,我们就能预计他会访问B页面,这时浏览器可以在加载完A页面的脚本和资源以后,在合适的时候后台自己预先抓取B页面要用到的脚本,这样当访问B页面时,相关文件已经准备好了。

当然了,这肯定不只是个想法了,其实现在的浏览器都已经支持这样的做法了,使用传统的<link>标签,我们其实就可以声明对某个文件的预加载,相当于在浏览器空闲的时候去背后获取。

<link
    rel="prefetch"
    href="/js/my-component.js"
    as="script"
>

这样了以后,当访问了A页面,速度依然很快,当脚本都加载完了,浏览器就自动去获取my-component.js文件了,当我们再访问到B页面时,也就不需要临时再加载什么文件了,已经都提前获取并放到缓存里了。

结论

{id="concolusion"}

这么好的一项功能,赶紧升级一下Mix,然后用到你的项目里吧,相信能提升不少你的网站加载速度。

本文是我们系列课程《Laravel&Vue深度整合实战第二版》的扩展文章,还记得课程里我们用到了Element-Ui,也即饿了么开发的vue ui组件,期间我们只是用了Element-Ui的几个模块,就导致我们的app.js文件瞬间膨胀到1M以上,在实际中,如果你严重依赖很多UI组件,那么你的打包文件好几M也都是很正常的。原来呢,我们得自行在webpack里进行各种设置,要么只是输出我们实际用到的UI模块,要么就自行实现今天说的文件分割效果,这对不怎么熟悉webpack的同学来说,挺恐怖的。那么现在,Mix默认简单地支持了资源文件分割效果,就大大解决了我们这方面的顾虑,让你在很多页面的效果体验上就可以更大胆、更有空间地做些事情了。

末了,欢迎到我的站点https://www.pilishen.com/来做客哦,也欢迎加入我们的公开群【公开课@pilishen.com】:109256050,等你哦~