webpack5基础篇!看完就会辣!

1,300 阅读8分钟

前言

本篇是 webpack5 基础篇教程,意在用尽可能简介明了的描述,帮助初学者学习,二来给老手复习,三来自己巩固知识!话不多说,直接开干!

说明: webpack:^5.75.0 webpack-cli:^5.0.1

1、基本配置

在开始使用 Webpack 之前,我们需要对 Webpack 的配置有一定的认识

1.1、webpack 5大核心

  1. entry(入口)

    entry是 webpack 打包的入口,即指示 webpack 从哪里开始打包

  2. ouput(出口)

    output是指示 webpack 将打包好的文件输出到哪里去,如何命名等

  3. loader(加载器)

    webpack 本身只能处理 js、json,对于图片、字体等资源,webpack 需要借助 loader 进行解析

  4. plugin(插件)

    plugin扩展 Webpack 的功能

  5. mode(模式)

    mode指示 webpack 使用哪种模式,有两种

    • development(开发模式)
    • production(生产模式)

2、项目初始化

2.1、安装 webpack

  1. 创建 learn_webpack5 文件夹,创建子文件夹 src,打开 vscode 终端,输入以下命令

npm init -y

npm i webpack webpack-cli -D

会生成如下文件:

1674041893364.png

  1. src 文件夹下创建 a.js、b.js、index.js 文件
//src/a.js
export function printA() {
    console.log('a')
}
//src/b.js
export function printB() {
    console.log('b')
}
//src/index.js
import { printA } from "./a";
import { printB } from "./b";

function print() {
    printA()
    printB()
}

print()
  1. 在根目录下,创建 public/index.html 并初始化
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

2.2、编写 webpack 基本配置

在根目录下,创建webpack/webpack.common.js,并编写如下基本配置:

//webpack/webpack.common.js
const path = require('path')

module.exports = {
    //打包的入口配置
    //相对路径和绝对路径都行
    entry: path.resolve(__dirname, "../src/index.js"),
    //打包文件的出口配置
    output: {
        // path: 文件输出目录,必须是绝对路径
        // path.resolve()方法返回一个绝对路径
        // __dirname 当前文件的文件夹绝对路径
        path: path.resolve(__dirname, '../dist'),
        //输出的文件名
        filename: 'bundle.js',
        //webpack5 版本中,自动清除上一次打包的结果
        clean: true
    },
    //加载器配置
    module: {
        rules: [

        ]
    },
    //插件配置
    plugins: [],
    //模式配置
    mode: 'development'
}

2.3、配置 package.json 脚本命令

打开 package.json,添加下面的命令:

"scripts": {
    "build": "webpack --config ./webpack/webpack.common.js",
 },

在 vscode 终端运行 npm run build,整体目录如下:

1674106670717.png

3、处理 HTML 资源

html-webpack-plugin 会生成一个HTML5文件,在 body 中使用 scrip t标签引 webpack 生成的 bundle.js

(1)下载 html-webpack-plugin

npm i html-webpack-plugin -D

(2)在 plugins 中配置 html-webpack-plugin

const HtmlWebpackPlugin = require
module.exports = {
    //前面的代码...
    plugins: [
        new HtmlWebpackPlugin({
            //输出的路径
            template: path.resolve(__dirname, '../public/index.html'),
            //输出的文件名
            filename: 'index.html'
        })
    ]
}

(3)再次执行 npm run build

1674107074417.png

(4)打开 dist/index.html,右键,选择运行在浏览器中:

f12 打开 network,发现我们打包后的资源都下载下来了 1674107195918.png

打开控制台,发现打印了 a b

1674107263887.png

这样我们打包后的 bundle.js 就可以直观的运行在页面上了。

4、处理样式资源

本章节我们学习使用 Webpack 如何处理 Css、Less、Sass、Scss、Styl 样式资源

Webpack 本身是不能识别样式资源的,所以我们需要借助 Loader 来帮助 Webpack 解析样式资源

4.1、处理 CSS 样式

