从零开始学习webpack5.x(四)

241 阅读3分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战 」。

前面我们已经学习了modeentryoutputloader这些基本配置,接下来继续学习webpack最重要的一个基本配置:Plugin

Plugin(插件)

前文也提到,webpack有打包过程分为许多个步骤,每一个步骤都会有相对应的钩子
plugin的作用就是在钩子中添加对应的打包逻辑,当钩子触发会调用预先声明的函数。

Plugin与Loader的区别

与上一节我们学到的Loader不同,Plugin的用处比Loader更广泛。
Loader是让webpack支持除了js和json文件之外的文件处理。
Plugin则是针对整个webpack打包的步骤去对对打包项目进行扩展和管理,包括但不限于打包优化资源管理注入环境变量

Plugin的用法

聊完Plugin的基本概念,接下来看一下如何使用Plugin,前面我们已经学会将模块打包成一个整体的文件,现在我们想要把js文件在打包完成之后自动地引入到html文件中
首先我们新建一个html模板:

<!DOCTYPE html>
<html lang="text/html">
  <head>
    <title>test</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <p>Hello World</p>
  </body>
</html>

在写两个简单的js文件

// entry.js
function test1() {
  console.log("test1");
}
test1();

// test.js
function test2() {
  console.log("test2");
}
test2();

编写webpack配置,将他们打包合并在一起,并且引用html-webpack-plugin插件,将生成后的js文件写入html模板并输出。

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

module.exports = {
  mode: "production",
  entry: [
    path.resolve(__dirname, "src", "entry.js"),
    path.resolve(__dirname, "src", "test2.js"),
  ],
  output: {
    filename: "bundle.js",
  },
  plugins: [
    new htmlPlugin({
      template: path.resolve(__dirname, "src", "test.html"),
    }),
  ],
};

打包后会出现两个文件,一个是js文件,另一个是基于模板html生成的html文件。并且html文件会带上打包后的js文件引用。

<!doctype html>
<html lang="text/html">
  <head>
    <title>test</title>
    <meta charset="utf-8"/>
    <script defer="defer" src="bundle.js"></script>
  </head>
  <body>
    <p>Hello World</p>
  </body>
</html>

编写一个Plugin

学会使用plugin后,接下来深入地研究一下:plugin究竟是如何编写的。
plugin实际上是一个对象,对象中必须有一个apply方法。

function MyPlugin() {
    return {
        apply(complier) {
            complier.hooks.run.tap('MyPlugin', (compilation) => {
              console.log('webpack is running!');
            });
        }
    }
}

上面的代码就是一个最简单的webpack插件。

  • 从代码中可以看到apply方法调用时,webpack会传入一个complier对象到方法中,complier是webpack的主要引擎,他包含了生命周期钩子,webpack的配置等信息。
  • 然后我们声明了一个在run生命周期的时候调用的方法。
    当调用时,webpack会传入一个compilation实例,它能够访问所有的模块和它们的依赖。
    具体的compilercompilation钩子参数,点击这里了解更多

了解了plugin是如何实现的,接下来我们就来写一个简单版的html-webpack-plugin
具体实现的功能:当打包完成后,生成一个script标签放入html文件中。
代码如下:

// plugin.js
const fs = require("fs");
const path = require("path");

function MyPlugin(templateName = "") {
  return {
    apply(complier) {
      complier.hooks.run.tap("MyPlugin", (compilation) => {
        const { outputPath } = compilation;
        const fileName = compilation.options.output.filename;
        const script = `<script lang="text/javascript" defer src="${fileName}"></script>`;
        let fileChunk = fs.readFileSync(templateName, "utf-8");
        fileChunk = fileChunk.replace("</head>", `${script}\n</head>`);
        fs.writeFileSync(path.resolve(outputPath, "index.html"), fileChunk);
      });
    },
  };
}
module.exports = MyPlugin;

// webpack.config.js
const path = require("path");
const htmlPlugin = require("html-webpack-plugin");
const MyPlugin = require("./src/plugin");

module.exports = {
  mode: "production",
  entry: [
    path.resolve(__dirname, "src", "entry.js"),
    path.resolve(__dirname, "src", "test2.js"),
  ],
  output: {
    filename: "bundle.js",
  },
  plugins: [new MyPlugin(path.resolve(__dirname, "src", "test.html"))],
};

小结

本小节讲述了plugin的作用;pluginloader的区别;用法和如何编写一个plugin。

  • plugin的作用就是在钩子中添加对应的打包逻辑,在打包过程中进行一些额外的操作。
  • loader是让webpack支持其他文件的处理;plugin是针对整个webpack打包的步骤去对对打包项目进行扩展。
  • 实现一个plugin,只需要返回一个对象,对象中包含一个apply方法即可

文章是从零开始学习webpack系列的第四篇,其他章节可以看下面👇:

从零开始学习webpack5.x(一)
从零开始学习webpack5.x(二)
从零开始学习webpack5.x(三)
从零开始学习webpack5.x(四)
从零开始学习webpack5.x(五)
从零开始学习webpack5.x(六)