前端性能优化(五):webpack构建优化

news2025/1/17 6:06:06

目录

一:webpack的优化配置

1.1.Tree-shaking

1.2.JS压缩

1.3.作用域提升

1.4.Babel 优化配置

二:webpack的依赖优化

2.1.noParse(不解析)

2.2.DllPlugin

三:webpack 细节优化

四:webpack的资源压缩

4.1.Terser 压缩 JS

4.2.mini-css-extract-plugin 压缩 CSS

4.3.HtmlWebpackPlugin-minify 压缩 HTML

五:基于webpack的资源持久化缓存

六:基于webpack的应用大小检测与分析

七:React 按需加载的实现方式


一:webpack的优化配置

webpack4 引入了 mode 模式,可以配置开发和生产模式,就可以使用一些已经默认好的插件帮我们达到想做的效果

1.1.Tree-shaking

是一个减小资源体积很有效的办法,因为有很多代码在最终生产的包里是用不到的,那在打包前可以对其进行处理,把用不到的代码给去掉

前提:无论是自己还是第三方,必须是模块化的,要基于 ES6 import export 导入导出的形式才可以,生产模式会默认启动 Tree-shaking,主要依赖于TerserPlugin插件

原理:从 index.js 开始,去看引用了哪些东西,进一步分析所有引入的包或模块里又引用了哪些模块或其他一些包,最后会把需要的东西都留下

由于Tree-shaking的实现是基于一定的规则,但在 JS 里,可能会涉及到修改全局作用域(window 对象),如果把这个 shake 掉,代码就会出现问题,这时就需要使用 sideEffects来告诉 webpack 哪些文件不需要 shake

package.json中配置sideEffects

"sideEffects": [
  "*.css"
]

注意 Babel 默认配置的影响

babel.config.js中,其中的presets会把常用的 babel 插件做一个集合。但它有个问题:在转码时会把 ES6 模块化的语法转换成其他语法,我们希望保留 ES6 模块化语法,所以要加上modules:false,这样 Tree-shaking 才能起到作用

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
        targets: {
          browsers: ['>0.25%'],
        },
        useBuiltIns: 'usage',
        bugfixes: true,
      },
    ],
    '@babel/preset-react',
  ],
  plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-transform-runtime'],
}

1.2.JS压缩

terser-webpack-plugin

支持压缩 ES6 (Webpack4),terser 无论从销量还是效果上都比 uglifyjs 好,所以 terser 后面作为生产模式下默认的压缩插件,主要作用就是减少JS的文件体积

1.3.作用域提升

  • 减小代码体积

    减少调用关系逻辑上的代码,把一些函数进行合并

  • 提高执行效率

    要进行引用的话,会花时间进行查找

  • 同样注意 Babel 的 modules 的配置

    需要加上modules:false的配置

/**************** util.js ********************/
export default 'Hello,Webpack';

/**************** index.jsx ******************/
import str from './util';
console.log(str);

/***************** 没有 scope hoisting, webpack 打包后 *******************/
[
  (function (module, __webpack_exports__, __webpack_require__) {
    var __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(1);
    console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);
  }),
  (function (module, __webpack_exports__, __webpack_require__) {
    __webpack_exports__["a"] = ('Hello,Webpack');
  })
]
/************************************/

/***************** 有 scope hoisting, webpack 打包后 ********************/
[
  (function (module, __webpack_exports__, __webpack_require__) {
    var util = ('Hello,Webpack');
    console.log(util);
  })
]
/************************************/

没有启用作用域提升的话,会把这两个模块打成单独的模块,当其中一个依赖到另一个时,会把依赖到的模块 require 进来,再通过 require 进来的模块进行调用;启用作用域提升,会做一个合并和分析,发现有这种依赖调用时,试图把依赖合并到调用里,最终变得更加精简

1.4.Babel 优化配置

1.在需要的地方引用 polyfill

polyfill 是兼容旧浏览器去进行新功能或新规范的实现。由于这个比较大,需要把所有涉及到的东西都引进来,但我们用到的可能是其中比较小的部分,这时需要在babel.config.js配置 useBuiltIns: 'usage' 即可

2.辅助函数的按需引入