(1)下载 css-loader、style-loader

npm i css-loader style-loader -D
  • css-loader:帮助 webpack 解析 css,包括 @import 和 url()
  • style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容

(2)配置

// webpack/webpack.common.js
module.exports = {
    //前面的代码...
    module: {
        rules: [
            {
                test: /\.css$/, //匹配以 css 结尾的文件
                use: ["style-loader", "css-loader"], //从右向左解析
            },
        ]
    },
    //后面的代码...
}

(3)创建 src/styles/a.css,写入样式

body{
    background-color: aqua;
}

在 src/index.js 中引入 a.css

import './styles/a.css'

(4)执行 npm run build 后,重新在浏览器运行 dist/index.html,发现样式已经生效

1674107918775.png

4.2、处理 Less 样式

(1)下载 less-loader

npm i less-loader -D
  • less-loader:负责将 Less 文件编译成 Css 文件

(2)配置

// webpack/webpack.common.js
module.exports = {
    //前面的代码...
    module: {
        rules: [
            {
                test: /\.css$/, //匹配以 css 结尾的文件
                use: ["style-loader", "css-loader"], //从右向左解析
            },
            {
                test: /\.less$/, //匹配以 less 结尾的文件
                use: ["style-loader", "css-loader", "less-loader"], //从右向左解析
            },
        ]
    },
    //后面的代码...
}

(3)创建 src/styles/b.less,写入样式

div{
    width: 200px;
    height: 200px;
    background-color: red;
    span{
        color: white;
    }
}

(4)打开 public/index.html,添加一个 div 和 span

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <div>
        <span> 123 </span>
    </div>

</body>
</html>

(5)打开 src/index.js,引入 b.less

import './styles/b.less';

(6)执行 npm run build 后,页面如下:

1674108621228.png

4.3、处理 Sass、Scss 样式

(1)下载 sass-loader、sass

npm i sass-loader sass -D

(2)配置

// webpack/webpack.common.js
module.exports = {
    //前面的代码...
    module: {
        rules: [
            {
                test: /\.css$/, //匹配以 css 结尾的文件
                use: ["style-loader", "css-loader"], //从右向左解析
            },
            {
                test: /\.less$/, //匹配以 less 结尾的文件
                use: ["style-loader", "css-loader", "less-loader"], 
            },
            {
                test: /.s[ac]ss$/,//匹配以 sass、scss 结尾的文件
                use: ["style-loader", "css-loader", "sass-loader"],
            },
        ]
    },
    //后面的代码...
}

(3)创建 src/styles/c.scss,写入样式:

$blue: blue;
.box2{
    width: 300px;
    height: 300px;
    background-color: $blue;
} 

(4)打开 public/index.html,添加一个 div.box2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <div>
        <span> 123 </span>
    </div>
    <div class="box2"></div>

</body>
</html>

(5)打开 src/index.js,引入 c.scss

import './styles/c.scss';

(6)执行 npm run build,页面如下:

1674109113387.png

4.4、抽取 CSS 到单独的文件

我们发现上面的打包结果,head 标签中有 3 个 style 标签,如果在 src/index.js 里面引入的样式资源越多,则打包后的 style 标签就越多,这个时候我们希望把所有的 CSS 都提取到一个单独的文件中,减少 DOM 的操作,我们需要使用 mini-css-extract-plugin

(1)下载 mini-css-extract-plugin

npm i mini-css-extract-plugin -D

(2)配置

// webpack/webpack.common.js
module.exports = {
    //前面的代码...
    module: {
        rules: [
            {
                test: /\.css$/,
                //将 style-loader 换成 MiniCssExtractPlugin.loader
                use: [MiniCssExtractPlugin.loader, "css-loader"], 
            },
            {
                test: /\.less$/, //匹配以 less 结尾的文件
                use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
            },
            {
                test: /\.s[ac]ss$/,
                use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
            },
        ]
    },
    plugins: [
        //前面的代码...
        
        // 提取css成单独文件
        new MiniCssExtractPlugin({
           // 定义输出文件名和目录
           filename: "asset/css/main.css",
        }),
    ]
}

