webpack学习笔记

发布于:2024-05-06 ⋅ 阅读:(27) ⋅ 点赞:(0)

webpack构建流程:

  1. 初始化参数,从配置文件和shell语句中读取和合并参数,得到最终的参数
  2. 开始编译,用上一步得到的参数初始化compiler这个对象,加载所有配置的插件,执行对象的run方法
  3. 确定入口,根据配置中的 entry 找出所有的入口文件
  4. 编译模块:从入口文件出发,调用所有配置的Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  5. 完成模块编译:在经过第四步使上oader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用

基础配置

plugins:可以在webpack运行到某个阶段时帮我们做一些事情,可以监听事件并执行特定的功能,有点像vue的生命周期
webpack.config.js中

const path = requeire('path')

module.exports = {
	mode:'development',
	entry:path.join(__dirname,'src','index.js')//把哪个文件作为打包入口
	output: {
		publicPath:'http://cdn.xxx.com/',
		path: path.join(__dirname,'dist')//把打包好的文件放在哪个路径,一般是dist
		filename:'boundle.js'//也可以用占位符[name].js·
	},
	plugins:[
		new HtmlWebpackPlugin({//打包完毕之后,帮忙自动生成html文件,再把打包后的结果注入到html之中
			template:path.join()__dirname,'src','index.html'),//把src底下index.html作为模板文件来打包,把打包好的js自动放进html里
			filename:'boundle.js'
		})
		new CleanWebpackPlugin()//自动删除dist文件夹
	],
	module:{//解析模块的规则
		rules:[
			{
				test:/\.js$/,
				loader:['babel-loader],//es6转化为es5
				include:path.join(__dirname,'src'),//只处理哪些代码
				exclude:/node_modules/,   //排除哪些代码
			}
		]
	},
	devServer: {
		port:8000,
		static:path.join(__dirname,'dist)//把dist目录作为静态资源的文件夹
	}
	
}

package.json文件中

'script':{
	"build":"webpack"//输入npm run build,运行webpack打包
	"dev":"webpack-dev-seerver"//实时编译代码,会把打包生成的文件放在内存里
},

.babelrc文件中

{//预设,
	"presets":["@babel/preset-env"]
}

拆分配置,合并配置

项目中常常会遇到,生产环境,测试环境,开发环境配置不同的情况,我们可以提取这些环境中的公共部分,写进webpack.base.config.js
在webpack.dev.config.js和webpack.prod.config.js中引入webpack.base.config.js

const commonConfig = require('./webpack.base.config');
const {smart:merge} = require('webpack-merge');//用smart方法合并配置,改名为merge

const prodConfig = {
	mode:'production'
}

module.exports = merge(commonConfig,prodConfig)
"scripts": {
	"build:dev":"webpack --config ./build/webpack.dev.config.js",//开发
	"build":"webpack --config ./build/webpack.prod.config.js",//生产

loader

Loader 是用于对模块的源代码进行转换的插件。
webpack本身是不认识图片,css,vue之类的东西的,只认识js,所以我们需要引入loader来处理各种模块

处理图片

webpack.dev.config.js

//开发环境
const devConfig = {
	module:{//解析模块的规则
		rules:[
			{
				test:/\.(png|jpg)$/,
				loader:'file-loader ',//把图片移到dist目录下,直接访问url来拿图
			}
		]
	},
}
//生产环境
const prodConfig = {
	module:{//解析模块的规则
		rules:[
			{
				test:/\.(png|jpg)$/,
				use:{
					loader:'url-loader ',//小图转化为base64,减少一次http请求
					options:{//大图依然像file-loader一样,单独打包到img文件夹里,发请求,防止页面首次渲染时间太慢
						limit: 5*1024
					}
				}
			}
		]
	},
}

index.js

import axios from 'axios'
axios.get('api/Yixiantong/getHomeDatas')//把api/Yixiantong rewrite成...
	.then(({data})=>{console.log(data)})

样式

webpack不能直接处理css
webpack.dev.config.js中

module.exports = {
	module:{//解析模块的规则
		rules:[
			{
				test:/\.css$/,
				loader:[
					'style-loader',//把样式插进style标签里
					'css-loader',//处理css之间的依赖关系
					'postcss-loader',//处理css3
					'sass-loader',//处理预处理器sass
				]
			},		
		]
	},

posts.config.js

moudle.exports = {
	plugins:[
		require('autoprefixer')

package.json

"browserslist": [//适配这些浏览器
		"> 1%",//选择全球使用率超过 1% 的浏览器版本。
		"last 2 versions"//选择每个浏览器的最近两个版本。
],

webpack-dev-server使用

webpack-dev-server可以用来转发请求
webpack.dev.config.js中

const devConfig = {
	mode:'development',
	devServer:{
		port:8000,//服务器气筒的端口8080
		contentBase:'./dist',//服务器静态资源文件夹
		progress:true,//打包时显示进度条
		open:true,//启动服务器后,自动打开浏览器
		compress:true,//开启gzip压缩
		proxy:{//请求转发
			'/api/Yixiantong': {
				target:'http://study.jsplus.com',
				pathRewite:{
					'^/api':''
				},
				changeOrigin:true
			}
		}
	}
}

多入口

webpack.config.js中

 module.exports = {
 	entry:{
 		index:'./src/index.js',
 		other:'./src.other/js'
 	},
 	output:{
 		filename:'[name].js',//打包后的文件名,[name] 示入口的名称,即 index 或 other。
 		path:path.resolve(__dirname,'../dist')
 	},
	plugins:[
		new HtmlWebpackPlugin({
			template:'./src/index.html',
			filename:'index.html',
			chunks:['index'],//chunk:由模块组成的代码块
		}),
		new HtmlWebpackPlugin({
			template:'./src/other',
			filename:'other.html'.
			chunks:['other'],
		}),
	],

抽离css

我们想在生产环境中,把样式抽离成css文件
webpack.prod.config.js中

const MiniCSSExtractPlugin =  require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsWepackPlugin = require('optimize-css-assets-wepack-plugin');

module.exports = {
	module:{
		rules:[
			{
				test:/\.css$/,
				loader:[
					MiniCSSExtractPlugin.loader,//换成minicss
					'css-loader',//处理css之间的依赖关系
					'postcss-loader',//处理css3
					'sass-loader',//处理预处理器sass
				]
			},		
		]
	},
	plugins:[
		new MiniCSSExtractPlugin({//根据文件内容生成的哈希值,只使用哈希值的前8个字符。
			filename:'css/main.[contentHash:8].css'
		}),
	],
	optimization:{
		minimizer:[
			new TerserPlugin(),//压缩js
			new OptimizeCssAssetsWepackPlugin(),//压缩css

这样做的结果就是,原本的css被压缩,比如注释掉的css都没有被打包进去,
css没有被插入进style标签,而是生成了css/main.abcd1234.css文件,并在link中引入

公共代码

  1. 公共模块
    公共模块的代码不需要重复打包,单独抽离成一个公共模块的文件,然后饮用即可
  2. 第三方模块
    第三方模块的代码一般不会轻易改变,不需要在业务代码改变之后再重新打包,单独抽离成一个第三方模块的文件,然后引用即可

一般在生产环境做这样的配置
webpack.prod.config.js中

 module.exports = {
  	entry:{
 		index:'./src/index.js',
 		other:'./src.other/js'
 	},
 	output:{
 		filename:'[name].[conetntHash:8]js',
 		path:path.resolve(__dirname,'../dist')
 	},
	plugins:[
		new HtmlWebpackPlugin({
			template:'./src/index.html',
			filename:'index.html',
			//html使用的js文件
			chunks:['index','vendor','common'],//vendor是第三方模块,common是公共模块
		}),
		new HtmlWebpackPlugin({
			template:'./src/other',
			filename:'other.html'.
			chunks:['other','common'],//common是公共模块
		}),
	],
	optimization:{
		splitChunks:{//代码分割
			chunks:'all'
			//all:对同步异步代码都做代码分割
			//async:只对异步代码做代码分割
			//initial:只对同步代码做代码分割
			//同步代码,例如import lodash from 'lodash'
			//异步代码,例如 import('lodash'),用import函数
			cacheGroups:{
				// 第三方模块
				vendor: {
					// 每个组的名字
					name: 'vendor',
					// 优先级,优先级越高,越先检测处理
					// 第三方模块 可能也会被作为公共模块来检测处理,通过高优先级,达到先被当做 第三方模块 来检测处理
					priority: 1// 检则方法,例如:检测模块是否来自 node_modules
					test: /node_modules/,//来自npm安装
					// 实际开发中,可以写 5*1024,也就是 5kb
					// 但这里为了看到 代码分割 的效果,我们把值沒置到最小,也就是0			  
					minSize: 0// 检测模块被引用了几次
					// 对于 第三方模块而言,引用1次就应该单独打包
					// 对于 公共模块 而言,引用2次以上就应该单独打包
					minChunks: 1,
				},
				// 公共模块
				common: {
					// 每个组的名字
					name: 'common'
					// 优先级,优先级越高,越先检测处理
					priority: 0// 实际开发中,可以写5*1024,也就是5kb
					// 但这里为了看到 代码分割 的效果,我们把值设置到最小,也就是0
				}
		}
	}

sourceMap

建立打包生成的代码与源代码之间的关系,方便改bug

module.exports={
	devtool:'eval-source-map',//开启sourcemap,关闭设为false
	//eval:打包速度最快,转化成eval()语法
	//source-map:把映射关系写入bundle.js.map文件里
	//inline-source-map:把映射关系写入bundle.js文件内最后一行,base64字符串
	//cheap:只记录哪行出错,不记录那列出错,不记录loader第三方模块出啥错

HMR模块热更新

占坑

性能优化

webpack的性能优化主要包括两部分,一是打包体积减少,一是打包速度加快
因为webpack构建流程其中有个步骤是所有的模块进行编译处理,那么我们可以在以下几点上做优化处理

  1. 缩小查找文件的范围,用alias,extensions等配置缩小范围
  2. 减少需要解解析的文件,使用noparse配置告诉webpack排除忽略指定文件,不对他们进行解析,
  3. 避免去重复的编译第三方库,打包到单独文件中,不会跟着业务文件一起重新打包,
  4. webpack在对代码进行压缩打包时,如果有多个js文件需要被压缩,她会一个个进行压缩,可以使用thread loader插件来开启多个子进程,采用并行的方式对多个js文件进行压缩打包。

参考:https://www.bilibili.com/video/BV1By4y177gX/?p=7&share_source=copy_web&vd_source=64698271e543eb5149301ff926e69c40