babel转码后对辅助函数的一个复用,在babel.config.js配置 @babel/plugin-transform-runtime插件即可

3.根据目标浏览器按需转换代码

在preset-env里配置targets: { browsers: ['>0.25%'], },即对市场份额超 0.25% 的浏览器进行支持

二:webpack的依赖优化

使用webpack打包完之后会得到一定的优化,但是在webpack打包的过程中也可以进行一定的优化

2.1.noParse(不解析)

  • 提高构建速度

  • 直接通知 webpack 忽略较大的库

    通常是第三方的一些类库,一般是比较大的库,且没用模块化的方式去编写,那么它本身也不会有外部的依赖,所以我们就可以不对它进行解析

  • 被忽略的库不能是模块化方式编写的,即不能有 import、require、define 的引入方式

module: {
  noParse: /lodash/, // loadsh比较独立
  noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/, // vue-cli里的配置
}

2.2.DllPlugin

将我们重复使用的库提取出来,变成一种引用的方式,这样我们就不用每次将这库重新构建,可以大大加速构建的过程

  • 避免打包时对不变的库重复构建

    比如:react 和 react-dom 其实从开始构建项目开始到最后上线都不太可能变了,我们可以对其进行动态链接库的引用,不再重复构建

  • 提高构建速度

  • 应用场景

    生产环境应用的可能性比较小,因为生产环境不会经常打包,但在开发的环境中用这个会更加合适

/* package.json */
{
  "scripts": {
    "dll-build": "cross-env NODE_ENV=production webpack --config webpack.dll.config.js"
  }
}

/* webpack.dll.config.js */
const path = require('path')
const webpack = require('webpack')
module.exports = {
  mode: 'production',
  entry: {
    react: ['react', 'react-dom'],
  },
  output: {
    filename: '[name].dll.js',
    path: path.resolve(__dirname, 'dll'),
    library: '[name]',
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]',
      path: path.resolve(__dirname, 'dll/[name].manifest.json'),
    }),
  ],
}

/* webpack.config.js */
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports = smp.wrap({
  plugins: [
    /* 动态链接库引用 */
    new DllReferencePlugin({
      manifest: require(`${__dirname}/dll/react.manifest.json`),
    }),
  ],
}

三:webpack 细节优化

代码拆分

  • 把单个 bundle文件拆分成若干个 bundles/chunks
  • 缩短首屏加载时间

webpack 代码拆分方法:

  • 手工定义入口
  • splitChunks 提取公有代码,拆分业务代码与第三方库

        1.把我们代码中重复使用的东西提取出来
        2.把我们这个业务逻辑与第三方依赖进行拆分
webpack 处理文件路径时,它们始终包含 Unix 系统中的 /Windows 系统中的 \,所以会在前面加上 [\\/]

chunks:有效值为 all、async、initial,initial同步加载,async异步加载

minChunks:拆分前必须共享模块的最小 chunks 数

module.exports = smp.wrap({
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendor',
          test: /[\\/]node_modules[\\/]/,
          minSize: 0,
          minChunks: 1,
          priority: 10,
          chunks: 'initial',
        },
        common: {
          name: 'common',
          test: /[\\/]src[\\/]/,
          chunks: 'all',
          minSize: 0,
          minChunks: 2,
        },
      },
    },
  },
})
  • 动态加载
<Suspense fallback={<div>Loading...</div>}>
  <Card
    key={panel.name}
    image={panel.image}
    title={panel.name}
    route={panel.route}
    description={panel.body}
  />
</Suspense>

四:webpack的资源压缩

  • Terser 压缩 JS
  • mini-css-extract-plugin 压缩 CSS
  • HtmlWebpackPlugin-minify 压缩 HTML

webpack4 mode

4.1.Terser 压缩 JS

mode: 'production'一行代码等同于下面写的所有代码

// webpack.production.config.js
module.exports = {
  mode: 'production',
  performance: {
    hints: 'warning',
  },
  output: {
    pathinfo: false,
  },
  optimization: {
    namedModules: false,
    namedChunks: false,
    nodeEnv: 'production',
    flagIncludedChunks: true,
    occurrenceOrder: true,
    sideEffects: true,
    usedExports: true,
    concatenateModules: true,
    splitChunks: {
      hidePathInfo: true,
      minSize: 30000,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
    },
    noEmitOnErrors: true,
    checkWasmTypes: true,
    minimize: true,
  },
  plugins: [
    new TerserPlugin(/* ... */),
    new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
    new webpack.optimize.ModuleConcatenationPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
  ],
}

