webpack高级概念

1.Tree shaking

tree shaking是一个术语来的,通常用于描述移除JavaScript上下文中的未引用的代码。比如某个js文件中导出的某一个方法没有使用,在production模式下打包就会把这个方法移除掉。

但是得注意:这个Tree shaking有时候会滥杀无辜,把我们一些需要的,但未应用得模块给移除掉的话,就会导致我们的项目会发生bug。例如:我们导入css模块的时候,import './style/index.css',由于这种无法引用的,如果我们配置Tree shaking,就会导致css样式失效。配置内容如下:

package.json文件
添加"sideEffects"属性:当值为“false”的时候:表示对所有的模块都使用Tree shaking。如果我们向某个模块或者css不使用Tree shaking,就配置一个数组:“[ "*.css", "./src/header.js", "jquery"]”。这样就所有css文件都不适用tree shaking,和src目录下的header.js也不使用tree shaking,下载的jquery也不使用。

"sideEffects": "false"

webpack.config.js文件
添加optimization选项:

optimization: {
	usedExports: true
}

:tree shaking在development模式下是不会移除掉未引用的代码的,只会在打包完的代码那里,添加未引用的注释,只有在production模式下才会真正的移除掉。

2.development和production模式的区分打包

由于development模式和production模式的配置信息不一样,我们就把development模式的配置信息写在webpack.dev.js,production模式的配置信息写在webpack.prod.js文件,然后抽离两个模式下的共同的配置信息,写在webpack.common.js文件下。然后使用webpack-merge插件的merge方法将配置信息合并。

webpack.dev.js文件基本结构:

const webpack_dev_config = {
	mode: 'development'
	....
}
module.exports = webpack_dev_config

webpack.prod.js文件基本结构:

const webpack_prod_config = {
	mode: 'production'
	....
}
module.exports = webpack_prod_config

webpack.common.js文件结构:

const {merge} = require('webpack-merge')
const webpack_prod_config = require('./webpack.prod.js')
const webpack_dev_config = require('./webpack.dev.js')
const webpack_common_config = {
	entry: {
		main: './src/index.js'
	},
	output: {
		path: './dist',
		filename: 'bundle.js'
	}
}
if(env && env.production) {
	module.exports = merge(webpack_common_config,webpack_prod_config)
} else {
	module.exports = merge(webpack_common_config,webpack_dev_config)
}

去package.json文件设置配置文件,和环境变量env.production:

  "scripts": {
    "build": "webpack --env.config --config ./build/webpack.common.js",
    "dev-build": "webpack --config ./build/webpack.common.js",
    "dev": "webpack-dev-server --config ./build/webpack.common.js"
  }

env.prodction不设置,默认是true

3.Code Spliting(代码分割)

code spliting:将一些库的代码和自己写的一些业务代码分开打包,分开打包的好处:我们的业务有时候需要修改,但是我们引用的某些库的代码是不会被修改的,由于浏览器有缓存的机制,加入我们自己写的代码有1mb,引用的库的代码也有1mb,在第一次加载的时候,需要加载2mb的代码,使不使用code spliting都不会影响第一次加载的速度;但是我们使用code spliting,如果我们修改了自己写的业务代码,第二次就只用加载我们自己写的业务代码,不用再加载第三方库的代码(因为有缓存)。
code Spliting的两种方式
第一种:使用import xx from 'xx’的导入方式,然后在webpack.config.js中配置:

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

第二种:使用import(‘xx’).then()这种动态导入形式,不需要任何配置(webpack有默认配置):

import(/*webpackChunkName: 'lodash'*/'lodash').then(({default: _}) => {
	console.log(_)
})

注:{default: _}这里是对象解构的用法。_是lodash导入的对象。/*webpackChunkName: 'loadsh'*/是起打包完后的文件名,这个教魔法注释,后面我们会在webpack中也会用到。

4.配置文件中splitChunks配置参数详解

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};

chunks:

  • async:表示只从异步加载模块import()里面进行拆分,即对import()和import()里面的所有导入模块进行拆分,包裹import xx from 'xx’这种
  • initial:表示只从入口模块进行拆分
  • all:表示两者都包括
    minSize:表示模块要大于多少才能进行代码分割。单位是byte
    minChunks:表示模块要导入大于多少次才能进行代码分割
    maxAsyncRequests:用来限制拆分数量的。限制异步模块内部的并行最大请求数,就是每个import()它里面的最大并行请求数量
  • import()算一个请求
  • js以外的公共资源不算,比如css
  • 如果有两个模块满足cacheGroup规则要进行拆分,但是maxAsyncRequests的值只允许拆分一个模块,那就拆分最大的那个模块
    maxInitialRequests:用来限制拆分数量的。它表示允许入口并行加载的最大请求数量。
  • 入口文件本身算一个请求
  • 如果入口里面有动态模块这个不算在内
  • 通过runtimeChunk拆分的runtime不算在内
  • js以外的公共资源不算,比如css
  • 如果有两个模块满足cacheGroup规则要进行拆分,但是maxInitialRequests的值只允许拆分一个模块,那就拆分最大的那个模块
    automaticNameDelimiter:用来连接文件名称的,例如:vendors~lodash.js
    cacheGroups:当模块都满足上面的条件,就进入第二轮进行,看是否满足cacheGroups中的条件。
    reuseExistingChunk:true:如果一个模块已经被打包过了,再打包的时候就忽略这个模块,直接使用被打包的那个模块。
    priority: 优先级,越大,优先级越高。选择那个组的条件。

