说说如何借助webpack来优化前端性能?

1、如果可以的话,尽量使用高版本的 Webpack 和 Node.js;

2、多进程/多实例构建

HappyPack(多进程压缩优化打包速度的,不过现在已经不维护了)、thread-loader

3、压缩代码

        ① 图片压缩

一般使用 loader 进行压缩:例如配置 image-webpack-loader

        ② CSS压缩

通过 mini-css-extract-plugin 分离样式文件,将 CSS 提取为独立文件,支持按需加载;还通过 css-loader 的 minimize 选项开启 cssnano 压缩 CSS。

         ③ 开启多进程执行代码压缩,提升构建速度

webpack-paralle-uglify-plugin

terser-webpack-plugin 开启 parallel 参数,压缩 ES6

4、 Tree shaking 摇树

  • 打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的 bundle中去掉(只能对 ES6 Modlue 生效) ,所以开发中尽可能使用 ES6 Module 的模块,提高 tree shaking 效率
  • 禁用 babel-loader 的模块依赖解析,否则 Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking
  • 使用 PurifyCSS(不在维护) 或者 uncss 去除无用 CSS 代码

    • purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建议)

5、缩小打包作用域

  • 通过配置 exclude / include (缩小 loader 解析范围)
  • 配置resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)
  • 配置 IgnorePlugin (确定完全的排除模块)
  • 合理配置别名alias(减少查找过程
  • resolve.mainFields 只采用 main 字段作为入口文件描述字段 (减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段)
  • resolve.extensions 尽可能减少后缀尝试的可能性
  • noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)

6、充分利用缓存提升二次构建速度

  • 启用 babel-loader 的 cacheDirectory 开启缓存
  • terser-webpack-plugin 开启缓存
  • 使用 cache-loader 或者 hard-source-webpack-plugin

7、提取页面公共资源

  • 基础包分离:

    使用 html-webpack-externals-plugin,将基础包通过 CDN 引入,不打入 bundle 中;

    使用 SplitChunksPlugin 进行合理分包,提供代码的加载性能。该插件webpack已经默认安装和集成,只需要配置。

    使用 DllPlugin 进行分包,使用 DllReferencePlugin(索引链接) 对 manifest.json 引用,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。

    通常来说,我们的代码都可以至少简单区分成业务代码和第三方库。如果不做处理,每次构建时都需要把所有的代码重新构建一次,耗费大量的时间。然后大部分情况下,很多第三方库的代码并不会发生变更(除非是版本升级),这时就可以用到dll;

    把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。

    使用 dll 时,构建过程分成 dll 构建过程和主构建过程,所以需要两个构建配置文件,例如叫做webpack.config.js和webpack.dll.config.js。

    步骤:

    使用DLLPlugin进行分包,对第三方包打包,完成后打包结果保存在项目中,后面就不需要再构建第三方包了。每次构建业务项目时候,使用 DllReferencePlugin 实现对构建好的第三方包dll的解析和处理。

  • HashedModuleIdsPlugin 可以解决模块数字id问题
  • Scope hoisting

「作用域提升」将每个模块都提升到引入者顶部,这样模块不会因为依赖链路较深而导致调用栈变深,它们都在同一层。

  • 构建后的代码会存在大量闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销变大。Scope hoisting 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突
  • 必须是ES6的语法,因为有很多第三方库仍采用 CommonJS 语法,为了充分发挥 Scope hoisting 的作用,需要配置 mainFields 对第三方模块优先采用 jsnext:main 中指向的ES6模块化语法
  • 动态Polyfill

    • 建议采用 polyfill-service 只给用户返回需要的polyfill,社区维护。 (部分国内奇葩浏览器UA可能无法识别,但可以降级返回所需全部polyfill)

8、关闭 sourceMap

关闭生成 map 文件 可以达到缩小打包体积。这个生产环境一定要关闭,不然打包的产物会很大。

9、webpack 长缓存优化

js文件使用 chunkhash,不使用 hash;
css文件使用 contenthash,不使用chunkhash,不受js变化影响;

