预取/预加载模块
webpack 4.6.0+增加了对预取和预加载的支持。
在声明导入时使用这些内联指令允许webpack输出“Resource Hint”,它告诉浏览器:
prefetch:将来某些导航可能需要资源
preload:当前导航期间可能需要资源
简单的预取示例可以是一个HomePage组件,该组件呈现一个LoginButton组件,然后在LoginModal点击后按需加载组件。
LoginButton.js
//...import(/* webpackPrefetch: true */ 'LoginModal');
这将导致<link rel="prefetch" href="login-modal-chunk.js">被附加在页面的头部,这将指示浏览器在空闲时间预取login-modal-chunk.js文件。
一旦父块加载,webpack将添加预取提示。
与prefetch相比,Preload指令有许多不同之处:
- 与 prefetch 指令相比,preload 指令有许多不同之处:
- preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
- preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
- preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
- 浏览器支持程度不同。
下面这个简单的 preload 示例中,有一个 Component,依赖于一个较大的 library,所以应该将其分离到一个独立的 chunk 中。
我们假想这里的图表组件 ChartComponent 组件需要依赖一个体积巨大的 ChartingLibrary 库。它会在渲染时显示一个 LoadingIndicator(加载进度条) 组件,然后立即按需导入 ChartingLibrary:
ChartComponent.js
//...import(/* webpackPreload: true */ 'ChartingLibrary');
在页面中使用 ChartComponent 时,在请求 ChartComponent.js 的同时,还会通过 <link rel="preload"> 请求 charting-library-chunk。假定 page-chunk 体积很小,很快就被加载好,页面此时就会显示 LoadingIndicator(加载进度条) ,等到 charting-library-chunk 请求完成,LoadingIndicator 组件才消失。启动仅需要很少的加载时间,因为只进行单次往返,而不是两次往返。尤其是在高延迟环境下。
错误地使用webpackPreload实际上会损害性能,因此使用它时要小心。
延迟加载
懒惰或“按需”加载是优化网站或应用程序的好方法。这种做法主要涉及在逻辑断点处拆分代码,然后在用户完成需要或将需要新代码块的操作后加载它。这可以加快应用程序的初始负载并减轻其总体重量,因为某些块甚至可能永远不会被加载。
例
让我们以Code Splitting为例,稍微调整一下,以进一步展示这个概念。这些代码确实会导致生成一个单独的块,lodash.bundle.js并在脚本运行时从技术上“延迟加载”它。问题是加载捆绑包不需要用户交互 - 这意味着每次加载页面时,都会触发请求。这对我们没有多大帮助,并且会对性能产生负面影响。
让我们尝试不同的东西。当用户单击按钮时,我们将添加一个交互以将一些文本记录到控制台。但是,我们将等待加载该代码(print.js),直到第一次发生交互。为此,我们将返回并重新编写Code Splitting中的最终Dynamic Imports示例,并留在主块中。lodash
webpack-demo|- package.json|- webpack.common.js|- webpack.dev.js|- webpack.prod.js|- server.js|- DEV-server.js|- /dist|- /src|- data.xml|- icon.png+|- style.css|- my-font.woff|- my-font.woff2|- print.js|- index.js|- math.js|- /node_modules
// print.jsconsole.log('The print.js module has loaded! See the network tab in dev tools...');export default () => {console.log('Button Clicked: Here\'s "some text"!');};
// index.jsimport _ from 'lodash';function component() {var element = document.createElement('div');var button = document.createElement('button');var br = document.createElement('br');button.innerHTML = 'Click me and look at the console!';element.innerHTML = _.join(['Hello', 'webpack'], ' ');element.appendChild(br);element.appendChild(button);// Note that because a network request is involved, some indication// of loading would need to be shown in a production-level site/app.button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {var print = module.default;print();});return element;}document.body.appendChild(component());
请注意,import()在ES6模块上使用时,必须引用该.default属性,因为它module是解析promise时将返回的实际对象。
构架
许多框架和图书馆都有自己的建议,说明如何在其方法中实现这一目标。这里有一些例子:
React:代码拆分和延迟加载
AngularJS:AngularJS +的WebPack = lazyLoad通过@var_bincom
