webpack5

125 阅读6分钟

尚硅谷文档

图片使用asset

字体图标使用asset/resource 文件原封不动

.eslintignore 配置eslint忽略的文件 如 dist

css兼容

  "browserslist":[
    "last 2 version",  所有浏览器只要最近的两个版本
     "> 1%",  覆盖99%的版本
      "not dead"  有些浏览器在发展中已经死了不用管了
  ]
  取得是交集

启用webpack

开发模式
npx webpack ./src/main.js --mode=development

 生产模式
npx webpack ./src/main.js --mode=production

`npx webpack`: 是用来运行本地安装 `Webpack` 包的。

`./src/main.js`: 指定`Webpack``main.js`文件开始打包,不但会打包 `main.js`,还会将其依赖也一起打包进来。

`--mode=xxx`:指定模式(环境)。

5 大核心概念

1.  entry(入口)

指示 Webpack 从哪个文件开始打包

2.  output(输出)

指示 Webpack 打包完的文件输出到哪里去,如何命名等

3.  loader(加载器)

webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析

4.  plugins(插件)

扩展 Webpack 的功能

5.  mode(模式)

主要由两种模式:
-   开发模式:development
-   生产模式:production

开发模式

const path = require('path');

const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // 入口
    entry: './src/main.js',
    //输出
    output: {
        // 文件的输出路径
        // __dirname  node.js的变量 代表当前文件的文件夹目录
        // path: path.resolve(__dirname, '../dist'),//绝对路径
        path:undefined,  //开发模式没有输出
        // 文件名
        filename: 'js/main.js',
    },
    // 加载器
    module: {
        rules: [
            //loader的配置
            //处理各种样式资源css less sass 
            {
                test: /\.css$/, //只检测.css文件
                use: [
                    // 执行顺序,从右向左,从下向上
                    "style-loader",  //将js中的css通过style标签添加到html文件中生效
                    "css-loader"
                
                ]  //把css编译成成common.js的模块到js中
            },
            {
                test: /\.less$/,
                //loader:xxx  只能使用一个loader
                use: [
                    "style-loader",  //将js中的css通过style标签添加到html文件中生效
                    "css-loader",  //把css编译成成common.js的模块到js中
                    "less-loader"  //将less编译成css
                ]
            },
            {
                test: /\.s[ac]ss$/,
                use: [
                    "style-loader",  //将js中的css通过style标签添加到html文件中生效
                    "css-loader",  //把css编译成成common.js的模块到js中
                    "sass-loader"  //将sass编译成css
                ]
            },
            {
                test: /\.styl$/,
                use: [
                    "style-loader",  //将js中的css通过style标签添加到html文件中生效
                    "css-loader",  //把css编译成成common.js的模块到js中
                    "stylus-loader"  //将stylus编译成css
                ]
            },
            //处理图片资源
            {
                test: /\.(png|jpg|gif|webp|svg)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        // 小于60kb装换成bas64
                        // 优点减少请求次数  缺点正大体积
                        maxSize: 60 * 1024 // 4kb
                    }
                },
                generator: {
                    // 将图片文件输出到 static/imgs 目录中
                    // 将图片文件命名 [hash:8][ext][query]
                    // [hash:8]: hash值取8位
                    // [ext]: 使用之前的文件扩展名
                    // [query]: 添加之前的query参数
                    filename: 'static/images/[hash:8][ext][query]'
                }
            },
            // 字体图标  媒体  其他资源
            {
                test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
                type: 'asset/resource', //对文件原封不动的输出
                generator: {
                    // 将字体图标文件输出到 static/media 目录中
                    filename: 'static/media/[hash:8][ext][query]'
                }
            },
            //babel配置
            {
                test: /\.js$/,
                exclude: /node_modules/, //排除node_modules文件不处理
                loader: 'babel-loader'
                //  options:{
                //     presets: ['@babel/preset-env']
                //  }

            }
        ]
    },
    // 插件
    plugins: [
        //plugins的配置
        new ESLintPlugin({
            //检车那些文件
            context: path.resolve(__dirname, '../src')
        }),
        new HtmlWebpackPlugin({
            // 模板  以public/index.html文件创建新的html文件
            // 新的html文件特点  1.结构与原来一致   2.自动引入打包输出的资源
            template: path.resolve(__dirname, '../public/index.html')
        })
    ],

    // 开发服务器  不会输出资源 实在内存中进行编译打包
    devServer: {
        host: "localhost", // 启动服务器域名
        port: "3000", // 启动服务器端口号
        open: true, // 是否自动打开浏览器
    },
    mode: 'development'
}

生产模式

const path = require('path');