(3)执行 npm run build

1674109797652.png

(4)页面运行结果如下:

1674109877828.png

1674109910477.png

4.5、兼容性处理

某些样式可能并不兼容低版本浏览器,所以需要对 css 进行兼容性处理 (1)下载 postcss-loader postcss postcss-preset-env

npm i postcss-loader postcss postcss-preset-env -D

(2)配置

// 由于需要对 css、less、sass 都进行兼容性处理,所以我们先合并一下样式的配置
const getStyleLoaders = (preProcessor) => {
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    //在 css-loader 后,配置 postcss-loader
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};

module.exports = {
    module: {
        rules: [
            {
                // 用来匹配 .css 结尾的文件
                test: /.css$/,
                // use 数组里面 Loader 执行顺序是从右到左
                use: getStyleLoaders(),
            },
            {
                test: /.less$/,
                use: getStyleLoaders("less-loader"),
            },
            {
                test: /.s[ac]ss$/,
                use: getStyleLoaders("sass-loader"),
            }
        ]
    }
}

(3)在 package.json 新增 browserslist 配置

"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
 },

(4)在 src/styles/b.less 中添加样式

div{
    width: 200px;
    height: 200px;
    background-color: red;
    span{
        color: white;
        transform: rotate(45deg); /* 这个属性会产生浏览器内核前缀如 -webkit*/
    }
}

(5)执行 npm run build,查看 dist/assets/css/main.cs

1674110644783.png

4.6、压缩 CSS

打包后的文件体积越小,浏览器加载资源的速度就越快,当项目很大时,压缩文件体积是非常有必要的,接下来我们压缩打包后 CSS 文件的体积

(1)下载 css-minimizer-webpack-plugin

npm i css-minimizer-webpack-plugin -D

(2)配置

//webpack/webpack.common.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
    //前面的代码...
    
    plugins: [
        // css压缩
        new CssMinimizerPlugin(),
    ]
}

(3)执行 npm run build,发现 dist/assets/css/main.css 的代码被压缩了

1674110954855.png

5、处理图片资源

过去在 Webpack4 时,我们处理图片资源通过 file-loader 和 url-loader 进行处理

现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源

(1)配置

module.exports = {
    module: {
        rules: [
            //前面的代码
            {
                test: /\.(png|jpe?g|gif|webp)$/,
                type: "asset",
                parser: {
                  dataUrlCondition: {
                    // 小于10kb的图片会被base64处理
                    // 优点:减少请求数量
                    // 缺点:体积更大
                    maxSize: 10 * 1024
                  }
                },
                generator: {
                  // 将图片文件输出到 asset/imgs 目录中
                  // 将图片文件命名 [hash:8][ext][query]
                  // [hash:8]: hash值取8位
                  // [ext]: 使用之前的文件扩展名
                  // [query]: 添加之前的query参数
                  filename: "asset/imgs/[hash:8][ext][query]",
                },
            },
        ]
    }
}

(2)添加图片 创建 src/assets/img 文件夹,在该文件夹下添加三张图片(素材自己随便找)

如下:

1.png

(3)使用图片 首先,我们先在 src/public/index.html 中添加两个 div

1676175372832.png

然后,在 src/styles/b.less 中,写入下面的样式:

div{
    width: 200px;
    height: 200px;
}
.box2{
    background-image: url("../asset/img/1.jpeg");
    background-size: cover;
}
.box3{
    background-image: url("../asset/img/2.png");
    background-size: cover;
}
.box4{
    background-image: url("../asset/img/3.gif");
    background-size: cover;
}

最后,执行打包命令 npm run build,观察结果

首先,图片资源被打包到了 dist/asset/imgs 目录中,并且只有两张图片,分别是 2.png 和 3.gif 打包后的输出

1676175907673.png

而 1.jpeg 没有,是因为 1.jpeg 小于10kb的图片,所以被处理为了 base64 格式 打开页面,我们发现