提取vendor,公共库不受业务模块变化影响;
内联webpack runtime 到页面,chunkld 变化不影响 vendor;
保证module ld稳定,不使用数字作为模块 id,改用文件内容的 hash值,使用HashedModuleldsPlugin,模块的新增或删除,会导致其后面的所有模块 id 重新排序,为避免这个问题;
保证chunkhash稳定,使用webpack-chunk-hash,替代 webpack自己的 hash算法,webpack 自己的 hash 算法,对于同一个文件,在不同开发环境下,会计算出不用的 hash 值,不能满足跨平台需求。

8、打包优化(主要是 webpack 优化)

拆包 extemals dllPlugin;

提取公共包 commonChunkPlugin 或 splitChunks;
缩小范围 各种 loader 配置 include和 exclude,noParse 跳过文件;
开启缓存 各种 loader 开启 cache;多线程加速 happypack或 thead-loader;
Scope Hoisting ES6 模块分析,将多个模块合并到一个函数里,减少内存占用,减小体积,提示运行速度

 ① webpack优化:resolve.alias配置(vite同理)

resolve.alias 配置通过别名来将原导入路径映射成一个新的导入路径。
可以起到两个作用:【起别名;减少查找过程】例如:

resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
② webpack优化:resolve.extensions配置(vite同理)

resolve.extensions 代表后缀尝试列表,它也会影响构建的性能,默认是:extensions: ['.js', '.json']

例如遇到 require('./data') 这样的导入语句时,Webpack会先去寻找 ./data.js 文件,如果该文件不存在就去寻找 ./data.json 文件,如果还是找不到就报错。
 

【所以后缀尝试列表要尽可能的小,不要把项目中不可能存在的情况写到后缀尝试列表中,频率出现最高的文件后缀要优先放在最前面,以做到尽快的退出寻找过程。】


在源码中写导入语句时,要尽可能的带上后缀,从而可以避免寻找过程。例如在你确定的情况下把require('./data')写成require('./data.json')。

resolve: {
    extensions: ['.js', '.vue', '.json'],
}
③ webpack优化:缩小 loader 范围

loader 是很消耗性能的一个点,我们在配置 loader 的时候,可以使用 include 和 exclude 来缩小loader 执行范围,从而优化性能。 例如:

{
    test: /\.svg$/,
    loader: 'svg-sprite-loader',
    include: [resolve('src/icons')]
 },
④ split chunks 代码分包

在没配置任何东西的情况下,webpack 4 就智能的帮你做了代码分包。入口文件依赖的文件都被打包进了main.js,那些大于 30kb 的第三方包,如:echarts、xlsx、dropzone等都被单独打包成了一个个独立 bundle。 其它被我们设置了异步加载的页面或者组件变成了一个个chunk,也就是被打包成独立的bundle。 它内置的代码分割策略是这样的:

新的 chunk 是否被共享或者是来自 node_modules 的模块;
新的 chunk 体积在压缩之前是否大于 30kb;
按需加载 chunk 的并发请求数量小于等于 5 个;
页面初始加载时的并发请求数量小于等于 3 个;

大家可以根据自己的项目环境来更改配置。webpack配置代码如下:

splitChunks({
  cacheGroups: {
    vendors: {
      name: `chunk-vendors`,
      test: /[\\/]node_modules[\\/]/,
      priority: -10,
      chunks: 'initial',
    },
    dll: {
      name: `chunk-dll`,
      test: /[\\/]bizcharts|[\\/]\@antv[\\/]data-set/,
      priority: 15,
      chunks: 'all',
      reuseExistingChunk: true
    },
    common: {
      name: `chunk-common`,
      minChunks: 2,
      priority: -20,
      chunks: 'all',
      reuseExistingChunk: true
    },
  }
})

没有使用webpack4.x版本的项目,可以通过按需加载的形式进行分包:
webpack如何使用按需加载

vite配置代码如下:

 build: {
    rollupOptions: {
      output: {
        chunkFileNames: 'js/[name]-[hash].js',  // 引入文件名的名称
        entryFileNames: 'js/[name]-[hash].js',  // 包的入口文件名称
        assetFileNames: '[ext]/[name]-[hash].[ext]' // 资源文件像 字体,图片等
      }
    }
 }
⑤ tree shaking

