webpack配置(vue2)

175 阅读6分钟

配置webpack.config.js文件:

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // 压缩优化css
const { VueLoaderPlugin } = require('vue-loader') // TW:VueLoaderPlugin 是一个插件,用于告诉 webpack 如何处理和解析 .vue 文件,而 vue-loader 则是实际执行加载和转换 .vue 文件的加载器
const CopyWebpackPlugin = require('copy-webpack-plugin') // TW:复制文件

const { appHtml } = require('./paths')

let isProd = true

function getWabpackConfig() {
	// TW:安装cross-env,package中添加NODE_ENV变量进行环境控制,后续可以根据环境变量对生产环境和开发环境做不同配置 npm install --save-dev cross-env
	isProd = process.env.NODE_ENV === 'production'

	const config = {
		// TW:development 打包速度快,不进行代码压缩和性能优化;production 打包速度慢,进行代码压缩和性能优化
		mode: isProd ? 'production' : 'development',

		// TW:devtool 通过资源地图的方式,给出打包后代码到原始代码的映射,方便开发人员调试
		// TW:选择source-map后,每个打包后的js模块会有一个对应的.map文件存储代码的映射关系;选择inline-source-map后,映射关系会一同写到编译后的代码中,bundle文件变得硕大无比;
		devtool: isProd ? 'source-map' : 'inline-source-map', // 正式环境也添加source-map,开发环境调试,使用inline-source-map

		// TW:指定打包的入口
		entry: {
			index: './src/main.js',
		},

		// TW:指定生成的文件要存放到哪里
		output: {
			// TW:配置输出文件的名称
			filename: 'js/[name].[contenthash:8].js', // 所有的js文件都放到js文件夹下
			// TW:配置输出文件存放在本地的目录
			path: path.resolve(__dirname, '../dist'),
			// TW:一些构建出的资源需要异步加载,加载这些异步资源需要对应的 URL 地址,output.publicPath 配置发布到线上资源的 URL 前缀
			publicPath: '/', // 发送到 output.path 目录的每个文件,都将从 output.publicPath 位置引用,指定了打包之后这些静态资源的根目录
			clean: true, // 每次构建前清理 /dist 文件夹
		},

		// TW:对打包结果进行优化
		optimization: {
			minimize: isProd, // 如果是ture会进行js、css压缩,会产生LICENSE.txt文件,把注释提取到单独的txt文件中
			minimizer: [
				// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
				`...`, // js的压缩全靠这三个...,webpack认为,如果配置了minimizer,就表示开发者在自定义压缩插件,无论配置minimizer是true还是false,内部的JS压缩器都会被覆盖掉。所以我们这里要手动把它加回来,webpack内部使用的JS压缩器是terser-webpack-plugin.
				new CssMinimizerPlugin(),
			],

			// TW:根据不同的策略来分割打包出来的bundle,可以将公共的依赖模块提取到单独的文件中
			splitChunks: {
				chunks: 'all', // initial同步,async异步,all同步或者异步
				cacheGroups: {
					// 其作用就相当于是一个分组条件,满足这个条件的输出为一个chunks。
					vendors: {
						// 将第三方库(library)(例如 lodash 或 vue)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改
						test: /[\\/]node_modules[\\/]/, // 匹配文件路径中包含 node_modules 的部分
						name: 'vendors',
						// eslint-disable-next-line max-len
						enforce: true, // 告诉 webpack 忽略 splitChunks.minSize、splitChunks.minChunks、splitChunks.maxAsyncRequests 和 splitChunks.maxInitialRequests 选项,并始终为此缓存组创建 chunk。
					},
				},
			},

			// TW:runtimeChunk作用:将开发过程中变化总是比较小的代码抽离出来,使得它们不会随着业务代码的变化而发生改变,减少重新打包的时间和消耗
			runtimeChunk: 'single', // 将包含chunks映射关系的list单独从入口文件里提取出来,方便浏览器缓存,否则会在入口文件js中每次都会发生变化,所有的入口文件一起共同生成一个runtimeChunk。
			// runtimeChunk: { name: "runtimechunk" },//同上,起个别名
			// runtimeChunk: {
			//   name: (entrypoint) => `runtimechunk~${entrypoint.name}`,//每个entry入口文件都生成一个runtimeChunk
			// },
		},

		// TW:相关解析策略
		resolve: {
			extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], // import引入文件的时候不用加后缀
			alias: {
				// 添加别名
				vue$: 'vue/dist/vue.esm.js',
				'@': path.resolve(__dirname, '../src'), // 为实现输入@符号能自动帮我们引出路径,需添加一个jsconfig.json文件对其中的path进行相关配置
			},
		},

		// TW:在NodeJs架设起临时的服务器用于项目的运行与调试,实现HRM即热更新
		// 需要安装才能使用 npm install --save-dev webpack-dev-server
		devServer: {
			static: {
				directory: path.join(__dirname, '../dist'),
			},
			client: {
				progress: true,
			},
			compress: true, // 启用 gzip compression:
			historyApiFallback: true,
			hot: true,
			open: true, // 自动打开浏览器
			port: 'auto', // 自动使用一个可用端口
			proxy: {
				'/api': {
					target: 'http://dev.xa.com',
					changeOrigin: true, // 设置为true, 本地就会虚拟一个服务器接收你的请求并代你发送该请求,主要解决跨域问题
				},
			},
		},

		// TW:配置对指定的文件类型进行指定的 Loader 解析规则
		module: {
			rules: [
				{
					test: /\.css$/i,
					// TW:use后面的加载器,webpack使用时是按照从后向前的顺序执行
					use: [
						isProd ? MiniCssExtractPlugin.loader : 'style-loader', // MiniCssExtractPlugin.loader和'style-loader'功能冲突,所以选一个就行
						'css-loader',
						'postcss-loader', // TW:使用postcss、postcss-loader、 postcss-preset-env进行样式兼容处理;添加配置文件postcss.config.js,postcss-loader 将会自动搜索该配置文件;同时添加.browserslistrc文件,指名要兼容的浏览器范围;
					],
				},
				{
					test: /\.less$/i,
					use: [
						isProd ? MiniCssExtractPlugin.loader : 'style-loader', // MiniCssExtractPlugin.loader和'style-loader'功能冲突,所以选一个就行
						'css-loader',
						'postcss-loader',
						'less-loader',
					],
				},
				{
					test: /\.s[ac]ss$/i,
					use: [
						isProd ? MiniCssExtractPlugin.loader : 'style-loader', // MiniCssExtractPlugin.loader和'style-loader'功能冲突,所以选一个就行
						'css-loader',
						'postcss-loader',
						'sass-loader',
					],
				},

				{
					test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,
					type: 'asset/resource',
				},
				{
					test: /\.(woff|woff2|eot|ttf|otf)$/i,
					type: 'asset/resource',
				},
				{
					test: /\.(js|mjs|jsx|ts|tsx)$/,
					exclude: /(node_modules)/,
					// include: path.resolve(__dirname, '../src'),
					use: {
						loader: 'babel-loader', // TW:使用babel将各种js相关的文件解析为浏览器能识别的es5语法;Babel在每个文件都插入了辅助代码,使代码体积过大,安装@babel/plugin-transform-runtime 插件,实现辅助代码的抽离;添加babel.config.js配置文件;
						options: {
							cacheDirectory: !isProd, // 使用 cacheDirectory 选项,将 babel-loader 提速至少两倍。这会将转译的结果缓存到文件系统中。
							// presets: ['@babel/preset-env'],
							// plugins: ['@babel/plugin-transform-runtime'],
							// 上边两项配置移动到babel.config.js
						},
					},
				},
				{
					test: /\.vue$/,
					exclude: /node_modules/,
					use: 'vue-loader',
				},
			],
		},

		plugins: [
			// TW:HtmlWebpackPlugin作用:当使用 webpack打包时,创建一个 html 文件,并把 webpack 打包后的静态js文件自动插入到这个 html 文件当中
			new HtmlWebpackPlugin({
				title: 'vue2-SPA-scaffold框架',
				template: appHtml,
				favicon: path.resolve(__dirname, '../public/favicon.ico'),
				// eslint-disable-next-line max-len
				// hash: true, //这里所有的引用都用一个hash值每次都会所有的都发生改变,所以用output的[contenthash]hash来替换这里。 append a unique webpack compilation hash to all included scripts and CSS files. This is useful for cache busting
				xhtml: true, // If true render the link tags as self-closing (XHTML compliant)
			}),

			isProd &&
				new BundleAnalyzerPlugin({
					// 打包分析工具 需要安装 npm install --save-dev webpack-bundle-analyzer
					analyzerMode: 'static', // generate a single HTML file with bundle report
					openAnalyzer: false, // Default: true. Automatically open report in default browser.
				}),

			new MiniCssExtractPlugin({
				// 将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件
				filename: 'css/[name].[contenthash:8].css', // 所有的css都放在css文件夹下
			}),

			new VueLoaderPlugin(),

			new webpack.DefinePlugin({
				// 解决浏览器报的warning
				__VUE_OPTIONS_API__: true, // 是否支持vue2的optionsAPI
				__VUE_PROD_DEVTOOLS__: false, // 开发阶段tree shaking
			}),

			new CopyWebpackPlugin({
				// 通过 CopyWebpackPlugin 插件将 public 中的文件复制到打包后的文件夹下
				// patterns 是匹配的意思
				patterns: [
					{
						from: 'src/assets/images', // 设置从哪一个源中开始复制
						to: `images`, // 可以省略,默认是复制到打包输出的路径,会根据 output
						globOptions: {
							ignore: ['**/DS_Store', '**/index.html', '**/abc.txt'], // ** 表示的是 from 的文件夹
						},
						// globOptions:设置一些额外的选项,其中可以编写需要忽略的文件,
						// 比如.DS_Store:mac目录下回自动生成的一个文件;.index.html:也不需要复制,因为我们已经通过HtmlWebpackPlugin完成了index.html的生成
					},
				],
			}),
		].filter(Boolean), // .filter(Boolean)去掉假值
	}

	return config
}

module.exports = getWabpackConfig()