1676176142361.png

1676176196535.png

至此,我们完成了对图片资源的处理。

6、处理字体图标资源

子图图标资源的处理和图片资源的处理方式类似,这里直接上配置,不再赘述

(1)配置

module.exports = {
    module: {
        rules: [
            {
                test: /\.(ttf|woff2?)$/,
                type: "asset/resource",
                generator: {
                  // 将字体图标文件输出到 asset/fonts 目录中
                  // 将字体图标命名 [hash:8][ext][query]
                  // [hash:8]: hash值取8位
                  // [ext]: 使用之前的文件扩展名
                  // [query]: 添加之前的query参数
                  filename: "asset/fonts/[hash:8][ext][query]",
                },
            },
        ]
    }
}

(2)在阿里巴巴矢量库,选择想要的图标添加到购物车,统一下载到本地(不会的同学可以百度,这里不过多赘述)

(3)将 iconfont.ttf、 iconfont.woff、 iconfont.woff2 添加到 src/asset/fonts, 将 iconfont.css 添加到 src/asset/styles

1676176751774.png

(4)使用字体图标,在 src/index.js 中引入字体图标

//src/index.js
import './styles/iconfont.css'

(5)在 src/public/index.html 中,使用字体图标

<i class="iconfont icon-yulan"></i>
<i class="iconfont icon-tiaozheng"></i>

(6)执行 npm run build,打开页面

1676177615447.png

至此,图标字体资源的处理完毕

7、处理其他资源

开发中可能还存在一些其他资源,如音视频等,我们也一起处理了

module.exports = {
    module: {
        rules: [
            {
                test: /\.(map4|map3|avi)$/,
                type: "asset/resource",
                generator: {
                  filename: "asset/media/[hash:8][ext][query]",
                },
            },
        ]
    }
}

8、处理 JS 资源

Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理,我们使用 Babel 来完成

(1)下载相关的包

npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime -D

其中:

@babel/core:babel核心库

babel-loader:处理 JS 的插件

@babel/preset-env:将 ES6 向后兼容

@babel/plugin-transform-runtime:处理 async,await、import() 等语法关键字的帮助函数

(2)根目录下,创建 babel.config.js 文件

module.exports = {
    presets: ["@babel/preset-env"],
};

(3)webpack.common.js中配置

module.exports = {
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                exclude: /node_modules/, // 排除node_modules代码不编译
                loader: "babel-loader",
            },
        ]
    }
}

(4)在 src/public/index.html 中

  <button>使用 es6 箭头函数</button>

    <script>
        document.querySelector('button').onclick = () => {
            console.log('使用 es6 箭头函数')
        }
    </script>

(5)执行 npm run build,打开页面,点击按钮后,窗口控制台的输出结果

1676179897345.png

9、区分环境

实际开发中,我们一般将 webpack 配置分为 webpack.common.js(公共配置)、webpack.config.dev.js (开发环境) 和 webpack.config.prod.js (生产环境),将配置的代码合并,避免重复代码

(1)npm i webpack-merge -D

(2)创建 src/webpack/webpack.config.dev.jssrc/webpack/webpack.config.prod.js,并分别对不同环境进行配置

  • 开发环境 webpack.config.dev.js

(1)npm i webpack-dev-server -D

(2)配置

const path = require("path");

module.exports = {
  mode: "development",
  devServer: {
    hot: true, //热更新
    open: true, //编译完自动打开浏览器
    compress: true, //开启gzip压缩
    port: 3000, //开启端口号
    //托管的静态资源文件
    //可通过数组的方式托管多个静态资源文件
    static: {
      directory: path.join(__dirname, "../public"),
    },
  },
};
  • 生产环境 webpack.config.prod.js
module.exports = {
  mode: "production",
  output: {
    clean: true
  }
};

(3)打开 package.json,写下命令

{
    //...其他代码
    "scripts": {
        "build": "webpack --config ./webpack/webpack.common.js --env production",
        "serve": "webpack serve --config ./webpack/webpack.common.js --env development"
      },
}

