webpack的性能优化(一)——分包优化

这篇具有很好参考价值的文章主要介绍了webpack的性能优化(一)——分包优化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.什么是分包?为什么要分包?

        默认情况下,Webpack 会将所有代码构建成一个单独的包,这在小型项目通常不会有明显的性能问题,但伴随着项目的推进,包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这种将所有资源打包成一个文件的方式存在两个弊端:

  • 资源冗余:客户端必须等待整个应用的代码包都加载完毕才能启动运行,但可能用户当下访问的内容只需要使用其中一部分代码
  • 缓存失效:将所有资源达成一个包后,所有改动 —— 即使只是修改了一个字符,客户端都需要重新下载整个代码包,缓存命中率极低

        这些问题都可以通过代码分离解决,例如 node_modules 中的资源通常变动较少,可以抽成一个独立的包,那么业务代码的频繁变动不会导致这部分第三方库资源被无意义地重复加载。

代码分离(Code Splitting) 是webpack一个非常重要的特性:
  • 它主要的目的是将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件; 比如默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载, 就会影响首页的加载速度;
  • 代码分离可以分出出更小的bundle,以及控制资源加载优先级,提供代码的加载性能; 
Webpack中常用的代码分离有三种:
  • 入口起点:使用entry配置手动分离代码;
  • 防止重复:使用Entry Dependencies或者SplitChunksPlugin去重和分离代码;
  • 动态导入:通过模块的内联函数调用来分离代码;

2.配置多入口

入口起点的含义非常简单,就是配置多入口:
  • 比如配置一个index.js和main.js的入口;
  • 他们分别有自己的代码逻辑;
const path = require('path'); 
module.exports = { 
    entry: { 
        main: './src/main.js', // 第一个入口起点 
        app: './src/app.js' // 第二个入口起点 
    }, 
   output: { 
       filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应 
       path: path.resolve(__dirname, 'build') 
    } ,
   };
  • 假如我们的index.js和main.js都依赖两个库:lodash、dayjs
  • 如果我们单纯的进行入口分离,那么打包后的两个bunlde都有会有一份lodash和dayjs;
事实上我们可以对他们进行共享;
const path = require('path'); 
module.exports = { 
    entry: { 
        main: { import: './src/main.js', dependOn: 'shared' }, // 第一个入口起点 
        app:  { import: './src/app.js', dependOn: 'shared' }, // 第二个入口起点 
        shared: ['dayjs', 'lodash'] // 共享的库
    }, 
   output: { 
       filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应 
       path: path.resolve(__dirname, 'dist') } 
   };

3.SplitChunks

        Webpack 提供了 SplitChunkPlugin 进行分包优化。SplitChunksPlugin 插件可以将应用程序中共享的代码拆分成单独的块,以便将其从应用程序代码中分离出来,从而提高性能和加载速度。         该插件webpack已经默认安装和集成,所以我们并不需要单独安装和直接使用该插件,只需要提供SplitChunksPlugin 相关的配置信息即可。

  • Webpack提供了SplitChunksPlugin默认的配置,我们也可以手动来修改它的配置:
  • 比如默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all;

SplitChunksPlugin默认的配置

const { resolve } = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build')
  },
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          namw:'', // 用在filename中的name占位符
          fileName: 'vender_[id]_[name].js', //打包之后的文件名
          reuseExistingChunk: true, 
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },

  },
};

一些常见的配置项

属性名
splitChunks.chunks
  • async:只拆分异步导入的模块。
  • initial:只拆分同步导入的模块。
  • all:拆分所有模块,无论是同步还是异步导入的。
splitChunks.minSize

拆分出来的这个包的最小尺寸为minSize(以 bytes 为单位)

如果一个包拆分出来达不到minSize,那么这个包就不会拆分;
splitChunks.maxSize

将大于maxSize的包, 拆分成不小于minSize的包

splitChunks.minChunks
至少被引入的次数,默认是1;
如果我们写一个2,但是引入了一次,那么不会被单独拆分;
splitChunks.maxAsyncRequests 最大的初始化请求数量
splitChunks.cacheGroups 用于对拆分的包进行分组

cacheGroups

        用于对拆分的包就行分组,比如一个lodash在拆分之后,并不会立即打包,而是会等到有没有其他符合规则的包一起来打包
  • test属性:匹配符合规则的包;
  • name属性:拆分包的name属性;
  • filename属性:拆分包的名称,可以自己使用placeholder属性;
  • priority一个模块可以属于多个cacheGroups。优化将优先考虑具有更高 priority(优先级)的cacheGroups。默认组的优先级为负,自定义组的默认值为 0;
  • reuseExistingChunk:如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块。这可能会影响 chunk 的结果文件名;

更多的配置可以参考:

SplitChunksPlugin | webpack 中文文档 (docschina.org)

4.动态导入

        当代码中存在不确定会被使用的模块时,最佳做法是将其分离为一个独立的 JavaScript 文件。

  • 这样可以确保在不需要该模块时,浏览器不会加载或处理该文件的 JavaScript 代码。
  • 我们平时使用的路由懒加载的就是这个原理,都是为了优化性能而延迟加载资源。

