前端面试-webpack系列(webpack配置)

199 阅读6分钟

webpack基础配置

1、webpack拆分配置和merge(拆分公共的配置进行引入dev和pro)
const {smart} = require('webpack-merge')
module.exports = smart(webpackCommcpnf, {

})
2、启动服务

安装webpack的dev-server,本地环境devServer配置,proxy本地代理去解决跨域问题

3、es6处理
rules: [
	{
		test: '/\.js$/',			// 匹配js文件
		loader: ['babel-loader'],			// 处理es6
		include: srcPath,			// 包括的文件路径
		exclude: /node_modules/			// 忽略的文件
	}
]

需要配置.babelrc文件

{
	'presets': ["@babel/preset-env"]		// 处理es6,es7等文件
}
4、处理样式
rules: [
	{
		test: '/\.css$/',			
		loader: ['style-loader','css-loader','postcss-loader'],			// 注意执行顺序从后往前
	}
]
postcss-loader: 浏览器兼容性处理
less-loader:处理less文件的时候

postcss是一个比较大的集合。里面会引入一些插件

postcss.config.js
// autoprefixer:增加前缀 --> -webkit-
module.exports = {
	plugins: [require['autoprefixer']]
}
5、处理图片
dev中:
rules: [
	{
		test: '/\.(png|jpg|jpeg|gif)/',			
		use: 'file-loader'
	}
]

线上:
rules: [
	{
		test: '/\.(png|jpg|jpeg|gif)/',			
		use: {
			loader: 'url-loader',
			options: {
				// 如果图片小于5mb就用base64位格式产出,否则打包到img1的目录下
				limit: 5 * 1024,
				outputPath: '/img1/'
			}
		}
	}
]

// 文件内柔没有变化的话,hash就不会变,就能命中缓存加快渲染
output: {
	filename:'bundle.[contentHash:8].js',			// js文件打包时,加上8位的hash值
	path: disPath
}

webpack高级配置

1、多入口配置
entry: {
	index: path.join(srcPath, 'index.js'),
	other: path.join(srcPact, 'other.js')
}

对应多出口

output: {
	filename:'[name].[contentHash:8].js',			// name即对应的入口的文件名称
	path: disPath
}
// 多入口生成文件 
plugins: {
	new HtmlWebpackPlugin({
		template: path.join(srcPath, 'index.html'),
		filename: 'index.html',
		chunks: ['index']
	})
	new HtmlWebpackPlugin({
		template: path.join(srcPath, 'other.html'),
		filename: 'other.html',
		chunks: ['other']
	})
}

总结:多入口需要entry配置多个入口,output配置多个出口,同时需要多个HtmlWebpackPlugin匹配生成文件

2、css线上处理(不能插入style中)
// 安装插件
const MiniCssExtractPlugin = require('min-css-extract-plugin')

// 抽离css
{
	test: /\.css$/,
	loader: [
		MiniCssExtractPlugin.loader,	// 生产环境不再用style-loader
		'css-loader',
		'postcss=loader'
	]
}
// 抽离less
{
	test: /\.less$/,
	loader: [
		MiniCssExtractPlugin.loader,
		'css-loader',
		'less-loader',
		'postcss=loader'
	]
}
// 抽离css文件
plugins: [
	new MiniCssextractPlugin({
		filename: 'css/main.[contentHash:8].css'
	})
]
// 压缩css
optimization: {
	minimizer: [new TerserJSPlugin({}), new OptimizeCssAssetSPlugin({})]
}

总结:css线上处理需要在生产环境处理的基础上在loader上通过MiniCssExtractPlugin去进行抽离,同时对抽离css文件hash处理,最后再进行一步压缩进一步优化