(4)修改 src/webpack/webpack.common.js 中的配置

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

//合并配置的插件
const { merge } = require("webpack-merge");
//引入生产环境和开发环境的配置
const prodConfig = require("./webpack.config.prod");
const devConfig = require("./webpack.config.dev");

const getStyleLoaders = (preProcessor) => {
    return [
        MiniCssExtractPlugin.loader,
        "css-loader",
        //在 css-loader 后,配置 postcss-loader
        {
            loader: "postcss-loader",
            options: {
                postcssOptions: {
                    plugins: [
                        "postcss-preset-env", // 能解决大多数样式兼容性问题
                    ],
                },
            },
        },
        preProcessor,
    ].filter(Boolean);
};

const commonConfig = {
    //打包的入口配置
    //相对路径和绝对路径都行
    entry: path.resolve(__dirname, "../src/index.js"),
    //打包文件的出口配置
    output: {
        // path: 文件输出目录,必须是绝对路径
        // path.resolve()方法返回一个绝对路径
        // __dirname 当前文件的文件夹绝对路径
        path: path.resolve(__dirname, '../dist'),
        //输出的文件名
        filename: 'bundle.js',
    },
    //加载器配置
    module: {
        rules: [
            {
                test: /\.css$/,
                use: getStyleLoaders(),
            },
            {
                test: /\.less$/, //匹配以 less 结尾的文件
                use: getStyleLoaders("less-loader"),
            },
            {
                test: /\.s[ac]ss$/,
                use: getStyleLoaders("sass-loader"),
            },
            {
                test: /\.(png|jpe?g|gif|webp)$/,
                type: "asset",
                parser: {
                    dataUrlCondition: {
                      // 小于10kb的图片会被base64处理
                      // 优点:减少请求数量
                      // 缺点:体积更大
                      maxSize: 10 * 1024
                    }
                },
                generator: {
                    // 将图片文件输出到 static/imgs 目录中
                    // 将图片文件命名 [hash:8][ext][query]
                    // [hash:8]: hash值取8位
                    // [ext]: 使用之前的文件扩展名
                    // [query]: 添加之前的query参数
                    filename: "asset/imgs/[hash:8][ext][query]",
                },
            },
            {
                test: /\.(ttf|woff2?)$/,
                type: "asset/resource",
                generator: {
                  filename: "asset/fonts/[hash:8][ext][query]",
                },
            },
            {
                test: /(\.jsx|\.js)$/,
                exclude: /node_modules/, // 排除node_modules代码不编译
                loader: "babel-loader",
            },
        ]
    },
    //插件配置
    plugins: [
        new HtmlWebpackPlugin({
            //输出的路径
            template: path.resolve(__dirname, '../public/index.html'),
            //输出的文件名
            filename: 'index.html'
        }),
        // 提取css成单独文件
        new MiniCssExtractPlugin({
            // 定义输出文件名和目录
            filename: "asset/css/main.css",
        }),
        // css压缩
        new CssMinimizerPlugin(),
    ],
}

module.exports = function(env) {
    //env.production 用于获取 终端命令行中 
    const isProduction = env.production;
    process.env.NODE_ENV = isProduction ? "production": "development";
  
    const config = isProduction ? prodConfig : devConfig;
    const mergeConfig = merge(commonConfig, config);
  
    return mergeConfig;
  };

(5)运行 npm run serve 查看开发环境

1676181190999.png

打开 localhost:3000

1676181260385.png

此时,我们去更改 src/a.js 中的输出,然后保存

//src/a.js
export function printA() {
    console.log('aaaaaaaa')
}

发现页面进行了热更新

1676181337924.png

至此,webpack 的环境分离已经完成

结尾

以上就是 webpack5 基础配置的教程,希望能帮助初学者学习,以及老手巩固基础

如果 这篇文章 对你有帮助,欢迎 点赞、收藏、评论,如果有 错误或还有疑问的地方,请 评论留言或者私信!