自学内容网 自学内容网

Webpack 特性:自定义 Loader 和 Plugin

前言:

Webpack是一个现代JavaScript应用的静态模块打包器,它能够将项目中的所有依赖项(包括JavaScript、图片、CSS等)打包成一个或多个bundle
在Webpack的构建过程中,存在许多生命周期钩子(hooks),这些钩子允许插件(plugins)和loaders在不同阶段介入构建过程。

Loader

  • 一个模块转换器它使得 Webpack 能够处理非 JavaScript 文件。Loader 在import模块时被调用,并且可以链式调用,形成一个处理流程。
  • Loader 通常用于转换文件,比如将 Sass 文件转换为 CSS,或者将图像文件转换为 DataURL。
  • Loader本身是一个函数,它接收源文件作为输入,输出转换后的文件内容。

自定义 Loader 的实现

我们现在的需求是,将 Markdown 文件转换为 HTML, 实现步骤

  1. 创建一个 JavaScript 文件作为 Loader,比如my-loader.js
  2. 在这个文件中,导出一个函数,这个函数将对文件资源进行处理。
  3. 在 Webpack 配置文件中webpack.config.js,添加一个规则,指定该 Loader 应用到特定的文件类型上。
// my-loader.js
const marked = require("marked");
module.exports = function (source) {
  // 使用marked将markdown转换为html
  const html = marked(source);
  return html;
};

然后在webpack.config.js中配置这个 Loader:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.md$/,
        use: "./my-loader",
      },
    ],
  },
};

Webpack生命周期:

在写plugin之前,我们先回顾下 webpack的 生命周期和内部使用的TapTable的库(用于处理事件注册和触发的)

Webpack的生命周期主要分为两个部分:Compiler 生命周期和Compilation 生命周期。

  • Compiler 生命周期是关于整个构建过程的,例如:

    • beforeRun:在开始编译之前调用。
    • run:在编译开始时调用。
    • emit:在所有资源被emit到发输目录之前调用。
    • done:在编译完成之后调用。
  • Compilation 生命周期是关于单独一次编译的,例如:

    • buildModule:在模块开始构建时调用。
    • normalModuleFactory:在模块工厂创建时调用。
    • seal:在编译完成,优化阶段开始之前调用。

Tapable

Tapable 是一个基于发布订阅模式实现的事件系统,Webpack 中的插件(Plugins)就是使用 Tapable 来监听和改变构建流程, Tapable允许开发者创建自定义的钩子,并且可以在这些钩子上注册监听函数,这些函数将在钩子被触发时执行。

Tapable 提供了多种类型的钩子,分为同步异步两大类,每种类型又有不同的行为。

安装 Tapable

首先,你需要安装 Tapable:

npm install --save tapable

钩子的类型

  • SyncHook: 同步执行,无返回值。
  • SyncBailHook: 同步执行,返回非 undefined 则中断。
  • SyncWaterfallHook: 同步执行,返回值会传递给下一个回调。
  • SyncLoopHook: 同步执行,返回非 undefined 则重新执行当前回调。
  • AsyncParallelHook: 异步并行执行。
  • AsyncParallelBailHook: 异步并行执行,有返回值则中断。
  • AsyncSeriesHook: 异步串行执行。
  • AsyncSeriesBailHook: 异步串行执行,有返回值则中断。
  • AsyncSeriesWaterfallHook: 异步串行执行,返回值会传递给下一个回调。

使用 Tapable

同步钩子(SyncHook)

Sync 类型 “钩子” 执行的插件都是顺序执行的,并且只能使用 tap 注册,可以使用 call 调用。

const { SyncHook } = require('tapable');

const hook = new SyncHook(['arg1', 'arg2']);
hook.tap('myPlugin', (arg1, arg2) => {
  console.log(`myPlugin: ${arg1}, ${arg2}`);
});

hook.call('hello', 'world'); // 输出:myPlugin: hello, world
异步钩子

异步钩子可以注册异步的回调函数,分为并行(AsyncParallelHook)串行(AsyncSeriesHook)两种。

AsyncParallelHook

并行执行所有注册的异步回调,所有回调完成后执行最终的回调。

const { AsyncParallelHook } = require('tapable');

const hook = new AsyncParallelHook(['arg1']);
hook.tapAsync('myAsyncPlugin', (arg1, callback) => {
  setTimeout(() => {
    console.log(`myAsyncPlugin: ${arg1}`);
    callback();
  }, 1000);
});

hook.callAsync('test', () => {
  console.log('所有任务执行完毕.');
});
AsyncSeriesHook

串行执行所有注册的异步回调,每个回调完成后,才会执行下一个。

const { AsyncSeriesHook } = require('tapable');

const hook = new AsyncSeriesHook(['arg1']);
hook.tapAsync('mySeriesPlugin', (arg1, callback) => {
  setTimeout(() => {
    console.log(`mySeriesPlugin: ${arg1}`);
    callback();
  }, 1000);
});

hook.callAsync('test', () => {
  console.log('所有任务执行完毕.');
});

钩子的拦截器(Interceptor)

Tapable 还允许你为钩子添加拦截器,可以在钩子执行前后添加自定义逻辑。

const hook = new SyncHook(['arg1', 'arg2']);
hook.intercept({
  call: (arg1, arg2) => {
    console.log(`Before call: ${arg1}, ${arg2}`);
  },
  tap: (tapInfo) => {
    console.log(`Tap registered: ${tapInfo.name}`);
  }
});

自定义 Plugin 的实现:

  1. 创建一个 JavaScript 文件作为 Plugin,比如my-plugin.js
  2. 在这个文件中,定义一个类,这个类必须实现apply方法。
  3. apply方法中,接受compiler参数,我们可以在上面注册我们的事件,并执行自定义逻辑。
// my-plugin.js
class MyPlugin {
  apply(compiler) {
    compiler.hooks.done.tap("MyPlugin", (stats) => {
      console.log("构建完成!");
      // 这里可以执行一些构建完成后的逻辑
      // 将打包后的代码上传至 minio, 方便下载
    });
  }
}
module.exports = MyPlugin;

然后在webpack.config.js中配置这个 Plugin:

// webpack.config.js
const MyPlugin = require("./my-plugin");
module.exports = {
  plugins: [new MyPlugin()],
};

原文地址:https://blog.csdn.net/cdns_1/article/details/142661211

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!