4.2.mini-css-extract-plugin 压缩 CSS

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].[chunkhash:8].css',
    }),
    new OptimizeCssAssetsPlugin({
      cssProcessorPluginOptions: {
        preset: ['default', { discardComments: { removeAll: true } }],
      },
      canPrint: true,
    }),
  ]
}

4.3.HtmlWebpackPlugin-minify 压缩 HTML

minification

{
  collapseWhitespace: true, // 移除空格、换行符
  keepClosingSlash: true, // 保留元素的末尾斜杠
  removeComments: true, // 移除注释
  removeRedundantAttributes: true, // 移除冗余属性(默认值)
  removeScriptTypeAttributes: true, // 移除script标签中的type属性
  removeStyleLinkTypeAttributes: true, // 移除style标签中的type属性
  useShortDoctype: true // 使用html5短的描述方式
}

五:基于webpack的资源持久化缓存

  • 每次打包的资源文件有唯一的 hash 值
  • 修改后只有受影响到的文件 hash 变化
  • 充分利用浏览器缓存

hash 特点:离散唯一的值,如果内容不变,计算出来的值也不变

contenthash:使即使同一个资源CSS、JS文件hash值也区分开来。会根据内容生成 hash,当只改 JS 时,进行重新打包后,CSS 就会保持原有的 hash 值。当更新部署时,就可以充分利用浏览器缓存,这样就可以保证用户体验且能进行一个平稳的更新过度

module.exports = {
  output: {
    path: `${__dirname}/build`,
    filename: '[name].[hash].bundle.js',
    chunkFilename: '[name].[chunkhash:8].bundle.js',
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash:8].css',
    }),
  ]
}

六:基于webpack的应用大小检测与分析

常用的工具:

  • Stats 分析与可视化图
  • webpack-bundle-analyzer 进行体积分析
  • speed-measure-webpack-plugin 速度分析

Webpack Chart

通过:webpack --profile --json > stats.json生成stats.json文件,之后将这个文件上传到这个网站即可

 这个可能还是不够细,想进一步分析可以使用 bundle-analyzer 工具实现,这里使用source-map-explorer进一步分析

npm i source-map-explorer

 这个分析不是基于我们的 bundle 文件,而是基于 sourcemap,需要需要生成 sourcemap

/* package.json */
{
  "scripts": {
    "analyze": "source-map-explorer 'build/*.js'"
  },
}

/* webpack.config.js */
module.exports = smp.wrap({
  mode: 'production',
  devtool: 'source-map'
}

 官方推荐的bundle-analyzer可以得到可视化图,不过相比 source-map-explorer 相比,它只能看个大概,少一些具体内容(大小)

速度分析可以使用speed-measure-webpack-plugin,运行npm run build 即可看到所有 plugins 和所有 loaders 的使用情况

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()

module.exports = smp.wrap({...})

七:React 按需加载的实现方式

  • React router 基于 webpack 动态引入
  • 使用 Reloadable 高级组件

代码拆分最初是为了解决一个过大请求的问题。通过一个请求,把整个包加载到首页,这时网络开销相对少但是包体积大,所以下载耗时长;我们可以把较大的包做拆解,拆分成若干个小包,小包只有被调用时才会加载(按需加载)。假如拆分水平定义到组件,那所有组件都被拆分成一个独立的模块,就会有很多 bundle 或 chunk,那就要发起若干个请求,开销会更大

通常最合理的方式是按照路由进行按需加载。只有当我们页面上的一些组件在不同路由的页面进行复用的时候,我们才把组件进行一个单独的拆解

import loadable from '@loadable/component'

// 使用React-Loadable动态加载组件
const LoadableAbout = loadable(() => import('./About.jsx'), {
  fallback: '<div>loading...</div>',
})
class App extends React.Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={LoadableAbout} />
        </Switch>
      </Router>
    )
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux和windows文件互传

