入门webpack的最佳实践(基于webpack4.X 5.X)-- 运行体验优化

2022-09-28 14:11:41 浏览数 (1)

theme: channing-cyan

导语

来到这家公司之后,一直在使用webpack,也写了不少笔记,但是都比较零散,现在决定整理一下webpack相关的知识点,由浅入深,方便自己后续查漏补缺,后续会一直更新。

前言

本文将从几个方面,介绍webpack如何优化打包后的运行体验,所谓运行体验,就是用户在使用我们打包后的应用时,能够快速加载页面,渲染关键信息。

目录
  • splitChunks
  • 懒加载
  • prefetch 与 preload
  • css内联

splitChunks

当我们打包的模块比较大的时候,我们可以通过splitChunks来进行分包配置,从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks,先来看一下它的默认配置

代码语言:javascript复制
module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,//当导入的模块最小是多少字节才会进行代码分割
      minRemainingSize: 0,//解析见代码下面的文字说明,不用设置
      minChunks: 1,//当一个模块被导入(引用)至少多少次才对该模块进行代码分割
      maxAsyncRequests: 30,//按需加载时的最大并行请求数
      maxInitialRequests: 30,//入口点的最大并行请求数
      enforceSizeThreshold: 50000,//解析见代码下面的文字说明,不用设置
      cacheGroups: {//缓存组
        defaultVendors: {
          test: /[\/]node_modules[\/]/,
          priority: -10,//优先级
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

更多配置请参阅: https://webpack.docschina.org/plugins/split-chunks-plugin/

chunks
  • all模式下,入口文件和动态引入文件都会进行打包,作用最强大
  • initial 模式下,会将入口文件中的依赖包重新切割为一个新的文件,其它文件中动态引入的不会进行拆分
  • async(默认值)模式下,入口文件中的模块输出一个依赖包,对于动态加载的模块,默认配置会将该模块单独打包。
cacheGroups

cacheGroups是让我们自定义打包策略的地方,我们想抽取的各类公共模块,都再这个地方配置,存组可以继承和/或覆盖来自 splitChunks.* 的任何选项,比较常用的几个参数有

  • priority:优先级,只配置在缓存组的每一项,决定执行的顺序。
  • minChunks:最小块,即当块的数量大于等于minChunks时,才起作用
  • minSize:最小大小,即当抽取的公共模块的大小,大于minSize所设置的值,才起作用
  • maxSize:如果引入的包大小已经超过了设置的最大值,那么webpack会尝试对该包再进行分割
  • test:匹配规则,说明要匹配的项,这里是匹配匹配绝对模块资源路径或 chunk 名称
  • name: 打包之后的文件名,从 webpack 5 开始,不再允许将 entry 名称传递给 {cacheGroup}.test 或者为 {cacheGroup}.name 使用现有的 chunk 的名称。

比如,我们想在默认缓存组的基础上,抽离react的相关依赖,我们可以这样配置

代码语言:javascript复制
cacheGroups: {
  // 配置提取模块的方案
  defaultVendors: {
    test: /[/]node_modules[/]/,
    priority: -10,
    reuseExistingChunk: true,
    name: 'vendors',
  },
  default: {
    minChunks: 2,
    priority: -20,
    reuseExistingChunk: true,
    name: 'default',
  },
  react: {
    test: /(react|react-dom)/, // 匹配chunk的名称
    name: 'react', //打包后的文件名
    chunks: 'all',
    priority: 13, // 优先级 越高则先处理
  },
},

在打包后,就会看到react的依赖包

懒加载

懒加载其实也叫动态加载,顾名思义,就是在项目中,不一开始就加载所有资源,而是在使用到的时候再进行加载,依赖于ES Module,比如说,

有一个asyncImportModule.js的文件,里面的方法返回一个新的组件

代码语言:javascript复制
// 用于动态引入的module
console.log('console一下证明引入了文件');

const AsyncImportModule = () => {
  return <div class='module'>这是一个新的module</div>;
};
export default AsyncImportModule;

然后我们在页面中的方法动态引用它

代码语言:javascript复制
onclick=() => {
  import('./base/asyncImportModule').then((res) => console.log(res));
}

通过splitchunks的配置,我们动态引用到的文件会打包成一个额外的包

在页面中运行时,一开始并不会加载这个js文件,只有当我们执行方法时才会加载这个js文件。

内联注释

通过在 import 中添加注释,我们可以进行诸如给 chunk 命名或选择不同模式的操作。比如,我们可以通过传入webpackChunkName来指定打包后的文件名

代码语言:javascript复制
import(/* webpackChunkName: "changeModuleName" */'./base/asyncImportModule').then((res) => console.log(res));

更多配置请参阅: https://webpack.docschina.org/api/module-methods/#magic-comments

react中使用懒加载

react提供了React.lazySuspense 方法来实现懒加载以及代码分割

代码语言:javascript复制
const Home = lazy(() => import(/* webpackChunkName: "home" */ './home/index'));

const SuspenseComponent = (Component: any) => (props: any) => (
    <Suspense fallback={Loading}>
      <Component {...props}></Component>
    </Suspense>
);

const App = () => {
return <div>
    {SuspenseComponent(Home)}
</div>
}

prefetch 与 preload

前面说到了我们可以动态的引入资源,但是如果需要异步加载的文件比较大时,在点击的时候去加载也会影响到我们的体验,这个时候我们就可以考虑使用 prefetch 来进行预拉取,使用preload进行预加载。

prefetch和preload也是通过内联注释进行配置

prefetch (预获取):浏览器空闲的时候进行资源的拉取

代码语言:javascript复制
// 按需加载
img.addEventListener('click', () => {
  import( /* webpackPrefetch: true */ './desc').then(({ default: element }) => {
    console.log(element)
    document.body.appendChild(element)
  })
})

preload (预加载):提前加载后面会用到的关键资源,因为会提前拉取资源,如果不是特殊需要,谨慎使用

官网示例:

代码语言:javascript复制
import(/* webpackPreload: true */ 'ChartingLibrary');

css内联

在打包时,我们可以将css通过style标签内联到页面中,这样做的好处是可以让页面样式更快的渲染出来,也能避免页面闪动,不过在webpack5已经放弃了这种方法。

使用postcss-loader实现

代码语言:javascript复制
{
  loader: 'postcss-loader',
  options: {
    //将样式标签插入到header
    insertAt: 'top',
    //将所有style标签合成为一个
    singleton: true,
    plugins: () => [
      require('autoprefixer')({
        //配置浏览器版本
        browsers: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'],
      }),
    ],
  },
},

项目链接

https://github.com/AdolescentJou/webpack-base-demo

最后

感谢你能看到这里,本文总结了优化运行体验的几种配置,希望对你有所帮助,之后会陆续更新其他webpack相关的文章。

参考链接

https://webpack.docschina.org

https://juejin.cn/post/7023242274876162084#heading-52

0 人点赞