3、抽离公共代码(线上环境抽离第三方库或者公共的资源代码)
optimization:[
	// 分割代码块儿
	splitChunks: {
		chunks: 'all',		// initial 入口chunk,对于异步导入的文件不处理;async异步chunk,只对异步导入的文件处理;all是都处理
		// 缓存分组
		cacheGroups: {
			// 第三方模块
			vendor: {
				name: 'vendor', //chunk名称
				priority: 1, 	// 全县更高,优先抽离(优先命中)
				test: '/node_modules/,		// 判断文件的路径,是否能在这个文件夹中命中
				minSize: 0, // 大小限制,			// 最小的话就不用进行过度拆分
				minChunks: 1		// 最少复用过几次
			},
			// 公共的模块
			common: {
				name: 'common',
				priority: 0,
				minSize: 0,
				minChunks: 2
			}
		}
	}
]
plugins: {
	new HtmlWebpackPlugin({
		template: path.join(srcPath, 'index.html'),
		filename: 'index.html',
		chunks: ['index', 'vendor', 'common']		// 对应的代码分割的name名称
	})
}

总结:抽离公共代码块需要在optimization的splitChunks中进行拆分模块儿,然后在生成文件的时候需要用到哪些chunks自己引入对应的name

4、懒加载(引入动态数据)
js中引入动态数据
setTimeOut(() => {
// 定义一个chunk
	import('./aaa.js').then(res => {
		console.log(111)
	})
}, 1500)
5、处理JSX和vue
处理jsx:安装breset-react,在babelrc中使用,然后loader配置下即可
处理vue:安装vue-loader,然后loader配置下即可
6、webpack概念总结
module、chunk、bundle区别
module:各个源码文件,webpack中一切皆模块 --- 所有的src引入的文件都是模块
chunk:多模块合并成的,如entry、import()、splitChunk --- 通过分析里面的内容可以生成一个代码的集合
budle:最终的输出文件		-- 一个chunk对应一个budle,chunk是整合的一个过程,budle是最终的结果

webpack的性能优化

1、优化babel-loader
{
	test: '/\.js$/',
	use:['babel-loader?cacheDirectory'],		// 开启缓存
	include: path.resolve(__dirname, 'src')		// 明确范围
	
	// include和exclud两者选一个即可
}
2、IgnorePlugin(忽略第三方包指定目录)
new webpack.IgnorePlugin({
    resourceRegExp: /^./locale$/,		// 匹配规则,文件目录中存在这个的全部忽略
    contextRegExp: /moment$/,		// 文件目录
})

注意:忽略文件后,如果需要用到里面的某个东西需要手动进行引入一下

3、noParse(过滤不需要解析的文件)
module: {
  noParse: '/jquery|lodash/'		// 不去解析引入的依赖库
}
4、happyPack多进程打包
rules: [
	{
		test: /\.js$/,
		use: ['happypack/loader?id=babel'],
		include: srcPath
	}
]

plugins:{
	new HappyPack({
		id: 'babel',			// 对应上面的唯一id,用来处理一类特定的文件
		loaders: ['babel-loader?cacheDirectory']
	})
}
5、parallelUglifyPlugin多进程压缩js
new ParallelUglifyPlugin({
	uglifyJS: {
		output: {
			beautify: false,		// 最紧凑的输出
			comments: false			// 删除所有的注释
		},
		compress: {
			// 删除所有的console语句,可以兼容ie
			drop_console: true,
			// 内嵌定义了但是只用到了一次的变量
			collapse_vars: true,
			// 提取出出现多次但是没有定义成变量的静态值
			reduce_vars: true
		}
	}
})
补充:上述两个都是多进程,但是为什么速度没有提升呢?

-- 项目比较大,打包速度慢,能提高速度

-- 项目比较小的话,打包速度快,开启反而会降低速度

6、webpack配置热更新
自动刷新:(自动刷新整个网页刷新,速度慢;状态会丢失)
module.export = {
	watch: true,			// 开启监听,默认为false
	// 注意,开启监听后,webpack-dev-server会自动开启刷新浏览器
	watchOptions: {
		ignore: /node_module/,
		aggregateTimeout: 300,		// 监听到文件发生变化后,300ms后再去执行,防止刷新频率过高
		poll: 1000		// 每隔1000ms询问一次
	}
}
热跟新:(新代码生效,网页不刷新,状态不丢失)
module.export = {
	extry: {
		index: [
			'webpack-dev-server/client?http://localhost:8080/',
			'webpack/hot/dev-server',
			path.join(srcPath, 'index.js')
		]
	},
	plugins: [
		new HotModuleReplacementPlugin()
	],
	devServer: {
		hot: true
	}
}

