# webpack

前端的工程化离不开 webpack, 它是一个现代 JavaScript 应用程序的静态模块打包器,用于 将适合用于开发的代码打包构建为适合用于生产的代码

# webpack.config.js

const path = require("path");
const { DefinePlugin } = require("webpack");
module.exports = {
    mode: "development", //development 优化打包速度,production 优化打包结果,none 不做处理
    entry: "./src/main.js",
    devtool: "source-map", // 开启 source-map, 构建后会产生 source-map 文件,但想要浏览器使用还需要主 js 文件添加对应的魔法注释
    output: {
        filename: "bundle.js",
        path: path.join(__dirname,"output")
    },
    module:{
        rules:[
            {
                test:/\.css/,
                use:[
                    {
                        loader: "style-loader",
                        optioins:{}
                    },
                    {
                        loader: "css-loader",
                        optioins:{}
                    },
                    "less-loader",
                    {
                        loader:"postcss-loader",
                        optioins: {
                            plugins: [
                                require("postcss-preset-env")
                            ]
                        }
                    }
                ]
            },
            {
                test:/\.(ttf|eot|woff2?)$/i,
                type: "asset/resource",
                generate: {
                    filename: "img/[name].[hash:6][ext]"
                }
            }
        ]
    },
    plugin:[
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: "webpack测试标题",
            Template: "./public/index.html"
        }),
        new DefinePlugin({
            BASE_URL: '"./"'
        }),
        new CopyWebpackPlugin({
            patterns: [
                {
                    from: "public",
                    globalOptions:[]
                }
            ]
        })
    ]
}

# mode 模式

用于配置构建模式

# entry 入口

用于配置入口文件

# output 输出

用于配置出口文件

# devtool 工具

用于配置开发工具,如:source-map、eval 等,它是由:inline、nosources、cheap、等的组合
vue-cli 在开发模式下直接配置的是 source-map, 生产环境直接不生成
react 的 cra 在生产环境下根据传入的配置判断是否配置 source-map, 开发环境下配置 cheap-module-source-map

# 最佳实践

  • 开发阶段:推荐使用 source-map 或者 cheap-module-source-map, 方便本地调试
  • 测试阶段:推荐使用 source-map 或者 cheap-module-source-map, 方便定位错误
  • 生成阶段:推荐不生成 source-map (配置为 false 或缺省不写), 因为多余的 source-map 文件加载消耗资源,并且通过 source-map 文件,别人可以还原我们的代码

# optimization 优化

optimization 字段用于配置优化项,主要有 minimizer 压缩、splitChunks 分包、mergeDuplicateChunks 合并相同模块的 chunk 等选项

# resolve 解析

设置模块如何配解析,主要包括: alias 别名、extensions 后缀、fallback 重定向模块等选项

# devServer 开发服务器

内部使用 webpack-dev-server, 开发服务器,用于快速开发应用程序,主要包括: static 静态文件、compress 压缩、port 端口、devMiddleware 资源配置项、http2 开启 http2 等选项

# cache 缓存

配置使用缓存

# targets 构建目标

告知 webpack 为目标 (target) 指定一个环境。默认值为 "browserslist",如果没有找到 browserslist 的配置,则默认为 "web"

# watch 监听

监听任何已解析文件的更改

# watchOptions

用来定制 watch 模式的选项:

# externals 外部链接

防止将某些 import 的包 (package) 打包到 bundle 中,而是在运行时 (runtime) 再去从外部获取这些扩展依赖 (external dependencies), 例如一些使用 cdn 引用的文件

# externalsType 外链类型

指定 externals 的默认类型。当 external 被设置为 amd,umd,system 以及 jsonp 时,output.libraryTarget 的值也应相同。例如,你只能在 amd 库中使用 amd 的 externals。

# performance

配置如何展示性能提示。例如,如果一个资源超过 250kb,webpack 会对此输出一个警告来通知你。

# node

这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量。

# module 模块

module 字段用于配置模块 (对应的 loader)

# loader

处理对应的模块 (webpack 默认只支持 JS 文件)
loader 是一个函数,接收传来的代码字符串作为参数,返回处理后的代码字符串,webpack 中的模块处理是以管道架构方式 (也成为构造者的设计模式) 来进行设计的,并且注意它的处理是逆序进行处理

# plugin 插件

plugin 字段用于配置插件

# stats 显示

stats 选项让你更精确地控制 bundle 信息该怎么显示。 如果你不希望使用 quiet 或 noInfo 这样的不显示信息,而是又不想得到全部的信息,只是想要获取某部分 bundle 的信息,使用 stats 选项是比较好的折衷方式。