const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 用来处理获取样式的loader
function  getStyleLoader(pre){
    return [
        // 执行顺序,从右向左,从下向上
        MiniCssExtractPlugin.loader, //将css提取成单独的文件
        "css-loader", //把css编译成成common.js的模块到js中
        // css兼容性处理
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: [
                        "postcss-preset-env" // 能解决大多数样式兼容性问题
                    ]
                }
            }
        },
        pre
    ].filter(Boolean)
}
module.exports = {
    // 入口
    entry: './src/main.js',
    //输出
    output: {
        // 文件的输出路径
        // __dirname  node.js的变量 代表当前文件的文件夹目录
        path: path.resolve(__dirname, '../dist'),//绝对路径
        // 文件名
        filename: 'js/main.js',
        clean: true, // 自动将上次打包目录资源清空
    },
    // 加载器
    module: {
        rules: [
            //loader的配置
            //处理各种样式资源css less sass 
            {
                test: /\.css$/, //只检测.css文件
         use:getStyleLoader()
                // use: [
                //     // 执行顺序,从右向左,从下向上
                //     // "style-loader",  //将js中的css通过style标签添加到html文件中生效
                //     MiniCssExtractPlugin.loader, //将css提取成单独的文件
                //     "css-loader", //把css编译成成common.js的模块到js中
                //     // css兼容性处理
                //     {
                //         loader: 'postcss-loader',
                //         options: {
                //             postcssOptions: {
                //                 plugins: [
                //                     "postcss-preset-env" // 能解决大多数样式兼容性问题
                //                 ]
                //             }
                //         }
                //     }
                // ]

            },
            {
                test: /\.less$/,
                //loader:xxx  只能使用一个loader
               use:getStyleLoader( "less-loader")
                // use: [
                //     // "style-loader",  //将js中的css通过style标签添加到html文件中生效
                //     MiniCssExtractPlugin.loader, //将css提取成单独的文件
                //     "css-loader",  //把css编译成成common.js的模块到js中
                //     // css兼容性处理
                //     {
                //         loader: "postcss-loader",
                //         options: {
                //           postcssOptions: {
                //             plugins: [
                //               "postcss-preset-env", // 能解决大多数样式兼容性问题
                //             ],
                //           },
                //         },
                //       },

                //     "less-loader"  //将less编译成css
                // ]
            },
            {
                test: /\.s[ac]ss$/,
                use:getStyleLoader("sass-loader")
                // use: [
                //     // "style-loader",  //将js中的css通过style标签添加到html文件中生效
                //     MiniCssExtractPlugin.loader, //将css提取成单独的文件
                //     "css-loader",  //把css编译成成common.js的模块到js中
                //     // css兼容性处理
                //     {
                //         loader: "postcss-loader",
                //         options: {
                //           postcssOptions: {
                //             plugins: [
                //               "postcss-preset-env", // 能解决大多数样式兼容性问题
                //             ],
                //           },
                //         },
                //       },
                //     "sass-loader"  //将sass编译成css
                // ]
            },
            {
                test: /\.styl$/,
                use:getStyleLoader("stylus-loader")
                // use: [
                //     // "style-loader",  //将js中的css通过style标签添加到html文件中生效
                //     MiniCssExtractPlugin.loader, //将css提取成单独的文件
                //     "css-loader",  //把css编译成成common.js的模块到js中
                //     // css兼容性处理
                //     {
                //         loader: "postcss-loader",
                //         options: {
                //           postcssOptions: {
                //             plugins: [
                //               "postcss-preset-env", // 能解决大多数样式兼容性问题
                //             ],
                //           },
                //         },
                //       },
                //     "stylus-loader"  //将stylus编译成css
                // ]
            },
            //处理图片资源
            {
                test: /\.(png|jpg|gif|webp|svg)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        // 小于60kb装换成bas64
                        // 优点减少请求次数  缺点正大体积
                        maxSize: 60 * 1024 // 4kb
                    }
                },
                generator: {
                    // 将图片文件输出到 static/imgs 目录中
                    // 将图片文件命名 [hash:8][ext][query]
                    // [hash:8]: hash值取8位
                    // [ext]: 使用之前的文件扩展名
                    // [query]: 添加之前的query参数
                    filename: 'static/images/[hash:8][ext][query]'
                }
            },
            // 字体图标  媒体  其他资源
            {
                test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
                type: 'asset/resource', //对文件原封不动的输出
                generator: {
                    // 将字体图标文件输出到 static/media 目录中
                    filename: 'static/media/[hash:8][ext][query]'
                }
            },
            //babel配置
            {
                test: /\.js$/,
                exclude: /node_modules/, //排除node_modules文件不处理
                loader: 'babel-loader'
                //  options:{
                //     presets: ['@babel/preset-env']
                //  }

            }
        ]
    },
    // 插件
    plugins: [
        //plugins的配置
        new ESLintPlugin({
            //检车那些文件
            context: path.resolve(__dirname, '../src')
        }),
        new HtmlWebpackPlugin({
            // 模板  以public/index.html文件创建新的html文件
            // 新的html文件特点  1.结构与原来一致   2.自动引入打包输出的资源
            template: path.resolve(__dirname, '../public/index.html')
        }),
        // css文件单独打包
        new MiniCssExtractPlugin({
            filename: 'static/css/main.css'
        }),
        new CssMinimizerPlugin()
    ],

    // 开发服务器  不会输出资源 实在内存中进行编译打包
    // devServer: {
    //     host: "localhost", // 启动服务器域名
    //     port: "3000", // 启动服务器端口号
    //     open: true, // 是否自动打开浏览器
    // },
    mode: 'production'
}