文章目录一、方法1&#xff1a;设置共享剪切版二、方法2&#xff1a;使用FileZilla软件1.开启 Ubuntu 下的 FTP 服务2.查看Ubuntu的ip地址2.windows安装FileZilla注意一、方法1&#xff1a;设置共享剪切版 在Ubuntu20版本中好像已经自动实现 本人使用的是旧版18.4&#xff0c…

【每日十分钟前端】基础篇21,为什么HTTPS更安全(SSL原理)、单行/多行文本溢出的省略样式、DOM常见的操作有哪些

1、[HTML]为什么HTTPS更安全(SSL原理)&#xff1a;对称加密、非对称加密、摘要、数字签名、数字证书。 2、[CSS]单行/多行文本溢出的省略样式。 3、[JS]DOM常见的操作有哪些&#xff1f; 1、[HTML]为什么HTTPS更安全(SSL原理)&#xff1a; 对称加密&#xff1a;协商密钥对数据…

异常检测实战应用案例精讲-【工具篇】时序异常检测TODS

前言 时间序列异常值检测旨在识别数据中意外或罕见的实例。作为数据分析最重要的任务之一,异常值检测在时间序列数据上有多种应用,例如欺诈检测、故障检测和网络安全攻击检测。例如,雅虎 和微软 已经建立了自己的时间序列异常值检测服务来监控他们的业务数据并触发异常值…

Hudi、Iceberg底层索引Z-Order

目录 第一部分 数据库领域的Z-Order 1.1 最左匹配原则 1.2 Z-Order动机 1.3 OLTP 1.4 OLAP 第二部分 Z-Order效率分析 2.1 按照A进行查询 2.2 按照B进行查询 2.3 总结 第三部分 Z-Order缺陷 第四部分 总结及建议 参考文章 Z-Order最早是1966提出的一项将多维数据映…

数据分析-深度学习 Day1

目录&#xff1a;第一节 机器学习&深度学习介绍第二节 机器学习攻略一、机器学习的框架二、模型训练攻略三、针对Optimization Issue的优化&#xff0c;类神经网络训练不起来怎么办(一) 局部最优点和鞍点(二) 批处理和momentum(三) 自动调节学习率Learning rate(四) 损失函…

cmake的常用语法

cmake 的注释 # 注释 #[[大段注释 第二行注释 第三行注释]]cmake的log -message cmake messagemessage(arg1 arg2 arg3 arg4) # 会自动连起message 多级别输出 message(FATAL_ERROR,"abc") # 最严重的错误&#xff0c;直接停止执行 message(SEND_ERROR,"aba…

NOP+终于来了,看看蔚来随NOP+释放的数据和思考

1. 行驶数据 ADAS功能累计用户行驶里程4.9亿公里&#xff1b;NT1的NOP功能累计行驶2.3亿公里&#xff1b;NT2的Pilot功能累计行驶了1700万公里。2. 统一辅助驾驶软件架构原来NOP将直路行驶和匝道作为两个场景开发&#xff0c;场景分割思路了城区和低速就变得无穷无尽。新NOP是以…

K_A11_001 基于STM32等单片机驱动DHT11 串口与OLED0.96双显示

K_A11_001 基于STM32等单片机驱动DHT11 串口与OLED0.96双显示一、资源说明二、基本参数1.参数2.引脚说明三、驱动说明时序对应程序:四、部分代码说明1、接线说明1.1、STC89C52RCDHT11模块1.2、STM32F103C8T6DHT11模块五、基础知识学习与相关资料下载六、视频效果展示与程序资料…

锁的分类,以及锁升级原理

1. 前言 锁在并发编程中非常重要&#xff0c;但是锁的种类有点多。这边文章的目的就是为了梳理锁的分类以及 锁升级的原理。 2. 锁的分类 种类\名称synchronizedReentrantLockReentrantReadWriteLock可重入锁√√√不可重入锁乐观锁①①①悲观锁√√√公平锁√√非公平锁√√√…

javaweb-Servlet基本使用

1&#xff0c; Servlet 1.1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门动态web资源开发技术。 使用Servlet就可以实现&#xff0c;根据不同的登录用户在页面上动态显示不同内容。 Servlet是JavaEE规范之一&#xff0c;其实就是一个接口&#xff0c…

