Spec-Zone.ru › webpack 1

Как написать загрузчик

Загрузчик — это модуль узла, экспортирующий function.

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

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

Загрузчик может получить доступ к API загрузчика в контексте this в функции.

Синхронный загрузчик, который хочет вернуть только одно значение, может просто return это значение. В любом другом случае загрузчик может вернуть любое количество значений с помощью функции this.callback(err, values...). Ошибки передаются функции this.callback или выбрасываются в синхронном загрузчике.

Загрузчик должен вернуть одно или два значения. Первое значение — это результирующий JavaScript-код в виде строки или буфера. Второе необязательное значение — SourceMap в виде JavaScript-объекта.

В сложном случае, когда цепочкой подключены несколько загрузчиков, только последний загрузчик получает файл ресурса, и только первый загрузчик ожидает возврата одного или двух значений (JavaScript и SourceMap). Значения, возвращаемые другими загрузчиками, передаются предыдущему загрузчику.

Примеры

// Identity loader
module.exports = function(source) {
  return source;
};
// Identity loader with SourceMap support
module.exports = function(source, map) {
  this.callback(null, source, map);
};

Рекомендации

(В порядке приоритета, первый должен иметь наивысший приоритет)

Загрузчики должны

Выполнять только одну задачу

Загрузчики могут быть объединены в цепочку. Создавайте загрузчики для каждой задачи, вместо загрузчика, выполняющего всё сразу.

Это также означает, что они не должны преобразовывать в JavaScript, если это не необходимо.

Пример: рендеринг HTML из файла шаблона путём применения параметров запроса

Я мог бы написать загрузчик, который компилирует шаблон из исходного кода, выполняет его и возвращает модуль, экспортирующий строку, содержащую HTML-код. Это плохо.

Вместо этого я должен написать загрузчики для каждой задачи в этом случае и применить их все (последовательность):

  • jade-loader: Преобразовать шаблон в модуль, экспортирующий функцию.
  • apply-loader: Принимает функцию, экспортирующую модуль, и возвращает исходный результат, применяя параметры запроса.
  • html-loader: Принимает HTML и экспортирует строку, экспортирующую модуль.

Генерировать модули, которые являются модульными

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

Пример: Это плохой дизайн: (не модульный, глобальное состояние, …)

require("any-template-language-loader!./xyz.atl");

var html = anyTemplateLanguage.render("xyz");

Помечать себя как кешируемые, если это возможно

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

Просто вызовите cacheable в загрузчике.

// Cacheable identity loader
module.exports = function(source) {
    this.cacheable();
    return source;
};

Не сохранять состояние между запусками и модулями

Загрузчик должен быть независимым от других скомпилированных модулей (за исключением тех, которые были выпущены загрузчиком).

Загрузчик должен быть независимым от предыдущих компиляций того же модуля.

Помечать зависимости

Если загрузчик использует внешние ресурсы (например, считывание из файловой системы), он обязан сообщить об этом. Эта информация используется для аннулирования кешируемых загрузчиков и повторной компиляции в режиме наблюдения.

// Loader adding a header
var path = require("path");
module.exports = function(source) {
    this.cacheable();
    var callback = this.async();
    var headerPath = path.resolve("header.js");
    this.addDependency(headerPath);
    fs.readFile(headerPath, "utf-8", function(err, header) {
        if(err) return callback(err);
        callback(null, header + "\n" + source);
    });
};

Разрешать зависимости

Во многих языках есть схема для указания зависимостей. Например, в CSS есть @import и url(...). Эти зависимости должны быть разрешены системой модулей.

Есть два варианта:

  • Преобразовать их в require.
  • Использовать функцию this.resolve для разрешения пути

Пример 1 css-loader: css-loader преобразует зависимости в require, заменив @import на require к другому стилю (также обработанному css-loader) и url(...) на require к файлу-ссылке.

Пример 2 less-loader: less-loader не может преобразовать @import в require, потому что все файлы less нужно скомпилировать за один проход, чтобы отслеживать переменные и миксины. Поэтому less-loader расширяет компилятор less с помощью пользовательской логики разрешения путей. Эта пользовательская логика использует this.resolve для разрешения файла с настройками системы модулей (алиасы, пользовательские каталоги модулей и т. д.).

Если язык принимает только относительные URL (например, в CSS url(file) всегда означает ./file), существует соглашение ~ для указания ссылок на модули:

url(file) -> require("./file")
url(~module) -> require("module")

Извлекать общий код

не генерируйте много кода, который является общим для каждого модуля, обработанного этим загрузчиком. Создайте (временный) файл в загрузчике и сгенерируйте require для этого общего кода.

Не следует встраивать абсолютные пути

Не встраивайте абсолютные пути в код модуля. Они нарушают хеширование, когда корень проекта перемещается. Существует метод stringifyRequest в loader-utils, который преобразует абсолютный путь в относительный.

Пример:

var loaderUtils = require("loader-utils");
return "var runtime = require(" +
  loaderUtils.stringifyRequest(this, "!" + require.resolve("module/runtime")) +
  ");";

Использовать библиотеку как peerDependencies при её использовании

Использование peerDependency позволяет разработчику приложения указать точную версию в package.json, если это необходимо. Зависимость должна быть относительно открытой, чтобы позволить обновление библиотеки без необходимости публикации новой версии загрузчика.

"peerDependencies": {
    "library": "^1.3.5"
}

Программируемые объекты в качестве query-опции

Встречаются ситуации, когда ваш загрузчик требует программируемых объектов с функциями, которые нельзя преобразовать в query-строку. Например, less-loader предоставляет возможность указать LESS-плагины. В таких случаях загрузчик может расширить options-объект webpack для получения этой опции. Чтобы избежать конфликтов имён, однако, важно, чтобы опция именовалась в пространстве имён загрузчика с использованием camelCase npm-имени.

Пример:

// webpack.config.js
module.exports = {
  ...
  lessLoader: {
    lessPlugins: [
      new LessPluginCleanCSS({advanced: true})
    ]
  }
};

Загрузчик также должен позволять указать ключ конфигурации (например, lessLoader) через query. См. обсуждение и пример реализации.

Добавляться в список загрузчиков

Список загрузчиков

Подробнее

Подробнее о загрузчиках.

© 2012–2015 Tobias Koppers
Licensed under the MIT License.
https://webpack.github.io/docs/how-to-write-a-loader.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API