配置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()