Разбор принципа работы вебпака (2) Реализовать простой загрузчик

внешний интерфейс Webpack
Разбор принципа работы вебпака (2) Реализовать простой загрузчик

Что такое загрузчик

в вебпакеloaderЭто очень важная концепция, загрузчик можно просто понимать как файловый процессор, веб-пакет используетloaderдля обработки различных типов файлов, таких как.scssпревратиться вcssфайлы, небольшие изображения преобразуются в изображения base64.

По сути,loaderЭто просто модуль JavaScript, экспортированный как функция. Когда веб-пакет упаковывается, он вызывает эту функцию и передает результат или файл ресурсов, сгенерированный предыдущим загрузчиком.

На этот раз я собираюсь разработать программу, которая преобразует обычные изображения в.webpЗагрузчик форматов для достижения цели уменьшения размера изображения.

Библиотека инструментов загрузчика

Прежде чем разрабатывать загрузчик, вы должны сначала разобраться с двумя инструментами разработки загрузчика:loader-utilsа такжеschema-utils

  • loader-utilsИспользуется для получения загрузчикаoptions.
  • schema-utilsиспользуется для проверки загрузчикаoptionsа такжеJSON SchemaЯвляется ли определение структуры непротиворечивым.
import { getOptions } from 'loader-utils';
import { validateOptions } from 'schema-utils';
const schema = {
  // ...
}
export default function(source) {
  // 获取 options
  const options = getOptions(this);
  // 检验loader的options是否合法
  validateOptions(schema, options, 'Demo Loader');

  // 在这里写转换 loader 的逻辑
  // ...
};

Руководство по разработке загрузчика

  • Единая ответственность: загрузчик обрабатывает только одну задачу, что обеспечивает простоту и удобство сопровождения, а сложные сценарии можно выполнять, комбинируя несколько загрузчиков.
  • Модульность: Убедитесь, что загрузчик является модульным. Модуль, сгенерированный загрузчиком, должен следовать тем же принципам проектирования, что и обычные модули.
  • Без сохранения состояния: мы не должны сохранять состояние в загрузчике между несколькими переходами модуля. Каждая среда выполнения загрузчика должна обеспечивать независимость от других скомпилированных модулей, а также должна быть независима от результатов компиляции того же модуля, скомпилированного предыдущими загрузчиками.

Одним словом, когда мы пишем загрузчик, мы ограничиваем его обязанности и заботимся только о вводе и выводе.

Синхронные и асинхронные загрузчики

Причина, по которой загрузчик разделен на синхронный и асинхронный, заключается в том, что обработка некоторых ресурсов занимает много времени и требует обработки асинхронно, а затем продолжить выполнение после ожидания завершения обработки. для погрузчикаthis.callback()Вернуть результат обработки следующим образом:

this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);
  1. Первый параметр должен быть Error или null
  2. Второй параметр — это строка или буфер.
  3. Необязательно: третий аргумент должен быть исходной картой, которую может разрешить этот модуль.
  4. Необязательно: четвертый параметр, игнорируемый веб-пакетом, может быть чем угодно (например, некоторыми метаданными).
// 同步loader 返回多个处理结果
module.exports = function(content, map, meta) {
  this.callback(null, someSyncOperation(content), map, meta);
};

В синхронном режиме, если возвращается только один результат, его также можно использовать напрямую.returnВернуть результат.

// 同步loader 只返回一个处理结果
module.exports = function(content, map, meta) {
  return someSyncOperation(content);
};

Использование в асинхронном режимеthis.asyncполучитьcallbackфункция

module.exports = function(content, map, meta) {
  var callback = this.async();
  someAsyncOperation(content, function(err, result, sourceMaps, meta) {
    if (err) return callback(err);
    callback(null, result, sourceMaps, meta);
  });
};

Разработайте свой собственный загрузчик

Структура каталогов проекта

|--src
| |--cjs.js //общая записьJs
| |--index.js // основной файл загрузчика
| |--options.json // файл определения опций загрузчика
|--babel.config.js
|--package.json
|--readme.md

определить параметры

optionsтолько одно свойствоquality, используется для управления генерацией.webpКачество документа определяется следующим образом:

{
  "additionalProperties": true,
  "properties": {
    "quality": {
      "description": "quality factor (0:small..100:big), default=75",
      "type": "number"
    }
  },
  "type": "object"
}

Преобразование формата изображения

cwebpЭтот модуль js предоставляет обычные изображения и.webpфункция для преобразования между ними.

const CWebp = require('cwebp').CWebp

/**
 * 普通图片转 .webp图片
 * @param {string | buffer} img 图片绝对路径或二进制流
 * @param {number} quality 生成 webp 图片的质量,默认75
 * @returns .webp 文件流
 */
async function convertToWebp (img, quality = 75) {
  let encoder = new CWebp(img)
  encoder.quality = quality
  let buffer = await encoder.toBuffer()
  return buffer
}

загрузчик записи

import schema from './options.json'

export default async function loader (content) {
  // 异步模式
  let callback = this.async()
  // 获取 options
  const options = loaderUtils.getOptions(this) || {}
  // 验证 options
  validateOptions(schema, options, {
    name: 'webp Loader',
    baseDataPath: 'options'
  })
  try {
    // 普通图片转 .webp
    let buffer = await convertToWebp(content, options.quality)
    callback(null, buffer)
  } catch (err) {
    callback(err)
  }
}
// loader 接收文件流
export const raw = true

На этом загрузчик в основном готов.

использовать

// webpack.config.js
module.exports = {
  // 其他配置
  // ...
  module: {
    rules: [{
      test: /\.(png|jpg|gif)$/,
      use: [{
        loader: 'file-loader',
        options: {
          name: '[name].[ext].webp'
        }
      },{
        loader: 'webp-loader',
        options: {
          quality: 70 
        }
      }]
    }]
  }
}

Суммировать

На самом деле написать загрузчик не так сложно, как вы думаете, пока вы освоите базовые моменты, вы также сможете иметь свой собственный загрузчик.

Подписывайтесь на нас