[ 理解Loader 理解插件 | 青训营笔记]

63 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天

理解Loader

问题:Webpack只认JS

为处理非标准JS 资源,设计出资源翻译模块

loader

用于将资源翻译为标准JS

使用Loader

  1. 按照Loader
npm add -D css-loader style-loader less-loader
  1. 添加module处理CSS文件
module.exports = {
  modules: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          "style-loader",
          "css-loader",
          "less-loader",
        ],
      },
    ],
  },
},

认识Loader: 链式调用

从前面的示例里面可以得到,我们用到了三个loader,分别是style-loader、css-loader、less-loader。

image.png

三个loader的职责

  • css-loader:将css包装成类型module.exports = "${css}" 的内容,包装后的内容符合JS的语法。
  • style-loader:将css模块包进require语句,并在运行时调用rejectStyle等函数将内容注入到页面的style标签。
  • less-loader:实现less->css的转换

认识Loader: 其他特性

image.png

特点

  1. 链式执行
  2. 支持异步执行
  3. 分normal、pitch两种模式

注:不是重点,不重要。pitch阶段,如果任何一个loader的pitch阶段有返回值的话,就会停止执行后面的阶段。通过这一特性,经常用来做一些catch,catch loader就是根据这一特性写的。

编写Loader

src/index.js

 console.log('hello xiaochengzi');

loaders/loader.js书写loader代码

module.exports = function(source) { 
// 这里不能用箭头函数
// source 为 loader 的输入
// 可能是文件内容,也可能是上一个 loader 处理的结果
  return source.replace('xiaochengzi', this.query.name);
}

在webpack.config.js中做 loader 的使用配置

const path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /.js/,
      use: [
        {
          loader: path.resolve(__dirname, './loaders/loader.js'),
          options: {
            name: 'world' // 传递给loader的参数
          }
        }
      ] // 使用自己写的loader模块 
    }] 
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

常见Loader

掌握这些常用的 Loader 的功能、配置方法。 image.png

理解插件

插件是什么?

为什么设计插件?

原因

  • 如果不用插件,当新人参加到项目中来,需要了解现有的整个流程细节,时间成本成本高,产出低;
  • 如果不用插件,功能迭代成本高,牵一发而动全身;
  • 如果不用插件,对于开源项目,功能僵化,缺乏成长性。

心智成本高 => 可维护性低 => 生命力弱

作用

提高应用、工具的扩展性

插件架构精髓

对扩展开发,对修改封闭

理解插件

插件安装、使用步骤(以 Webpack Dashboard 为例)

  1. 安装插件
npm i -D webpack-dashboard
  1. webpack-config.js配置项
    1. 引入插件
const DashboardPlugin = require('webpack-dashboard/plugin')
  1. 创建插件实例
module.exports = { 
  // ... 
  plugins: [new DashboardPlugin()], 
  // ... 
};

写插件

// 一个 JavaScript 类
class MyWebpackPlugin {
  // 在插件函数的 prototype 上定义一个 `apply` 方法,以 compiler 为参数。
  apply(compiler) {
    // 指定一个挂载到 webpack 自身的事件钩子。
    compiler.hooks.thisCompilation.tap(
      'MyWebpackPlugin',
      (compilation, callback) => {
      }
    );
  }
}

注:tap是同步方法,tapAsnyc 和 tapPromise 是异步方法。

插件围绕‘钩子’展开 thisCompilation就是一个钩子,相当于一个事件 钩子的核心信息

  1. 时机

什么时候触发的事件。

实例中,当有一个compilation对象传入时,事件被触发。

  1. 上下文

通过Tapable提供的回调机制,以参数方式传递上下文信息。

  1. 交互

在上下文参数对象中附带了很多存在side effect 的交互接口,插件可以通过这些接口改变。

关键的钩子 image.png

image.png 时机:compiler.hooks.compilation

参数:compilation等

交互:dependencyFactories.set