实现动态导入的方式是使用ES6的import()语法来完成。

注意:使用动态导入bar.js:
  • 在webpack中,通过动态导入获取到一个对象
  • 真正导出的内容,在该对象的default属性中,所以我们需要做一个简单的解构;

4.1 路由懒加载

动态导入最常见的使用场景就是路由懒加载

// main.js文件中
const homeBtn = document.createElement('button')
const aboutBtn = document.createElement('button')
homeBtn.textContent = '加载home文件'
aboutBtn.textContent = '加载about文件'

document.body.appendChild(homeBtn)
document.body.appendChild(aboutBtn)

homeBtn.addEventListener('click', () => {
    import('./views/home.js')
})

aboutBtn.addEventListener('click', () => {
    import('./views/about.js')
})

打包之后的资源: 

webpack的性能优化(一)——分包优化,webpack学习笔记,webpack,前端

4.2 配置打包文件的名称

但是我们会发现一个问题,从包名中无法区分是哪个文件构建后的包,我们可以通过以下方式修改打包之后的文件名:

  • output.chunkFilename
const { resolve } = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build'),
    chunkFilename: 'chunk_[name]_[id].js',
  },
};

默认情况下我们获取到的 [name][id] 的名称保持一致的,如果我们希望修改name的值,可以通过magic comments(魔法注释)的方式;

  • webpackChunkName 魔法注释
// main.js
homeBtn.addEventListener('click', () => {
    import(/* webpackChunkName: "home" */'./views/home.js') // 让webpack读取的魔法注释,固定写法
})

aboutBtn.addEventListener('click', () => {
    import(/* webpackChunkName: "about" */'./views/about.js')
})

打包之后的资源,可以从名称看出原始文件是哪一个 

webpack的性能优化(一)——分包优化,webpack学习笔记,webpack,前端

4.3 prefetch(预获取)

prefetch被用于懒加载策略。它会在浏览器空闲时,即浏览器已经加载主要资源并且有剩余带宽时,开始加载。这意味着它不会影响初始页面加载时间,因为它是在后台加载的。通常用于加载将来可能需要的资源,例如懒加载的代码块或其他不太紧急的资源。

4.4 preload(预加载)

preload是告诉浏览器预先请求当前页面需要的资源,通常是当前页面渲染所必需的关键资源,如字体、样式表或脚本。它会在当前页面加载时立即开始加载,而不需要等待解析完js或者css之后再去加载对应的资源。并且不管浏览器的空闲状态如何。因此,preload可能会影响初始页面加载性能,因为它可以竞争主要资源的带宽。。

import(/* webpackPrefetch: true */ './view/home');
import(/* webpackPreload: true */ './view/about');

5.runtime代码的分包

配置 runtime 相关的代码是否抽取到一个单独的chunk中:
  • runtime相关的代码指的是在运行环境中,对模块进行解析加载、模块信息相关的代码;
  • 比如我们的component、bar两个通过import函数相关的代码加载,就是通过runtime代码完成的;
runtime抽离出来后,有利于浏览器的缓存策略
  • 比如我们修改了业务代码(main),那么runtime和component、bar的chunk是不需要重新加载的;
  • 比如我们修改了component、bar的代码,那么main中的代码是不需要重新加载的;
const { resolve } = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build')
  },
  optimization: {
    runtimeChunk: 'true/multiple' //针对每个入口打包一个runtime文件
    runtimeChunk: 'single'  //打包一个runtime文件
    runtimeChunk: {
      name: function(entrypoint) {
        return `my-${entrypoint.name}` // 决定runtimeChunk的名称
      }
    }

  },
};
设置的值:
  • true/multiple:针对每个入口打包一个runtime文件;
  • single:打包一个runtime文件;
  • 对象:name属性决定runtimeChunk的名称;

6.将css提取到一个独立的css文件

我们平时在打包css文件时,是通过css-loaderstyle-loader进行如下配置,最终会把css注入到页面中,

const { resolve } = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
        {	//通过正则告诉webpack匹配是什么文件
            test: /\.css$/,
            use: [
             //  因为loader的执行顺序是从右向左(或者说从下到上,或者说从后到前							 的),所以我们需要将style-loader写到css-loader的前面;
                { loader: 'style-loader' },
                { loader: 'css-loader' }
            ]
        }
    ]
},
};

如果将css单独打包到一个css文件中有如下好处:

  • 分离结构和样式:将CSS独立出来可以将网页的结构(HTML)和样式(CSS)分开,使代码更加模块化和易于维护。
  • 缓存优化:独立的CSS文件可以被浏览器缓存,当用户再次访问网站时,可以减少加载时间,提高性能。
MiniCssExtractPlugin 可以帮助我们将css提取到一个独立的css文件中,该插件需要在webpack4+才可以使用。
  • 首先,我们需要安装 mini-css-extract-plugin:
