删库在逃程序员的Blog

Webpack 资源处理大全 —— CSS/JS/HTML/图片/字体完整指南

author
·
8
0

Webpack 资源处理大全 —— CSS/JS/HTML/图片/字体完整指南

系列文章第 4 篇 | 预计阅读时间:18 分钟


一、资源处理概述

Webpack 的核心功能之一就是处理各种类型的资源文件

资源类型 处理方式 核心 Loader/Plugin
CSS/Less/Sass 样式处理 style-loader, css-loader
JavaScript 编译转换 babel-loader
HTML 模板生成 html-webpack-plugin
图片 资源模块 Asset Modules
字体图标 资源模块 Asset Modules

二、CSS 资源处理

2.1 基础 CSS 处理

安装依赖:

npm i style-loader css-loader -D

配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],  // 从右到左执行
      },
    ],
  },
};

两个 Loader 的作用:

Loader 作用
css-loader 将 CSS 编译成 Webpack 能识别的模块
style-loader 创建 <style> 标签,将样式注入页面

在 JS 中引入 CSS:

// main.js
import "./css/index.css";

2.2 Less/Sass/Stylus 处理

安装依赖:

npm i less-loader -D                    # Less
npm i sass-loader sass -D               # Sass/Scss
npm i stylus-loader -D                  # Stylus

配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
        test: /\.styl$/,
        use: ["style-loader", "css-loader", "stylus-loader"],
      },
    ],
  },
};

使用示例:

// main.js
import "./css/index.css";
import "./less/index.less";
import "./sass/index.scss";
import "./styl/index.styl";

2.3 CSS 兼容性处理

使用 postcss-loader 自动添加浏览器前缀:

安装依赖:

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

配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  "postcss-preset-env",  // 自动添加浏览器前缀
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

效果:

/* 输入 */
.box {
  display: flex;
}

/* 输出(自动添加前缀) */
.box {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}

三、JavaScript 资源处理

3.1 Babel 编译

作用: 将 ES6+ 语法转换为向后兼容的 JavaScript

安装依赖:

npm i babel-loader @babel/core @babel/preset-env -D

babel.config.js 配置:

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

webpack.config.js 配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,  // 排除第三方代码
        loader: "babel-loader",
      },
    ],
  },
};

3.2 ESLint 代码检查

作用: 统一团队代码风格,提前发现潜在问题

安装依赖:

npm i eslint-webpack-plugin eslint -D

.eslintrc.js 配置:

module.exports = {
  extends: ["eslint:recommended"],
  env: {
    node: true,
    browser: true,
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: "module",
  },
  rules: {
    "no-var": 2,  // 禁止使用 var
  },
};

webpack.config.js 配置:

const ESLintWebpackPlugin = require("eslint-webpack-plugin");

module.exports = {
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "src"),  // 检查根目录
      exclude: /node_modules/,  // 排除 node_modules
    }),
  ],
};

3.3 忽略 ESLint 检查的文件

创建 .eslintignore 文件:

# 忽略 dist 目录
dist
# 忽略构建文件
build

四、HTML 资源处理

4.1 HtmlWebpackPlugin

作用:

  1. 自动生成 HTML 文件
  2. 自动引入打包生成的 JS/CSS 资源
  3. 支持自定义模板

安装依赖:

npm i html-webpack-plugin -D

配置:

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",  // 模板文件
      filename: "index.html",           // 输出文件名
      minify: {
        collapseWhitespace: true,       // 压缩 HTML
        removeComments: true,           // 移除注释
      },
    }),
  ],
};

模板文件(public/index.html):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Webpack App</title>
    <!-- 不需要手动引入 JS,插件会自动添加 -->
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

输出结果:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Webpack App</title>
    <script src="main.a1b2c3d4.js"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

4.2 HTML 压缩

生产模式默认开启 HTML 压缩,无需额外配置。

如需自定义压缩选项:

new HtmlWebpackPlugin({
  template: "./public/index.html",
  minify: {
    collapseWhitespace: true,    // 折叠空白
    removeComments: true,        // 移除注释
    removeAttributeQuotes: true, // 移除属性引号
    minifyCSS: true,             // 压缩内联 CSS
    minifyJS: true,              // 压缩内联 JS
  },
});

五、图片资源处理

5.1 Asset Modules(Webpack 5 内置)

Webpack 5 使用 Asset Modules 处理图片,无需额外安装 Loader。

配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|webp|svg)$/,
        type: "asset",  // 自动选择 inline 或 resource
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,  // 小于 10kb 转 base64
          },
        },
        generator: {
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
    ],
  },
};

type 的四种类型:

类型 作用 相当于
asset 自动选择 inline 或 resource url-loader
asset/resource 输出文件 URL file-loader
asset/inline 输出 base64 Data URI url-loader (仅 inline)
asset/source 输出文件原始内容 raw-loader

5.2 使用方式

在 CSS 中使用:

