likes
comments
collection
share

webpack5代码分离优化项目加载速度

作者站长头像
站长
· 阅读数 13

@[toc]

什么是代码分离

  • 代码分离是webpack的特性之一
  • 可以把代码分离到不同的bundle中 bundle就是我们打包分离出来的文件
  • 然后就可以把这些文件按需加载或者并行加载

代码分离的好处

  • 可以用于获取更小的bundle 以及控制资源加载的优先级 如果使用合理 可以极大的影响首屏的加载时间

常用的代码分离方法

  • 第一种叫做配置入口节点 -- 可以使用entry来配置手动的分离代码 -- 这种方式有个问题 就是如果有多个入口 就会分别在每个包里去重复打包
  • 第二种方法叫防止重复 --可以在入口的地方通过entry dependencies或者splitChunksPlugin 去重和分离代码 -- 抽离出共享的文件 防止代码重复打包 优化打包的文件大小
  • 第三种方法动态导入 -- 可以通过模块的内联函数import来调用这个函数分离代码 实现代码的懒加载

入口节点分离法

  • 这种方法是是最简单直观的分离代码的方法
  • 比如我们创建一个一些js文件 里面写点东西
  • 然后手动去修改webpack.config.js 完成多个入口节点entry的配置
 entry:{
    index: './src/index.js', //第一个js文件
    another: './src/another-module.js' //第二个js文件
  }, 
  output:{
  // 打包后的文件名 [name]根据文件名称自动生成打包后输出的名字
    filename:'[name].bundle.js',
  },
  • 打包后输出了两个js文件 实现了根据不同的js代码打包出了不同的文件webpack5代码分离优化项目加载速度
  • 但是这样也就会有问题 比如我两个js文件都引用了loadash库
  • 按理说loadash是一个共享的方法 但是这种方式的打包会在每个文件都会打包一个loadsh

这就是entry配置多入口的问题 所以如果我们在不同入口的chunk之间 包含一些重复的代码 那么这些重复的模块 会引入到各自的bundle中

防止重复

  • 相对于第一种方法 可以把一些公共的文件 抽离成单独的chunk
  • entry需要改写一下 等于是我们要加一个dependOn
  • 然后把有lodash库的地方 抽离成单独的一个chunk
 entry:{
    index:{
      import:'./src/index.js',
      dependOn:'shared',
    },
    another:{
      import:'./src/another-module.js',
      dependOn:'shared',
    },
    shared:'lodash', 
  }, 

更加推荐方法 : 或者直接在optimization里配置splitChunks也可以自动实现一个公共方法的抽离

 optimization: {
    splitChunks: {
      chunks:'all'
    }
  }, 

这样打包后就会把lodash给抽离出来了 其他的文件就小了很多

动态导入

  • 使用import去完成import返回的是一个promise!!!! 比如我在js文件中写下这些代码去加载一个lodash的join方法
function getComponent(){
 return  import('lodash') //异步加载lodash 返回的是pormise
  .then(({default: _}) => {
   const ele = document.createElement('div');
   ele.innerHTML=_.join(['Anot  her', 'module', 'loaded!'], ' ');
   return ele
  })
}

getComponent().then(ele => {
  document.body.appendChild(ele); 
})

打包后可以发现 已经把lodash给抽离出来了 就是vendors-node_modules_lodash.jswebpack5代码分离优化项目加载速度

建议利用第二种方法配合第三种方法一起使用

  • 动态导入方法可以分离出import的公共方法
  • 第二种防止重复的方法可以分离出静态直接使用的公共方法
  • 不会冲突

import动态导入 魔法注释

  • 可以在import里定义一个注释 来自定义打包出的chunk的名字哦
  • /* webpackChunkName : ' 自定义名称 ' */

webpack5代码分离优化项目加载速度

懒加载 ( 动态导入方法的应用 )

  • 这个动态导入方法有什么用? 直接使用静态的不就很好吗?

  • 懒加载也就是按需加载 是一个优化网页或应用的方式 如果使用import动态导入的方法 只有用到才会加载 不用就不会加载

  • 自己可以试一试 比如一个按钮要调用某个js文件里的函数 用的是import调用的

  • 可以在浏览器控制台里的Network里看 是不是只有当点击按钮调用的时候 才会加载对应的js

  • 有这么一个场景

  • 下面的代码的意思其实就是点击一个按钮 会动态调用lodash库 我们来试试效果

function getComponent(){
 return  import(/* webpackChunkName:'math'*/,'lodash') //异步加载lodash
  .then(({default: _}) => {
   const ele = document.createElement('div');
   ele.innerHTML=_.join(['Anot  her', 'module', 'loaded!'], ' ');
   return ele
  })
}

const button = document.createElement('button');
button.innerHTML = 'Click me and look at the console!';
document.body.appendChild(button);
button.onclick = async () => {
  getComponent().then(ele => {
    document.body.appendChild(ele); 
  })
}
  • 现在的结果是懒加载 只有点击了按钮 才会加载lodsh资源 不点就不会加载

预获取/预加载模块

  • 既不影响首屏加载速度 又可以省去了将来模块加的延迟

在webpack v4.6.0+增加了对预获取和预加载的支持

  • 在声明import时候 使用内置指令 可以让webpack输出resource(资源提示)来告知浏览器
  • prefetch( 预获取 ) 将来某些导航下可能需要的资源 提前下载一下
prefetch尝试

尝试一下 在懒加载的前提下 又加上了webpackPrefetch:true的魔法注释呢?

function getComponent(){
 return  import(/* webpackChunkName:'math', webpackPrefetch:true */'lodash') //异步加载lodash
  .then(({default: _}) => {
   const ele = document.createElement('div');
   ele.innerHTML=_.join(['Anot  her', 'module', 'loaded!'], ' ');
   return ele
  })
}

const button = document.createElement('button');
button.innerHTML = 'Click me and look at the console!';
document.body.appendChild(button);
button.onclick = async () => {
  getComponent().then(ele => {
    document.body.appendChild(ele); 
  })
}
  • 刷新页面的时候 没点击按钮 这个math.bundle.js就已经被预下载下来了
  • 然后点击的时候还会加载一遍
  • 意义就是在我们首页内容加载完毕后 在网络空闲的时候 会预加载一些我们定义的好的模块
  • 这样的方式 更加提升性能 这就是prefetch预加载 webpack5代码分离优化项目加载速度