npm install mini-css-extract-plugin -D
  • 配置rules和plugins:
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
        {
            test: /\.css$/,
            use: [
                // 将CSS样式提取为单独的CSS文件,通过链接方式(link)引入到HTML中
                { loader: MiniCssExtractPlugin.loader },  
                { loader: 'css-loader' }
            ]
        }
    ]
},
  plugins: [
      new MiniCssExtractPlugin({ // 使用MiniCssExtractPlugin插件
                filename: "css/[name]_[id].css",  // 打包后的css文件放到css文件夹中
                chunkFilename: "css/[name]_[id].css"
              }
           )
        ],
};

打包之后,css被单独打包到build/css/main_179.css 

webpack的性能优化(一)——分包优化,webpack学习笔记,webpack,前端

参考:

Webpack 优化实操(十一):页面分包优化 - 知乎 (zhihu.com)

webpack性能优化(一):分包 - 掘金 (juejin.cn)文章来源地址https://www.toymoban.com/news/detail-783068.html

到了这里,关于webpack的性能优化(一)——分包优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【前端工程化面试题】使用 webpack 来优化前端性能/ webpack的功能

    这个题目实际上就是来回答 webpack 是干啥的,你对webpack的理解,都是一个问题。 (1)对 webpack 的理解 webpack 为啥提出 + webpack 是啥 + webpack 的主要功能 前端开发通常是基于模块化的,为了提高开发效率,webpack 是一个基于模块的构建工具,是一个用于 js 应用程序的静态模块

    2024年02月20日
    浏览(58)
  • webpack基础知识八:说说如何借助webpack来优化前端性能?

    一、背景 随着前端的项目逐渐扩大,必然会带来的一个问题就是性能 尤其在大型复杂的项目中,前端业务可能因为一个小小的数据依赖,导致整个页面卡顿甚至奔溃 一般项目在完成后,会通过webpack进行打包,利用webpack对前端项目性能优化是一个十分重要的环节 二、如何优

    2024年02月14日
    浏览(40)
  • 前端知识点、技巧、webpack、性能优化(持续更新~)

    可以把  图片转换成  base64  放在src里面   减少服务器请求  但是图片会稍微大一点点 以上的方法不需要一个一个自己转化 可以在webpack  进行 性能优化   (官网有详细描述)

    2024年03月10日
    浏览(46)
  • 用webpack做一些前端打包时的性能优化

    一.webpack 的五个核心概念 1.Entry:入口指示,webpack以哪个文件为入口起点开始打包,分析构建内部依赖图 2.output:输出指示,webpack打包后的资源bundles输出到哪里去,以及如何命名 3.loader :loader让webpack能够去处翻译理那些非js文件(img css…) 4.Plugins :Plugins插件可以用于执行范围

    2024年02月12日
    浏览(50)
  • webpack性能优化方案(详细)

    💂 个人网站:【紫陌】【笔记分享网】 💅 想寻找共同学习交流、共同成长的伙伴,请点击【前端学习交流群】 文章最后有作者l联系方式(备注进群) webpack的性能优化较多,我们可以对其进行分类: 优化一:打包后的结果,上线时的性能优化。(比如分包处理、减小包体

    2024年02月16日
    浏览(34)
  • webpack5性能优化

     注意:开启缓存,配置后打包是就能缓存babel webpack.common.js文件命中缓存cacheDirectory         Directory/dəˈrektəri/目录;   测试:  打包后的结果:  注意:打包后promise的打包文件会变化文件名    注意:引入第三方模块,模块可能有许多东西是我们不需要的,而引入时会默认

    2024年02月16日
    浏览(45)
  • 【万字解析】Webpack 优化构建性能(分析->优化)

    全局安装 webpack-bundle-analyzer 插件 运行 webpack-bundle-analyzer 开始打包,需要获取所有的依赖模块 搜索所有的依赖项,这需要占用一定的时间,即搜索时间,那么就确定了: 需要优化的第一个时间就是 搜索时间 。 解析所有的依赖模块(解析成浏览器可运行的代码) Webpack 根据

    2024年01月21日
    浏览(48)
  • 性能优化-webpack配置gzip

    3步搞定,实测1.3Mjs压缩到363k,体积减少70% 1.装包 yarn add compression-webpack-plugin --dev 2.配置webpack 打开config/webpack.config.js 1)在 module.exports 导出函数前面引入插件 2)添加配置 位置,搜索new HtmlWebpackPlugin(在其上边添加配置

    2024年02月15日
    浏览(42)
  • umi 借助Webpack优化前端?

    2024年02月09日
    浏览(32)
  • 使用 Webpack 优化前端开发流程

    在现代前端开发中,构建工具的选择和优化流程的设计至关重要。Webpack 是一个功能强大的前端构建工具,能够优化我们的开发流程,提高开发效率和项目性能。本文将介绍如何使用 Webpack 来优化前端开发流程。 代码优化和资源管理也是前端项目中不可忽视的一部分。我们将

    2024年02月15日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包