使用 Webpack5 配置多页面应用

188 阅读2分钟
注:文章理解源于哲玄前端(全栈)的大前端全栈实践

什么是前端构建

.html.js.css 在浏览器的共同工作,可以渲染出可交互的丰富网页内容。然而,在实际开发中,我们编写的都是 .vue.jsx 等浏览器无法识别的业务文件。而将业务文件解析为浏览器识别的文件,即为 前端构建

行业内前端构建工具包含 WebpackViteRollup 等,本文采用 Webpack5 进行实现。

前端构建核心步骤

而解析引擎的核心三个步骤分别是: 解析编译模块分包压缩优化

  • 解析编译Webpack5 中主要通过以下方式实现:
    • 使用 config.entry 配置入口文件。
    • 使用 config.resolve 配置模块解析的行为。
    • 使用 config.loader 配置各种类型文件的解析。
    • 使用 config.plugins 配置 loader 无法实现的功能。

在多页面应用中,我们需要一个约定:所有入口文件应放在 pages 文件夹下,并以 entry.*.js 命名。通过结合 glob 库和 html-webpack-plugin 插件,可以自动生成入口配置和打包文件引入。

const glob = require("glob");
const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");

const pageEntries = {};
const htmlWebpackPluginList = [];

// 获取 app/pages 目录下所有入口文件 (entry.xxx.js)
const entryList = path.resolve(process.cwd(), "./app/pages/**/entry.*.js");
glob.sync(entryList).forEach((file) => {
  const entryName = path.basename(file, ".js");
  // 构造 entry
  pageEntries[entryName] = file;

  // 构造最终渲染的页面文件
  htmlWebpackPluginList.push(
    // html-webpack-plugin 辅助注入打包后的 bundle 文件到 tpl 文件中
    new HTMLWebpackPlugin({
      // 产物 (最终模板) 输出路径
      filename: path.resolve(
        process.cwd(),
        "./app/public/dist/",
        `${entryName}.tpl`
      ),
      // 指定使用的模板文件
      template: path.resolve(process.cwd(), "./app/view/entry.tpl"),
      // 要注入的代码块
      chunks: [entryName],
    })
  );
});
  • 模块分包和压缩优化:这些通常通过 config.optimization 配置实现。

开发环境与生产环境的配置

开发环境

开发环境的核心是启动热模块替换功能(HMR)和开发服务器。为深入理解开发服务器的工作原理,可以自行实现一个开发服务器,也可以使用 Webpack 的官方开发服务器。

以下是一个自定义开发服务器的实现示例:

// 本地开发启动 devServer
const express = require("express");
const path = require("path");
const webpack = require("webpack");
const consoler = require("consoler");
const devMiddleware = require("webpack-dev-middleware");
const hotMiddleware = require("webpack-hot-middleware");

// 从 webpack.dev.js 获取 webpack 配置 和devServer 配置
const { webpackConfig, DEV_SERVER_CONFIG } = require("./config/webpack.dev.js");

const app = express();

const compiler = webpack(webpackConfig);

// 静态文件目录
app.use(express.static(path.join(__dirname, "../public/dist")));

// 引入 devMiddleware 中间件 (监控文件改动)
app.use(
  devMiddleware(compiler, {
    // 落地文件
    writeToDisk: (filePath) => filePath.endsWith(".tpl"),
    // 资源路径
    publicPath: webpackConfig.output.publicPath,
    // headers 配置
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, PORT, PUT, DELETE, PATCH, OPTIONS",
      "Access-Control-Allow-Headers":
        "X-Request-With, content-type, Authorization",
    },
    stats: {
      colors: true,
    },
  })
);

// 引入 hotMiddleware 中间件 (实现热更新通讯)
app.use(
  hotMiddleware(compiler, {
    path: `/${DEV_SERVER_CONFIG.HMR_PATH}`,
    log: () => {},
  })
);

consoler.info("请等待 webpack 初次构建完成提示...");

// 启动 devServer 服务
const port = DEV_SERVER_CONFIG.PORT;
app.listen(port, () => {
  console.log(`app listening on port: ${port}`);
});

生产环境

在生产环境中,重点是提升打包效率和优化性能。例如:

  • 压缩资源文件(如 JavaScript、CSS 和图片)。
  • 提炼 CSS 资源为独立文件。
  • 使用多进程打包以提高构建速度。
  • 管理产物文件夹,确保干净和有序。

总结

通过前端构建,我们可以将复杂的业务文件解析为浏览器可识别的资源文件,从而实现现代化的前端开发流程。

例如,以下代码无法直接在浏览器中运行:

// index.js
import _ from "lodash";
import "./index.css";

这是因为现代前端开发依赖于构建工具来管理代码和资源,通过自动化流程生成最终的可执行文件。这正是前端工程化的意义所在。