【Webpack】性能优化

前置

开发环境

  1. 优化打包构建速度 HMR
    • HMR(模块热替换)
  2. 优化代码调试 souceMap

生产环境

  1. 优化打包构建速度
    * oneof
    * babel缓存
    * 多进程打包(提升打包速度,但是进程开启交流有时间开销)
    * externals (不让一些资源包去打包,排除掉)-- cdn
    * dil (先打包好,后面直接用,就不用打包了)-- 自己的服务器
  2. 优化代码运行的性能
    * 缓存(hash-chunkhash-contenthash)
    * tree shaking
    * code split 代码分割
    * 懒加载/与加载
    * pwa(离线访问)

HMR

(hot module replacement) 热模块替换 / 模块热替代

作用:

  1. 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块)
  2. 极大提升构建速度
  3. 样式文件: 可以 使用HMR功能:因为style-loader内部实现了
  4. js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码
    注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。
  5. html文件: 默认不能使用HMR功能, 同时会导致问题,html文件不能热更新了!(不用做HMR功能,因为框架基本都是虚拟dom加载到页面上–单页面、组件化)
    解决:修改entry入口,将html文件引入。[’./src/js/index.js’, ‘./src/index.html’]
    devServer: {
     ...
       // 开启HMR功能,!!修改了配置,要重启webpack服务
       hot: true
    }
    

source-map

一种提供源代码到构建后代码技术映射(如果构建后代码出错了,通过映射关系可以追踪到源代码错误)便于debug

// [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
devtool: 'inline-source-map'

方式详解

source-map:外部

  1. 错误代码准确信息 和 源代码的错误位置

inline-source-map: 内联

  1. 只生成一个内联的source-map
  2. 错误代码准确信息 和 源代码的错误位置

hidden-source-map: 外部

  1. 错误代码错误原因,但是没有错误位置。
  2. 不能追踪源代码错误,只能提示到构建代码后的代码错误位置

eval-source-map:内联

  1. 每一个文件都生成对应的source-map,都在eval函数中
  2. 错误代码准确信息 和 源代码的错误位置

nosources-source-map:外部

  1. 错误代码的准确信息,没有任何源代码错误信息

cheap-source-map:外部

  1. 错误代码的准确信息 和 源代码的错误位置
  2. 错误只精确到行,不能精确到列

cheap-module-source-map:外部

  1. 错误代码的准确信息 和 源代码的错误位置
  2. module 会将loader的source map加入

内联和外部的区别

  1. 外部生成了文件,内联没有 (xx.js.map文件)
  2. 内联构建速度更快
  3. 内联会是代码体积变大

具体环境应用

开发环境:速度快,调试更友好。 —> eval-source-map / eval-cheap-source-map

  • 速度快(eval>inline>cheap>…) eval-cheap-source-map: 最快 > eval-source-map
  • 调试友好 source-map> cheap-module-source-map >cheap-source-map

生产环境:源代码要不要隐藏,调试要不要友好。—> source-map/ cheap-module-source-map

  • 内联会让代码体积变大,所以生产环境不用内联

  • nosources-source-map 全部隐藏

  • hidden-source-map 只隐藏源代码,会提示构建后代码错误信息

oneOf

loader只会匹配一个(注意: 不能有两个配置处理同一种类型文件)

module: {
	rules: [
		{
			oneOf: [
				{
					...
				}
			]
		}
	]
}

缓存

同HMR 但是生产环境是不会配置HMR的,所以需要开启babel缓存

  • babel缓存 ==》让第二次打包构建速度更快

    cacheDirectory: true

{
	test: /\.js$/,
	....,
	options: {
		...,
		// 开启babel缓存
		// 第二次构建时,才会读取之前缓存,速度更快
		cacheDirectory: true
	}
}
  • 文件资源缓存 ==》 让代码上线运行缓存更好使用

    hash: built.[hash:10].js 每次webpack构建时会生成一个唯一的hash值

【问题】因为js和css同时使用一个hash值,如果重新打包,会导致所有缓存失效。(可能我却只改动一个 文件)

【解决】chunkhash: built.[chunkhash:10].js 根据chunk(代码块)生成的hash值。如果打包来源于用一个chunk, 那么hash值一样

【问题】: js和css的hash值还是一样的,因为css是在js中被引入的,所以同属于一个chunk

【解决】 contenthash: built.[contenthash:10].js 根据文件的内容生成hash值。不同文件hash不一样

tree shaking

作用:1.去除在应用程序中无用的代码,使打包后的代码体积变小(把一个模块中没用到的代码过滤掉)
前提:1.必须用es6模块化 2.开启production环境(就自动开启了) 3.只应用于js

在package.json中配置

​“sideEffects”: false 所有代码都没有副作用(都可以进行tree shaking )

​【问题】 可能会把css / @babel/polyfill(副作用)文件干掉

​【解决】“sideEffects“:["*.css", "*.less"]注释不想删除的代码