code spliting详解比较好的文章

5.lazy loading懒加载

使用import()来实现懒加载:

function func() {
	return import(/*webpackChunkName: 'lodash'*/'lodash').then(({default: _}) => {
		return _
	})
}
document.onclick = () => {
	func().then((lodash)=> {
		console.log(lodash)
	})
}

这样的话,只有点击浏览器,才会加载lodash这个模块。第一次加载不用加载lodash,加快打开网页速度。

6.强化代码利用率

再浏览器控制台中,使用ctrl + shift + p,然后输入show coverage,就可以查看当夜网站的代码利用率。
可以优化的代码

document.onclick = () => {
	const div = document.createElement('div')
	div.innerHTML = 'hell world'
	document.body.appendChild(div)
}

优化:

document.onclick = () => {
	import('./handle.js').then((default: func) => {
		func()
	})
}

创建一个handle.js文件:

export default function func() {
	const div = document.createElement('div')
	div.innerHTML = 'hell world'
	document.body.appendChild(div)
}

优化性能,就得多写异步代码,增加代码利用率!

7.使用prefetch来利用空闲带宽加载资源

使用魔法注释:/*webpackPrefetch: true*/

document.onclick = () => {
	import(/*webpackPrefetch: true*/'./handle.js').then((default: func) => {
		func()
	})
}

创建一个handle.js文件:

export default function func() {
	const div = document.createElement('div')
	div.innerHTML = 'hell world'
	document.body.appendChild(div)
}

注:preload的用法和prefetch的都是通过魔法注释开启,preload的开启:webpackPreload: true。但是preload是和页面核心代码一起加载的,所以没什么优化。prefetch是等核心代码加载完成,带宽空闲才加载的。

8.css代码分割

css代码分割:webpack默认是会把css打包在js中的,这就是我们所说的css in js概念。我们想要把css从js中剥离出来的话,需要借助webpack的插件:mini-css-extract-plugin;css代码分割出来之后,我们可以借助插件:optimize-css-assets-webpack-plugin。如果webpack版本更新,建议去参考配置。以下是webpack4的配置:
1.安装mini-css-extract-plugin

npm i mini-css-extract-plugin

2.在index.js中导入css文件

import './style.css'

3.在webpack.config.js中配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
	plugins: [new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
        chunkFilename: '[name].[contenthash].chunk.css'
    })],
        module: {
        rules: [
            {
                test: /\.(sc|c)ss$/,
                use: [MiniCssExtractPlugin.loader, {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2
                    }
                },
                    'postcss-loader',
                    'sass-loader']
            }
        ]
    }
}

这样就可以对css进行代码分割了。
注:如果没有生成css文件,可能你使用tree shaking功能,由于import 进来的css文件没有被引用,就被摇晃掉了,这时候需要去package.json中配置:"sideEffects": [ "*.css", "*.scss" ]

优化:在production模式使用optimize-css-assets-webpack-plugin来压缩合并css代码
1.安装optimize-css-assets-webpack-pluginterser-webpack-plugin

npm install --save-dev optimize-css-assets-webpack-plugin terser-webpack-plugin

2.在webpack.config.js中配置

const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
	optimization: {
        minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
        splitChunks: {
			styles: {
              name: 'styles',
              test: /\.css$/,
              chunks: 'all',
              enforce: true
            }
		}
    }
}

这样就可以实现css代码合并和压缩了。
版本更新的导致配置失效或报错,建议去看官方最新文档
webpack官方文档:点我

9.webpack与浏览器缓存

我们在第一次打开页面的时候,浏览器会帮我们把一些文件给缓存下来。下次进入这个页面的时候,它会对比文件名是否和上次的一致,一致就走缓存,不一致就重新请求。所以有时候我们修改了js代码的时候,页面没有效果,原因是浏览器没有请求我们最新编写的js文件,这个时候我们需要ctrl + f5 强制刷新页面才能看到最新效果。
为了阻止以上缺点,webpack为我们提供了一个很好的解决方法,为打包好的文件的文件名添加contenthash值,这样就能让浏览器及时请求最新的代码了

webpack.config.js文件:

module.exports = {
	output: {
		filename: '[name].[contenthash].js',
		path: path.resolve(__dirname, './dist')
	}
}

注:contenthash的值是随着内容的改变而改变,如果内容不变,无论打包多少次contenthash的值是不会变的。如果你webpack版本比较低,可能会出现内容不变,但contenthash值发生了变化,那就要增加以下配置:

optimization: {
	runtimeChunk: {
		name: 'runtime'
	}
}

这样就会打包多一个runtiem.xxxx.js的文件。这个文件的内容就是业务代码和你用到的库的一些联系。

10.Shimming的使用

shimming:大概是电片的意思,用来申明一些**全局变量(所有模块都能用的变量)或者改变一些全局变量(所有模块都能用的变量)**的指向。
申明全局变量:

const webpack = require('webpack')
module.exports = {
	plugins: [
		new webpack.ProvidePlugin({
			$: 'jquery',
			_join: ["lodash", 'join'] 
		})
	]
}

_join: ['lodash', 'join']是吧lodash中的join方法赋值给_join

改变全局变量的指向(将this指向window):

npm i imports-loader
module.exports = {
	module: {
     rules: [
       {
         test: /.js$/,
         use: [
         {
			loader: 'babel-loader'
		},
		{
			loader: 'imports-loader?this=>window'	
		}],
       },
     ],
   },
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值