tree shaking(摇树)。望文生义,它是用来清除我们项目中的一些无用代码,它依赖于ES中的模块语法得以实现。 比如日常使用 lodash 的时候:

import _ from 'lodash'

如果如上引用 lodash 库,在构建包的时候是会把整个 lodash 包打入到我们的 bundle 包中的。

import _isEmpty from 'lodash/isEmpty';

如果如上引用 lodash 库,在构建包的时候只会把 isEmpty 这个方法抽离出来再打入到我们的bundle包中。

tree shaking可以大大减少包体积,是性能优化中的重要一环。 在 vite 和 webpack4.x 中都已经默认开启 tree-shaking。

⑥ vite关闭一些打包配置项

webpack也有类似的配置,自行查阅

build: { 
      terserOptions: {
        compress: {
          //生产环境时移除console
          drop_console: true,
          drop_debugger: true,
        },
      },
      //关闭文件计算
      reportCompressedSize: false,
      //关闭生成map文件 可以达到缩小打包体积
      sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
}

通过webpack优化前端的手段有:

① JS代码压缩        ② CSS代码压缩        ③ HTML文件代码压缩

④ 文件大小压缩     ⑤ 图片压缩               ⑥ Tree Shaking

⑦ 代码分离            ⑧ 内联 chunk

1、JS代码压缩

terser是一个JavaScript的解释、绞肉机、压缩机的工具集,可以帮助我们压缩、丑化我们的代码,让bundle更小。

production模式下,webpack 默认就是使用 TerserPlugin 来处理我们的代码的。如果想要自定义配置它,配置方法如下:

const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
    ...
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin({
                parallel: true // 电脑cpu核数-1
            })
        ]
    }
}

属性介绍如下:

  • extractComments:默认值为true,表示会将注释抽取到一个单独的文件中。开发阶段可设置为 false,不保留注释
  • parallel:使用多进程并发运行提高构建的速度,默认值是true。并发运行的默认数量: os.cpus().length - 1
  • terserOptions:设置我们的terser相关的配置:
  • compress:设置压缩相关的选项,mangle:设置丑化相关的选项,可以直接设置为true
  • mangle:设置丑化相关的选项,可以直接设置为true
  • toplevel:底层变量是否进行转换
  • keep_classnames:保留类的名称
  • keep_fnames:保留函数的名称

2、CSS代码压缩

CSS压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等。

CSS的压缩我们可以使用另外一个插件:CssMinimizerPlugin

配置方法如下:

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
    // ...
    optimization: {
        minimize: true,
        minimizer: [
            new CssMinimizerPlugin({
                parallel: true
            })
        ]
    }
}

3、HTML文件代码压缩

使用 HtmlWebpackPlugin插件来生成HTML的模板时候,通过配置属性minify进行html优化。

module.exports = {
    ...
    plugin:[
        new HtmlwebpackPlugin({
            ...
            minify:{
                minifyCSS:false, // 是否压缩css
                collapseWhitespace:false, // 是否折叠空格
                removeComments:true // 是否移除注释
            }
        })
    ]
}

 设置了minify,实际会使用另一个插件html-minifier-terser

4、文件大小压缩

对文件的大小进行压缩,减少http传输过程中宽带的损耗。一般使用 CompressionPlugin 插件。

npm install compression-webpack-plugin -D
new CompressionPlugin({
    test:/\.(css|js)$/,  // 哪些文件需要压缩
    threshold:500, // 设置文件多大开始压缩
    minRatio:0.7, // 至少压缩的比例
    algorithm:"gzip", // 采用的压缩算法
})

5、图片压缩

一般来说在打包之后,一些图片文件的大小是远远要比 js 或者 css 文件要来的大,所以图片压缩较为重要。一般使用loader进行压缩:file-loader 和 image-webpack-loader

配置方法如下:

module: {
  rules: [
    {
      test: /\.(png|jpg|gif)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[name]_[hash].[ext]',
            outputPath: 'images/',
          }
        },
        {
          loader: 'image-webpack-loader',
          options: {
            // 压缩 jpeg 的配置
            mozjpeg: {
              progressive: true,
              quality: 65
            },
            // 使用 imagemin**-optipng 压缩 png,enable: false 为关闭
            optipng: {
              enabled: false,
            },
            // 使用 imagemin-pngquant 压缩 png
            pngquant: {
              quality: '65-90',
              speed: 4
            },
            // 压缩 gif 的配置
            gifsicle: {
              interlaced: false,
            },
            // 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
            webp: {
              quality: 75
            }
          }
        }
      ]
    },
  ]
} 