webpack优化

SourceMap(提升开发体验)

-   开发模式:`cheap-module-source-map`
    -   优点:打包编译速度快,只包含行映射
    -   缺点:没有列映射
module.exports = {
  // 其他省略
  mode: "development",
  devtool: "cheap-module-source-map",
};

-   生产模式:`source-map`

    -   优点:包含行/列映射
    -   缺点:打包编译速度更慢


module.exports = {
  // 其他省略
  mode: "production",
  devtool: "source-map",
};

HotModuleReplacement(提高打包构建速度)

开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。
所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快
HotModuleReplacementHMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面

    hot:true  默认就是true不写也是true对css有效,对js无效(需要单独配置)
    
    devServer: {
        host: "localhost", // 启动服务器域名
        port: "3000", // 启动服务器端口号
        open: true, // 是否自动打开浏览器
    hot:true
    },
    
    让js支持热模块替换的功能
if(module.hot){
     count.js和sum.js支持了热模块替换
    module.hot.accept("./js/count.js")
    module.hot.accept("./js/sum.js")
}
让js支持热模块替换这样写很麻烦
vue和react有相关的loader
vue-loader    react-hot-loader

oneOf(loader匹配上了就不想下走了)

loader匹配上了还会向下走

    module: {
        rules: [
            {
                //每个文件只能被其中一个loader配置处理
                oneOf:[
                
                loader
                {},
                {}
                ]
            }
              ]
           }

Include/Exclude

开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。
而这些文件是不需要编译可以直接使用的。

所以我们在对 js 文件处理时,要排除 node_modules 下面的文件。

-   nclude

包含,只处理 xxx 文件

-   exclude

排除,除了 xxx 文件以外其他文件都处理
            {
                test: /\.js$/,
                exclude: /node_modules/, //排除node_modules文件不处理
                loader: 'babel-loader'
            }

Cache

每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。

我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了

babel缓存
      {
                test: /\.js$/,
                include:path.resolve(__dirname,"../src"),
                loader: 'babel-loader',
                options:{
                    cacheDirectory: true, //开启babel编译缓存
                    cacheCompression: false, //缓存文件不要压缩
                 }
            }
            
eslint缓存
  new ESLintPlugin({
            //检车那些文件
            context: path.resolve(__dirname, '../src'),
            exclude:"node_modules",  //默认值
            cache:true,
            缓存路径
            cacheLocation:path.resolve(__dirname,"../node_modules/.cache/eslintcache")
            }),
        

Thead(多线程打包)

多进程打包:开启电脑的多个进程同时干一件事,速度更快。

需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销

我们启动进程的数量就是我们 CPU 的核数。

  1. 如何获取 CPU 的核数,因为每个电脑都不一样。
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
  1. 下载包
npm i thread-loader -D

3.使用

{
   test: /\.js$/,
   // exclude: /node_modules/, //排除node_modules文件不处理
   include: path.resolve(__dirname, "../src"),
   use: [
        { //开启多线程打包
          loader: 'thread-loader',
          options: {
                  work: threads//进程数量
                  }
        },
        {
         loader: 'babel-loader',
         options: {
                  cacheDirectory: true, //开启babel编译缓存
                  cacheCompression: false, //缓存文件不要压缩
                  }
       }
     ]
 }
        //plugins的配置
        new ESLintPlugin({
            //检车那些文件
            context: path.resolve(__dirname, '../src'),
            exclude: "node_modules",  //默认值
            cache: true, //开启缓存
            cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"),
            threads  //开启多线程打包
        }),

js代码压缩

    // 配置压缩
    optimization: {
        minimizer: [
            // css压缩
            new CssMinimizerPlugin(),
            // js压缩
            new TerserWebpackPlugin({
                parallel: threads//开启多线程
            })
        ]
    },