名词解释
Babel: 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码。注意:Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API。
Polyfill: 用于实现浏览器并不支持的原生API的代码。

code split 代码分割

  1. 第一种: 多入口
entry:{
  // 多入口: 有一个入口,最终输出就有一个bundle
	main: './js/index.js',
	test: './js/test.js'
},
output: {
	// [name]:取文件名,生成对应文件的输出文件
	filename: 'js/[name].[contenthash:10].js',
	path: resolve(__dirname, 'build')
}
  1. 第二种 单入口
  • 可以将node_modules中代码单独打包成一个chunk最终输出
  • 自动分析多入口chunk中,有没有公共的文件,如果有,会打包成单独的一个chunk
optimization: {
	splitChunks: {
		chunks: 'all'
	}
}
  1. 第三种 单入口
    通过js代码,让某个文件被单独打包成一个chunk
    import动态导入语法:能将某个文件单独打包
// 魔法注释去命名输出文件的名字
//!该代码在input入口文件中写
import(/* webpackChunkName: 'test'*/'./test')
	.then((res)=>{
		// 文件加载成功~
		...
	})
	.catch(()=>{
		...
	})

懒加载和预加载

懒加载:用到的时候再加载,不用的时候不要加载 (加载过多,会出现触发事件后需要等待的问题)
预加载: 等其他资源加载完毕,浏览器空闲了,再偷偷加载资源(慎用-兼容问题)
正常加载:可以认为是并行加载(同一时间加载多个文件)

预加载事例:

document.getElementById('btn').onClick = function() {
  // 必须打包成单独的文件,才能用时候再调用
  // 懒加载:当文件需要使用时,才加载
  // 预加载: webpackPrefetch: true 就是初始化先加载了js文件,等用的时	 候直接调用
  import(/* webpackChunkName: 'test', webpackPrefetch: true*/'./test').then(({mul}) => {
    ....
  })
}

PWA -不常用,知道就行

渐进式网络应用程序(progressive web application)是一种可以提供类似于native app (原生应用程序)体验的web app (网络应用程序)

离线可访问
workbox -> workbox-webpack-plugin

// webpack.config.js

plugins: [
  /*
    1.帮助serviceworker快速启动
    2.删除旧的 serviceworker
    
    生成一个serviceworker配置文件~
  */
	new workboxwebpackplugin.GenerateSW({
		clientsClaim: true,
		skipWatting: true
	})
]

多进程打包

缺点:进程启动大概需要600ms, 进程通信也要花时间,只有工作时间消耗比较长,才需要多进程打包.
使用:loader: 'thread-loader’

test: /\.js$/,
use: [
	// 开启多进程打包
	{
		loader: 'thread-loader',
		options: {
			workers: 2 // 进程2个
		}
	},
  {
    loader: 'babel-loader',
    options: {
      presets: [
        [
          '@babel/preset-env',
          {
            useBuiltIns: 'usage',
            corejs: {version: 3}
            ...
          }
        ]
      ]
    }
  }
	...
]

@babel/preset-env: 它可以根据开发者的配置,按需加载插件,并不是一股脑都加载,因为现在需要兼容的越来越少,多余的转换不单降低执行效率,还浪费带宽。

externals

项目用cdn请求资源时,用这个可以忽略它去打包
cdn: 内容分发网络,分布式存放静态资源,缓解服务器压力。

externals: {
	// 忽略库名 -- npm 包名
  	// 拒绝JQuery打包进来
	jquery: 'JQuery'
}

dil

使用dil技术,对某些库(第三方库:jquery、react、vue…)进行单独打包
当你运行webpack时,默认查找webpack.config.js
当运行webpack.bil.js文件 --> webpack --config webpack.dil.js

/*webpack.bil.js*/
module.exports = {
  entry: {
    // 最终打包生成【name】 --> jquery
    //['jquery'] 要打包的库是jquery
    jquery: ['jquery']
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dil'),
    library: '[name]_[hash]', // 打包的库里面向外暴露出去的内容叫什么名字
  },
  plugins: [
  	// 打包生成一个manifast.json --> 提供和jquery映射
  	new webpack.DilPlugin({
  	  name: '[name]_[hash]', //映射库暴露的内容名称
      path: resolve(__dirname, 'dil/manifest.json') // 输出文件路径
		}),
      
    new webpack.DilReferencePlugin({
      manifest: resolve(__dirname, 'dil/manifest.json')
    })
  ],
  mode: 'production'
} 
/*webpack.config.js*/
// add-asset-html-webpack-plugins
plugins: [
  	...
  // 告诉webpack哪些库不参与打包,同时使用时的名称也得变
    new webpack.DilReferencePlugin({
      manifest: resolve(__dirname, 'dil/manifest.json')
    })// 将某个文件打包输出去,并在html中自动引入该文件
  	new AddAssetHtmlWebpackPlugin({
  	filename: resolve(__dirname, 'dil/dil/jquery.jss')
  })
],
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值