6、Tree Shaking

Tree Shaking 是一个术语,在计算机中表示消除死代码,依赖于ES Module的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)

webpack实现Tree shaking有两种不同的方案:

① usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化的

配置方法也很简单,只需要将usedExports设为true

module.exports = {
    ...
    optimization:{
        usedExports: true
    }
}

使用之后,没被用上的代码在webpack打包中会加入unused harmony export mul注释,用来告知 Terser 在优化时,可以删除掉这段代码

② sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用

sideEffects用于告知webpack compiler哪些模块时有副作用。

配置方法是在package.json中设置sideEffects属性

如果sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports

如果有些文件需要保留,可以设置为数组的形式

"sideEffects":[
    "./src/util/format.js",
    "*.css" // 所有的css文件
]

上述都是关于javascripttree shakingcss同样也能够实现tree shaking

③ css tree shaking

css进行tree shaking优化可以安装 PurgeCss插件

npm install purgecss-plugin-webpack -D
const PurgeCssPlugin = require('purgecss-webpack-plugin')
module.exports = {
    ...
    plugins:[
        new PurgeCssPlugin({
            path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true} // src里面的所有文件
            safelist:function(){
                return {
                    standard:["html"]
                }
            }
        })
    ]
}

  • paths:表示要检测哪些目录下的内容需要被分析,配合使用glob
  • 默认情况下,Purgecss会将我们的html标签的样式移除掉,如果我们希望保留,可以添加一个safelist的属性

7、代码分离

将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件。

默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度。

代码分离可以分离出更小的bundle,以及控制资源加载优先级,提供代码的加载性能。

这里通过splitChunksPlugin来实现,该插件webpack已经默认安装和集成,只需要配置即可。

默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all

module.exports = {
    ...
    optimization:{
        splitChunks:{
            chunks:"all"
        }
    }
}

 splitChunks主要属性有如下:

  • Chunks:对同步代码还是异步代码进行处理(默认针对异步代码)
  • minSize: 拆分包的大小, 至少为minSize。如果包的大小不超过minSize,这个包不会拆分
  • maxSize: 将大于maxSize的包,拆分为不小于minSize的包
  • minChunks:被引入的次数,默认是1

8、内联chunk

可以通过InlineChunkHtmlPlugin插件将一些chunk的模块内联到html,如runtime的代码(对模块进行解析、加载、模块信息相关的代码),代码量并不大,但是必须加载的

const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    ...
    plugin:[
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/]
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了优化前端性能Webpack可以采取多种措施。首先,通过代码压缩、合并和缓存控制,可以减少文件大小并提高加载速度。例如,可以使用Webpack的压缩插件(如UglifyJS)来压缩JavaScript代码,并使用提取公共代码的功能来减少重复代码的加载。这样可以减小文件体积并提升页面加载速度。 其次,Webpack还支持使用ES6或CoffeeScript等高级语言来编写源码,并将其构建成浏览器支持的ES5代码,从而提高开发效率和代码质量。这可以通过使用Babel等工具和Webpack的loader来实现。 此外,Webpack还支持CSS的压缩。可以使用插件(如css-minimizer-webpack-plugin)来去除无用的空格,减小CSS文件的大小。这样可以提高页面的加载速度。 最后,对于HTML文件,Webpack也可以进行压缩。可以使用插件(如html-minimizer-webpack-plugin)来去除HTML文件中的无用空格、注释等,从而减小文件大小。这样可以加快页面加载速度。 综上所述,通过使用Webpack的各种优化手段,可以有效地提升前端项目的性能,加快页面加载速度,提高用户体验。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【前端知识之webpackwebpack如何优化前端性能](https://blog.csdn.net/weixin_44337386/article/details/125845074)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [webpack学习教程之前端性能优化总结](https://download.csdn.net/download/weixin_38656364/14902051)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值