/* less/index.less */
.box {
  width: 100px;
  height: 100px;
  background-image: url("../images/bg.png");
  background-size: cover;
}

在 JS 中使用:

// main.js
import logo from "./images/logo.png";

const img = document.createElement("img");
img.src = logo;
document.body.appendChild(img);

5.3 图片压缩

安装插件:

npm i image-minimizer-webpack-plugin imagemin -D
npm i imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D

配置:

const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");

module.exports = {
  optimization: {
    minimizer: [
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
  },
};

六、字体图标处理

6.1 下载字体图标

  1. 打开 阿里巴巴矢量图标库
  2. 选择图标添加到购物车
  3. 下载到本地,解压到 src/fonts/ 目录

6.2 配置

module.exports = {
  module: {
    rules: [
      {
        test: /\.(ttf|woff2?|eot)$/,
        type: "asset/resource",
        generator: {
          filename: "static/fonts/[hash:8][ext][query]",
        },
      },
    ],
  },
};

6.3 使用方式

引入 CSS 文件:

// main.js
import "./css/iconfont.css";

在 HTML 中使用:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Webpack App</title>
  </head>
  <body>
    <!-- 使用字体图标 -->
    <i class="iconfont icon-arrow-down"></i>
    <i class="iconfont icon-ashbin"></i>
    <i class="iconfont icon-browse"></i>
  </body>
</html>

七、开发服务器

7.1 安装与配置

安装依赖:

npm i webpack-dev-server -D

配置:

module.exports = {
  devServer: {
    host: "localhost",      // 服务器域名
    port: 3000,             // 服务器端口
    open: true,             // 自动打开浏览器
    hot: true,              // 开启 HMR
    compress: true,         // 启用 gzip 压缩
    proxy: {                // 代理配置
      "/api": {
        target: "http://localhost:8080",
        changeOrigin: true,
        pathRewrite: { "^/api": "" },
      },
    },
  },
};

7.2 启动脚本

package.json 配置:

{
  "scripts": {
    "start": "npm run dev",
    "dev": "npx webpack serve --config webpack.config.js",
    "build": "npx webpack --config webpack.prod.js"
  }
}

启动开发服务器:

npm run dev

7.3 开发服务器特点

  • ✅ 代码在内存中编译打包,不输出到磁盘
  • ✅ 支持热模块替换(HMR)
  • ✅ 自动刷新浏览器
  • ✅ 支持代理解决跨域问题

八、完整配置示例

8.1 开发模式配置

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/main.js",
  output: {
    path: undefined,  // 开发模式不输出
    filename: "static/js/main.js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "src"),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public/index.html"),
    }),
  ],
  devServer: {
    host: "localhost",
    port: 3000,
    open: true,
    hot: true,
  },
  mode: "development",
  devtool: "cheap-module-source-map",
};

8.2 生产模式配置

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "js/[name].[contenthash:8].js",
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: ["postcss-preset-env"],
              },
            },
          },
        ],
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "less-loader",
        ],
      },
      {
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
          filename: "media/[name].[contenthash:8][ext]",
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader",
            options: {
              cacheDirectory: true,
              plugins: ["@babel/plugin-transform-runtime"],
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
      context: path.resolve(__dirname, "src"),
      cache: true,
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public/index.html"),
      minify: {
        collapseWhitespace: true,
        removeComments: true,
      },
    }),
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash:8].css",
    }),
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
      new TerserPlugin(),
    ],
    splitChunks: {
      chunks: "all",
    },
  },
  mode: "production",
  devtool: "source-map",
};

九、小结

本篇我们学习了 Webpack 处理各种资源的完整方案:

资源类型 核心方案 关键配置
CSS style-loader + css-loader 生产模式用 MiniCssExtractPlugin
Less/Sass 预处理器 Loader 添加对应预处理器依赖
JS babel-loader + ESLint 开启缓存优化速度
HTML HtmlWebpackPlugin 自动引入资源
图片 Asset Modules type: "asset"
字体 Asset Modules type: "asset/resource"

最佳实践总结:

  1. ✅ 开发模式使用 style-loader(热更新)
  2. ✅ 生产模式使用 MiniCssExtractPlugin(提取 CSS)
  3. ✅ 图片使用 Asset Modules(Webpack 5 内置)
  4. ✅ 字体图标使用 asset/resource
  5. ✅ HTML 使用 HtmlWebpackPlugin 自动生成
  6. ✅ 开启 Babel 和 ESLint 缓存

下一篇预告: 《高级优化实战》—— 深入讲解 PWA、Core-js、多进程打包、性能分析等高级主题,让你的项目达到生产级优化水准!


系列导航:

  • 📌 第 1 篇:Webpack 入门与基础
  • 📌 第 2 篇:开发模式完全指南
  • 📌 第 3 篇:生产模式与性能优化
  • 📌 第 4 篇:资源处理大全(本文)
  • ⏭️ 第 5 篇:高级优化实战

本文基于 Webpack 5 编写,如有问题欢迎留言讨论。

评论 (0)