# 深入源码

# eval 函数

webpack 当 mode 为 development 模式下的 devtool 默认是 eval , 这将导致打包后的文件中,JS 代码是通过 eval 函数进行执行的,而不是直接执行的,原因是:通过 eval 函数执行可以 添加上source-map对应的魔法注释 ,这样当出现报错时就能准确定位到对应的文件位置

# 知识点

开发模式下,只要引入模块就会将模块打包进构建结果
生产模式下,会进行 tree-shaking, 如果引入了但不使用就不会被打包进构建结果

# webpack.config.js 配置示例

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
// MiniCssExtractPlugin 插件用于单独生成 css 文件,而不是嵌入到 html 中
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// HTMLInlineCSSWebpackPlugin 插件用于在 html 中内联 css 文件
const HTMLInlineCSSWebpackPlugin = require("html-inline-css-webpack-plugin");
// CleanWebpackPlugin 插件用于清除 dist 目录
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
//stats-webpack-plugin 插件用于生成 webpack 构建的详细信息
const StatsPlugin = require('stats-webpack-plugin');
//progress-bar-webpack-plugin 插件用于生成一个进度条,用于显示构建的进度
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
//webpack-manifest-plugin 为构建后的文件生成一个 manifest.json 文件,用于记录文件名和文件路径的映射关系,对 SPA 应用友好
const ManifestPlugin = require('webpack-manifest-plugin');
//webpack-md5-hash 为文件名添加一个 MD5 哈希值,从而保证文件名的唯一性
const WebpackMd5Hash = require('webpack-md5-hash');
const webpack = require("webpack");
const {
  WebpackBundleSizeAnalyzerPlugin,
} = require('webpack-bundle-size-analyzer');
module.exports = {
    entry:"./src/index.js",
    output:{
        path:path.resolve(__dirname,"dist2"),
        filename:"[name]_[hash].js"
    },
    mode:"development",
// 注意 pitch loader 是从前往后执行,normal loader 从后往前执行(洋葱模型,loaderIndex 指针控制)
    module:{
        strictExportPresence: true, // 导出一个内容没有导出时报错而不是警告
        rules:[
            {
                test:/\.html/,
//inline-html-loader 的作用是将图片和 css 等资源内嵌到 html 中,而不是引用的方式使用
                use:"inline-html-loader"
            },
            {
                test:/\.css$/,
                use:[
                    // {
                    //     loader:"style-loader"
                    // },
                    // 用于单独生成 css 文件
                    MiniCssExtractPlugin.loader,
                    {
                        loader:"css-loader"
                    },
// 用于将 css 中的 px 单位转为 rem 单位
                    {
                        loader:"px2rem-loader",
                        options:{
                            remUnit:75,
                            remPrecision:8
                        }
                    },
// 使用 postcss-loader 将 css 文件进行转换
                    {
//postcss-loader 用于将 css 文件进行转换,例如添加前缀等操作
                        loader:"postcss-loader",
                        options:{
                            plugins:() => [
                                require('autoprefixer')({
                                  // 指定兼容的浏览器版本,可以用 browserlist 文件代替 
                                  overrideBrowserslist: ['last 100 version', 'ios 7'],
                                }),
                            ],
                        }
                    }
                ]
            },
            {
                test:/\.less$/,
                use:["style-loader","css-loader","less-loader"]
            },
            {
                test:/\.scss$/,
                use:["style-loader","css-loader","sass-loader"]
            },
//svg-inline-loader 的作用是将 svg 文件内联到 html 中,而不是引用的方式使用
            {
                test:/\.svg/,
                use:[{loader:"svg-inline-loader"}]
            },
            {
                test:/\.(png|jpg|gif|jpeg)$/,
                use:[
                    {
                        loader:"file-loader",
                        options:{
                            name:"[name].[ext]",
//file-loader 中的 limit 配置用于配置指定的文件大小限制,如果文件大小超出了这个限制
//file-loader 会将文件转换为 base64 格式存在 Js 文件中
                            limit:200 * 1024
                        }
                    }
                ]
            },
            {
                test:/\.j|tsx?$/,
                use:[{
// 使用 babel-loader 配置 jsx 语法,也可以在.babelrc 文件中配置
                        loader:"babel-loader",
                        options:{
                            presets:["@babel/preset-env","@babel/preset-react"]
                        }
                    },
//eslint-loader 用于将 eslint 集成到 webpack 构建流程中,用于在代码中发现错误并强制执行代码规范
                    {
                        loader:"eslint-loader",
                        // 通常使用 eslint 配置文件进行配置
                        options:{
                            fix:true
                        }
                    }
                ],
                include:path.resolve(__dirname,'src')
            },
            {
                test:/.(woff|woff2|eot|tff|otf)$/,
                use:[
                    {
                        loader:"file-loader",
                        options:{
                            name:"[name].[ext]",
//file-loader 用于限制大小,超过这个大小就会将文件存在 js 之中
                            limit: 30 * 1024 * 1024
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            // 配置内联资源,和 HTMLInlineCSSWebpackPlugin 一起使用
            inlineSource:".css$",
            template: "src/index.html",
            inject:true,
            minify:{
                html5:true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false,
            }
        }),
        new HTMLInlineCSSWebpackPlugin(),
// 插件也可以是一个函数,webpack 会在构建时进行执行,注册对应的事件
        function () {
            this.hooks.done.tap("done",(stats) => {
                // 如果构建过程中报错,直接退出
                if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1) {
                    console.log('webpack.config.js: build error');
                    process.exit(1);
                  } else {
                    console.log('webpack.config.js: build done');
                  }
            })
        },
// HtmlWebpackExternalsPlugin 插件用于排除项目中希望从外部引入的资源,而不是将它们打包到 bundle 中
// 配置 HtmlWebpackExternalsPlugin 之后,需要删除掉项目中 import 或者 require 的资源,否则会构建两次
        new HtmlWebpackExternalsPlugin({
            externals: [
                {
                  module: 'react',
                  entry: {
                    path: 'https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js',
                    attributes: {
                      crossorigin: 'crossorigin',
                    },
                  },
                  global: 'React',
                },
                {
                  module: 'react-dom',
                  entry: {
                    path: 'https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js',
                    attributes: {
                      crossorigin: 'crossorigin',
                    },
                  },
                  global: 'ReactDOM',
                },
              ],
        }),
        new StatsPlugin("stats.json",{
            chunkModules:true,
            exclude:[/node_modules/],
        }),
        new ManifestPlugin(),// 创建 manifest.json 文件,包含项目中所有资源和最终输出路径,对 SPA 应用非常有用
        new WebpackMd5Hash(),// 为生成的文件添加 md5 加密后的 hash 值
        new WebpackBundleSizeAnalyzerPlugin('./bundle-size-analyzer.log'),// 分析打包后文件的大小
        new ProgressBarPlugin(),//
//webpack.BannerPlugin 插件用于为输出的文件顶部添加一个横幅注释,通常包含版权声明、作者信息等
        new webpack.BannerPlugin({
            banner:`这是 BannerPlugin 注入的内容
            https://github.com/ShenBao
            Copyright 2016 - Present`,
            raw: true, // 表示 banner 字符串将被原样处理,不进行任何处理
            entryOnly:true, // 表示只在入口文件处添加 banner
        }),
    ],
// 用于配置构建过程中的优化项
    optimization: {
        minimize:true, //webpack 会自动选择合适的插件来压缩代码
        minimizer: [
// OptimizeCSSAssetsPlugin 插件用于压缩 css 文件,需要配合 MiniCssExtractPlugin 使用
        //   new OptimizeCSSAssetsPlugin({
        //     assetNameRegExp: /\.css$/g,
        //     cssProcessor: require('cssnano'),
        //   }),
        new TerserPlugin({
            include:/\.min\.js$/,
        })
        ],
        splitChunks: {
            chunks: 'async',
            minSize: 30000,
            maxSize: 0,
            minChunks: 1,
            maxAsyncRequests: 2,
            maxInitialRequests: 2,
            automaticNameDelimiter: '-', // 文件名连接符
            name: true,
            cacheGroups: {
              vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: -10, // 优先级
                filename: 'vendors.js',
              },
              default: {
                minChunks: 2,
                priority: -20,
                reuseExistingChunk: true, // 已经被打包过的使用之前的
                filename: 'common.js',
              },
            },
          },
    },
// 配置信息量,errors-only 表示只有当出错时才会输出
    stats: "errors-only",
    devServer:{
        contextBase:"./dist",
        host:true,
    },
    devtool: "source-map",
    resolveLoader:{
        modules:["node_modules","./MyLoaders"] // 自定义查找 loader 的文件夹
    },
    bail:true, // 如果构建过程中出现错误,立即停止构建过程
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