监听范围外,需要热更新的js文件

if (module.hot) {
	module.hot.accept(['./math'], () => {
		console.log('热更新')
	})
}
7、DllPlugin 动态链接库插件

-- 前端框架一般体积比较大,构建比较慢

-- 较稳定,不常升级版本

-- 同一个版本每次只构建一次就行,不用每次都重新构建

webpack已经内置了DllPlugin文件支持

① DllPlgin打包出dll文件

② DllReferencePlugin去使用dll文件,之后只要文件不变就会一直使用打包好的dll文件

新建一个webpack.dll.js
modules.export = {
	mode: 'development',
	entry: {
		vendor: ['element-ui', vuex]
	},
	output: {
		filename: '[name].dll.js',
		path: disPath,
		library: '[name]_[hash]'
	},
	plugins: [
		new DllPlugin({
			name: '[name]_[hash]',
			path: path.join(disPath, '[name]-mainfest.json')
		})
	]
}

Package.json中去定义路径打包,然后在index中去引用dll.js

'dll': 'webpack --config ./webpack.dll.js'

webpack.dev.js

plugins:[
	new DllReferencePlugin({
		mainfast: require(path.join(disPath, 'vendor-manifest.json'))
	})
]
8、webpack性能优化-产出代码

-- 体积更小

-- 合理分包,不重复加载

-- 速度更快,执行速度更小

方法

-- 小图片base64位编码

-- bundle + hash

-- 懒加载

-- 提取公共代码

-- ignorePlugin

-- 使用cdn加速

-- 使用production

-- Scope Hosting

使用production
mode:'production'		
-- 自动压缩代码
-- vue React等会自动删掉调试代码
-- 自动启用Tree-Shaking

注意:ES6 Module才能让tree-shaking生效;commonjs不行
ES6 Module和commonjs区别

-- ES6 Module静态引入,编译时引入

-- Commonjs动态引入,执行时引入

-- 只有ES6 Module才能静态分析,实现Tree-Shaking

动态静态举例:require可以放在判断条件里面引入

Scope Hosting
-- 代码体积更小
-- 创建函数作用域更少
-- 代码可读性更好
module.exports = {
	resolve: {
	// 针对Npm中的第三方模块优先采用 jsnext:main中指向的ES6模块化语法的文件
		mainFields: ['jsnext:main', 'browser','main']
	},
	plugins: [
    new ModuleConcatenationPlugin()
  ]
}

babel

1、环境搭建和基本配置
.babelrc
// es6转换成es5语法
{
	"presets": [
		[
			"@babel/preset-env"			// 预设,包里面写了很多的plugin,插件的集合
		]
	],
	“plugins":[
	
	]
}
2、babel-polyfill(补丁,兼容低版本浏览器)

core.js库 -- 能满足绝大多数es6,es7语法的兼容(generator函数不能兼容,被async/await代替) regenerator库 -- 能支持generator语法

babel-polyfill就是这两个库的集合(7.4之后弃用,推荐直接使用core库,regenerator库)

3、babel-polyfill按需引入(文件较大,只用了部分功能)

-- babel只解析语法是否规范,至于是否有这个api或者浏览器是否支持不在解析范围内

-- babel不处理模块化(webpack处理)

.babelrc
{
	"presets": [
		[
			"@babel/preset-env",
      {
      	"useBuiltIns": "usage",
      	"corejs": 3			// corejs 版本
      }
		]
	],
	“plugins":[
	
	]
}
4、babel-runtime

babel-polyfill问题

-- 会污染全局环境

-- 独立web系统无碍

pakeage.js
"devDependencies": {
	"@babel/plugin-transform-runtime": ""
},
"dependencies": {
	"babel/runtime": ''
}
.babelrc
{
	"presets": [
		[
			"@babel/preset-env",
      {
      	"useBuiltIns": "usage",
      	"corejs": 3			// corejs 版本
      }
		]
	],
	“plugins":[
		"@babel/plugin-transform-runtime",
		{
			"absoluteRuntime": false,
			"corejs": 3,
			"helpers": true,
			"regenerator": true,
			"usaESModules"; false
		}
	]
}

下一篇:前端面试-webpack系列(webpack真题总结)