Как разработать загрузчики веб-пакетов

внешний интерфейс Webpack

О вебпаке

Как инструмент для упаковки, который в последнее время был в центре внимания, webpack в основном занял круг фронтенда. Я полагаю, вам неловко говорить, что вы не знаете webpack.
Заинтересованные студенты могут обратиться к моему предыдущемуВведение в вебпак .
Действительно, идея о том, что в вебпаке все модуль, очень удобна для нашей разработки, функция упаковки css, картинок и других файлов неотделима от всевозможных загрузчиков.
Для чего-то необходимо знать, почему это так, и с таким менталитетом давайте посмотрим на соответствующие знания о загрузчике и на то, как его развивать.

метод исследования

Я считаю, что лучший способ узнать что-то новое — это его официальная документация. Что касается загрузчика, взгляните на его официальную документацию, чтобы узнать, как разработать простейший загрузчик.
просто егоофициальная документацияОн был на английском языке, поэтому я легко перевел его, чтобы углубить свое понимание, с одной стороны. С другой стороны, он дает ссылку для других студентов.
Я думаю, вы узнаете, как разработать загрузчик после прочтения документации.

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

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

простой случай

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

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

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

Загрузчик ожидает вернуть 1-2 значения, первое — это код js, возвращаемый в виде строки или буфера после обработки. Второй — SourceMap или объект js.

Осложнения:

Когда несколько загрузчиков вызываются в цепочке, только последний загрузчик получает файл ресурсов.
Также ожидается, что только первый загрузчик вернет 1-2 значения (т.е. JavaScript и SourceMap, упомянутые выше).
Другой загрузчик получает значение, переданное предыдущим загрузчиком.

Другими словами, цепные загрузчики выполняются справа налево или снизу вверх.
Например: порядок выполнения следующего кода восходящий foo-loader==>bar-loader

module: {
  loaders: [
    {
      test: /\.js/,
      loaders: [
        'bar-loader',
        'foo-loader'
      ]
    }
  ]
}

Примечание: в настоящее время weboack будет искать только указанный вами загрузчик в папке nodemodules.

Если вашей папки нет в этом каталоге, вам нужно добавить конфигурацию в config:
То есть к node_modules обращаются по умолчанию, если вашей папки там нет, то нужно вручную добавить ее в конфигурационный файл.

    resolveLoader: {
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
    }

Советы

ps: После моей собственной практики я обнаружил, что это неправильно.Вам не нужно анализировать путь, просто напишите каталог файлов напрямую.
Вообще говоря, загрузчики будут выпущены в npm для управления.Не беспокойтесь об этой ситуации, но если вы хотите проверить себя на этапе разработки, вы столкнетесь с этой ситуацией.
Например мой рукописный myloader находится под loaders, пример такой.

     resolveLoader:{
        modules: ['node_modules','loader']
    }

Examples

Это так же просто, как обычный загрузчик

    module.exports = function(source,map){
    this.cacheable && this.cacheable()
    this.value = source
    return '/*copy@ xiaoxiangdaiyu*/'+JSON.stringify(source)
    }

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

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

Одна задача

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

Например: преобразовать строковый шаблон в html через строку запроса.
Если вы пишете загрузчик, который делает все, вы нарушаете первое требование к загрузчику.
Вы должны создать загрузчик для каждой задачи и использовать их через конвейер.

  • jade-loader: преобразовать шаблон в модуль
  • apply-loader: создает модуль и возвращает результаты с параметрами запроса.
  • html-loade: создайте модуль, который обрабатывает html и возвращает строку

2. Создать модуль молдовских слов, то есть обычный модуль

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

    require("any-template-language-loader!./xyz.atl");
    var html = anyTemplateLanguage.render("xyz");

В-третьих, попробуйте указать, можно ли кэшировать загрузчик

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

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

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

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

5. Указание зависимостей

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

    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);
    });
};

6. Разбор зависимостей

Многие языки предоставляют некоторые спецификации для объявления зависимостей, такие как @import и url(...) в css. Эти зависимости должны быть разрешены системой модулей.

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

Если язык принимает только относительные URL-адреса (например, URL-адрес (файл) в CSS всегда означает ./file), используйте ~ для обозначения зависимостей модулей.

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

7. Извлеките общедоступный код

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

8. Избегайте написания абсолютных путей

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

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

9. Используйте peerDependencies для указания зависимых библиотек

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

10. Программируемые объекты как элементы запроса

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

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

заключительные замечания

До сих пор, как разработать загрузчик веб-пакетов, я думаю, вы уже знаете, если вам не ясно, вы можете перейтиw-loaderПроверить.
Кроме того, для такого английского подонка, как я, это действительно сложно перевести. Вот несколько предложений, я надеюсь, что каждый может обсудить и учиться вместе.