关于分组函数(聚合函数)

分组函数&#xff1a;也叫"多行处理函数"或"聚合函数" &#xff08;特点&#xff1a;输入多行&#xff0c;最终输出一行&#xff09; 用于对表中指定字段下的内容进行统计的函数。 - count() 计数&#xff08;返回指定字段下内容不为null的数…

一文看懂Linux内存管理:虚拟内存、用户空间、内核空间、用户态、内核态、IPC通信原理

目录 一、虚拟内存地址 1.为什么要有虚拟内存地址&#xff1f; 2.虚拟地址好处 二、用户空间和内核空间 1.概念 2.用户态和内核态 3.IPC通信原理 一、虚拟内存地址 1.为什么要有虚拟内存地址&#xff1f; 因为如果CPU直接访问物理内存&#xff0c;那如果两个进程写入一…

MSF客户端渗透

利用Acrobat Reader漏洞执行payload ● 构造PDF文件 exploit/windows/fileformat/adobe_utilprintf仅支持8.1.2软件版本和XP系统&#xff1b; ● 构造恶意网站 exploit/windows/browser/adobe_utilprintf#同理&#xff0c;浏览器上运行pDF● 之后可以通过Meterpreter进行下一…

克罗格 Kroger EDI需求分析及注意事项

项目背景 Kroger&#xff08;美国克罗格公司&#xff09;是具有百年历史的名店之一。它虽然历史悠久&#xff0c;但并没有被变化的世界所淘汰&#xff0c;相反&#xff0c;它围绕着市场消费需求的变化&#xff0c;不断地进行创新&#xff0c;创造了世界零售百年史上的若干个第…

Linux物理内存管理:page、zone、node

基本概念页&#xff1a;struct page &#xff0c;如下图所示&#xff0c;x86架构下一般为4K为大小分区&#xff1a;struct zone &#xff0c;如下图所示&#xff0c;x86架构下分为三个区 ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM内存节点&#xff1a;struct node。对于一个简单的嵌入…

杭州社保解读截止2023

杭州社保新政规定的社保内容以及缴费比例是怎样的? 1、养老保险&#xff1a;单位&#xff0c;14%;个人&#xff0c;8%。 2、医疗保险&#xff1a;单位&#xff0c;9.9%;个人&#xff0c;2% 。 3、失业保险&#xff1a;单位&#xff0c;0.5%;个人&#xff0c;0.5%。 4、工伤…

PC浏览器无法浏览网页的解决教程

前言 在浏览Potplayer官网和Github官网时&#xff0c;无论是火狐浏览器还是Edge浏览器&#xff0c;都无法正常链接到网站。以下教程不纠结具体原理&#xff0c;只介绍具体步骤&#xff0c;以便以后自查。而且以下教程以Github官网为例。 具体步骤 打开Chinese Firewall Test…

excel统计函数:应用广泛的动态统计之王OFFSET 上篇

【前言】OFFSET函数是判断Excel函数使用者是否进阶的一个重要函数之一。在实际工作中&#xff0c;如果你需要对工作中的数据文件进行系统化、自动化的建模&#xff0c;那么势必会使用这个函数。【功能及语法】OFFSET函数的功能是&#xff0c;以指定的引用为参照系&#xff0c;通…

你一定要知道这6个,高质量图片素材库

其实图片素材网站已经分享过很多次了&#xff0c;除了大家非常熟悉的 Pixabay、Pexels之外&#xff0c;其实还有很多优质的图片素材网。今天再给大家推荐几个&#xff0c;对你有帮助记得点赞、收藏哦&#xff01; 1、潮点视频 https://shipin520.com/shipin-tp/0-1329-0-0-0-…

轻松掌握Jenkins

Jenkins一、docker安装Jenkins1.linux2.web二、流水线1.gitlab连接jenkins1.jenkins服务器创建密钥2.将密钥添加到gitlab上3.创建gitlab访问令牌4.安装jenkins插件5.配置 GitLab 凭据2.创建流水线1.新增凭证配置 Username with password2.创建任务3.构建触发器4.构建5.配置gitl…