Что такое вебпак? Что может вебпак? Как использовать вебпак? Слишком много вводных туториалов.Я буду много искать, и я не буду говорить больше.Кроме того,официальная документация webpack должна быть эталоном индустрии документации.Продвинутый уровень уровня продукта в среде очень подробный и легко понять, поэтому я не буду вдаваться в подробности здесь, бросьте одинссылка на документацию веб-пакета, вы можете играть в нее в соответствии с учебником в первую очередь.
Начав играться с webpack или имея некоторое представление о webpack, здесь мы сосредоточимся на более интересных плагинах webpack, которые помогают более гибко использовать инструмент webpack в проекте. Поняв механизм плагина, вы не будете сбиты с толку, когда столкнетесь с кучей конфигураций веб-пакетов.
Во-первых, нужно понять одну интересную вещь: механизм плагинов webpack — это скелет всего инструмента webpack, и сам webpack строится на основе этого механизма плагинов.
Это кажется неудобным, это должно исходить от веб-пакетаисходный кодКонкретная реализация веб-пакета может быть четко объяснена.На данный момент можно понять, что ядром веб-пакета является компилятор (компилятор), и этот компилятор также предоставляется в виде подключаемого модуля к подключаемой платформе веб-пакета. .
плагин веб-пакета
Во-первых, давайте просто и ясно поймем, что такое плагин веб-пакета, как описано в следующем коде:some-webpack-plugin
Это простой плагин для веб-пакетов, который фокусируется на конкретной задаче в процессе компиляции веб-пакета.
const webpack = require('webpack');
// 假设有这么一个 webpack plugin
const SomewebpackPlugin = require('some-webpack-plugin');
webpack({
// ...
plugins: [
new SomewebpackPlugin({/* some plugin options */})
]
// ...
});
Так что же можно назвать плагином веб-пакета? Полный плагин веб-пакета должен соответствовать следующим правилам и характеристикам:
- является независимым модулем.
- Внешнее воздействие функционального модуля JS.
- Инъекция определена на прототипе функции
compiler
объектapply
метод. -
apply
Функция должна иметь обработчик событий веб-пакета, смонтированный через объект компилятора. Текущий скомпилированный объект компиляции можно получить в обратном вызове обработчика. Если это плагин асинхронной компиляции, можно получить обратный вызов обратного вызова. - Завершите процесс пользовательской подкомпиляции и обработайте внутренние данные объекта компиляции.
- Если плагин скомпилирован асинхронно, обратный вызов будет выполнен после завершения обработки данных.
Это описывает базовую форму плагина веб-пакета, и разница между каждым плагином почти только в自定义子编译流程
На этом этапе вы можете глубоко понять конкретную форму плагина веб-пакета через код:
// 1、some-webpack-plugin.js 文件(独立模块)
// 2、模块对外暴露的 js 函数
function SomewebpackPlugin(pluginOpions) {
this.options = pluginOptions;
}
// 3、原型定义一个 apply 函数,并注入了 compiler 对象
SomewebpackPlugin.prototype.apply = function (compiler) {
// 4、挂载 webpack 事件钩子(这里挂载的是 emit 事件)
compiler.plugin('emit', function (compilation, callback) {
// ... 内部进行自定义的编译操作
// 5、操作 compilation 对象的内部数据
console.log(compilation);
// 6、执行 callback 回调
callback();
});
};
// 暴露 js 函数
module.exports = SomewebpackPlugin;
компилятор и объект компиляции
Благодаря предварительному пониманию плагина webpack мы заметили, что в плагине Webpcak есть два объекта, один объект компилятора, а другой объект компиляции.На первый взгляд, эти два объекта нужно спутать.Компилятор и объекты компиляции Два основных объекта веб-пакета являются ключом к расширению функциональности веб-пакета. Чтобы облегчить понимание механизма подключаемого модуля веб-пакета в будущем, давайте сначала сосредоточимся на этих двух объектах.
объект компилятора
Объект компилятора — это объект компилятора веб-пакета. Как упоминалось ранее, ядром веб-пакета является компилятор. Объект компилятора будет инициализирован один раз при запуске веб-пакета. Объект компилятора содержит все конфигурации, которые могут быть настроены веб-пакетом, такие как конфигурация загрузчика, конфигурации плагина, конфигурации входа и других исходных конфигураций веб-пакета и т. д., в процессе пользовательской подкомпиляции в плагине веб-пакета мы обязательно будем использовать соответствующую информацию о конфигурации в объекте компилятора, мы можем передать компилятору Объект получает всю информацию об основной среде веб-пакета.
объект компиляции
Прежде всего, нам нужно понять, что такое скомпилированные ресурсы.Компилированные ресурсы представляют собой статическую карту управления ресурсами, сгенерированную вебпаком через конфигурацию (все хранится в памяти), а упакованный файл вебпака описывается в виде ключ-значение. Скомпилированные ресурсы представляют собой эту карту, состоящую из пар "ключ-значение". Скомпилированные ресурсы должны быть сгенерированы объектом компиляции.
Экземпляр компиляции наследуется от компилятора, а объект компиляции представляет собой единую версию процесса сборки и генерации скомпилированных ресурсов веб-пакета. При запуске промежуточного программного обеспечения среды разработки webpack каждый раз, когда обнаруживается изменение файла, будет создаваться новая компиляция, что приводит к новому набору скомпилированных ресурсов и новому объекту компиляции. Объект компиляции содержит当前的模块资源
,编译生成资源
,变化的文件
,так же как被跟踪依赖的状态信息
. Скомпилированный объект также предоставляет ряд обратных вызовов ключевых точек, которые подключаемый модуль может выбрать для использования при выполнении пользовательской обработки.
Видно, что если разработчику необходимо выполнить пользовательскую компиляцию через подключаемый модуль, если это связано с изменением скомпилированного ресурсного продукта, объект компиляции должен быть неотделим.
Если вам нужно больше узнать о компиляторе и объектах компиляции, вы можете передатьconsole.log(compilation)
Способ просмотра содержимого содержащихся объектов, но если вы хотите более глубоко понять слова, просмотрите исходный код — это очень хороший способ, вы получите более глубокое понимание веб-пакета.
Механизм плагина webpack
Webpack предоставляет гибкие и мощные пользовательские функции API в виде плагинов. Используя плагины, мы можем добавить функциональность в webpack. Кроме того, webpack предоставляет хуки жизненного цикла для регистрации плагинов. В каждой точке жизненного цикла webpack запускает все зарегистрированные плагины и предоставляет текущую информацию о статусе компиляции webpack.
Как пользователь и разработчик веб-пакета, если вы хотите поиграть с веб-пакетом, очень необходимо настроить некоторые из ваших собственных подключаемых модулей веб-пакета, и если вы хотите написать более полный подключаемый модуль веб-пакета, вам нужно иметь более глубокие знания. понимание механизма webpack.Plugin и понимания того, как работает весь механизм плагинов webpack. Механизм плагинов webpack обеспечивает большую гибкость платформы webpack, и этот механизм плагинов нельзя проследить до библиотеки под названием Tapable.
Tapable и Tapable экземпляры
Архитектура плагинов webpack в основном основана наTapableРеализовано, Tapable — это внутренняя библиотека команды проекта webpack, которая в основном абстрагирует набор подключаемых механизмов. Некоторые экземпляры Tapable в исходном коде веб-пакета наследуют или смешивают класс Tapable. Tapable позволяет нам добавлять и применять плагины к нашим модулям JavaScript. Он может быть унаследован или смешан с другими модулями. Он похож на класс NodeJS EventEmitter и фокусируется на запуске и действии пользовательских событий. В дополнение к этому, Tapable позволяет вам получить доступ к производителю события через аргументы функции обратного вызова.
Объекты экземпляра Tapable имеют четыре набора функций-членов:
-
plugin(name<string>, handler<function>)
- Этот метод позволяет зарегистрировать пользовательский плагин для событий экземпляра Tapable. Эта операция аналогична операции EventEmitter.on()
,注册一个处理函数
->监听器到某个信号
->事件发生时执行
(Плагины, определяемые разработчиком, должны часто использовать этот метод для настройки функции обработчика перехватчиков событий, чтобы они могли быть отправлены основным процессом компиляции.). -
apply(...pluginInstances<AnyPlugin|function>[])
— AnyPlugin — это подкласс AbstractPlugin, либо класс с методом apply (или, в редких случаях, объект), либо просто функция с регистрационным кодом. Этот метод просто применяет определение подключаемого модуля, поэтому фактический прослушиватель событий будет зарегистрирован в реестре экземпляра Tapable. -
applyPlugins*(name<string>, ...)
- Это набор функций, с помощью которых экземпляр Tapable может применяться ко всем плагинам под указанным хэшем. Эти методы работают аналогично EventEmitter.emit()
, вы можете использовать разные стратегии для управления выпуском событий для разных вариантов использования (Во внутреннем механизме реализации webpack этот метод часто используется в процессе компиляции основного процесса для создания настраиваемых подключаемых модулей, настраиваемых перехватчиков событий внешних подключаемых модулей.). -
mixin(pt<Object>)
- Простой способ расширить прототип Tapable гибридным способом, а не наследовать.
TapableREADMEТакже подробно описано в , стоит отметить, что эта группаapplyPlugins*
метод,*
Регистрации событий, представляющие различные ситуации, этот наборapplyPlugins*
Методы можно увидеть повсюду в исходном коде веб-пакета, они также включают порядок выполнения плагинов веб-пакета, разныеapplyPlugins*
Соответствует следующим различным ситуациям:
- Плагин синхронного последовательного выполнения -
applyPlugins()
- Выполнять плагины параллельно -
applyPluginsParallel()
- Плагины выполняются один за другим, и каждый плагин получает возвращаемое значение (водопад) предыдущего плагина —
applyPluginsWaterfall()
- Асинхронно выполнить плагин -
applyPluginsAsync()
- Защищенный режим завершает выполнение плагина: как только плагин возвращается
非 undefined
, завершит запущенный процесс и вернет возвращаемое значение этого плагина. Это похоже на EventEmitteronce()
, но они совсем другие -applyPluginsBailResult()
Многие объекты в webpack расширяют класс Tapable, открываяplugin
метод. можно использовать плагиныplugin
метод для внедрения пользовательских шагов сборки. В различных плагинах веб-пакета вы можете увидетьcompiler.plugin
а такжеcompilation.plugin
используется часто. По сути, каждый вызов плагина связан с обратным вызовом в процессе сборки для запуска определенного шага. Каждый плагин будет установлен один раз при запуске webpack, webpack
вызвав плагинapply
для их установки и передать ссылку на объект компилятора веб-пакета. Тогда вы можете позвонитьcompiler.plugin
для доступа к компиляции ресурсов и их отдельных шагов сборки.
Вот пример плагина webpack:
// MyPlugin.js
function MyPlugin(options) {
// Configure your plugin with options...
}
MyPlugin.prototype.apply = function (compiler) {
compiler.plugin('compile', function (params) {
console.log('The compiler is starting to compile...');
});
compiler.plugin('compilation', function (compilation) {
console.log('The compiler is starting a new compilation...');
compilation.plugin('optimize', function () {
console.log('The compilation is starting to optimize files...');
});
});
// 异步的事件钩子
compiler.plugin('emit', function (compilation, callback) {
console.log('The compilation is going to emit files...');
callback();
});
};
module.exports = MyPlugin;
Прочитав исходный код или документацию плагина webpack, можно увидеть, что компилятор и объекты компиляции являются экземплярами Tapable.Для разработчиков плагина webpack очень важно знать, какие экземпляры Tapable находятся в исходном коде webpack. . Эти примеры дают различныехук событий, чтобы разработчики могли прикреплять собственные плагины.
Note:
Читая исходный код веб-пакета, вы можете найти интересный дизайн.Ядром веб-пакета является объект компилятора веб-пакета, а сам объект компилятора является экземпляром Tapable. Объект компилятора отвечает за компиляцию объекта конфигурации веб-пакета и возврат экземпляра компиляции. Когда экземпляр Compilation запускается, он создает необходимый пакет (также известный как результат компиляции), что является фантастическим дизайном 👍.
работающий процесс webpack
Здесь нам нужно иметь глубокое понимание всего рабочего процесса веб-пакета.При написании подключаемого модуля веб-пакета нам нужно выполнять соответствующую обработку в нужное время, и все перехватчики событий, предоставляемые веб-пакетом, основаны на жизни цикл вебпака. Ниже приведена схема запущенного процесса webpack (мелкозернистый слишком сложен, webpack больше всего критикуется из-за его сложности, но и самый привлекательный еще и из-за своей сложности)
Изображение взято с Taobao FED:Таобао Fed.org/blog/2016/0…
Note:
Я рекомендую блог Taobao FED, который проясняет общий процесс веб-пакета, подробно объясняет базовую архитектуру веб-пакета и подробно анализирует компилятор и объекты компиляции.
Щелкните для просмотра увеличенного изображения, рекомендуется сохранить локально
Перехватчики событий, связанные с плагинами webpack
Исходя из вышеизложенного, процесс пользовательской подкомпиляции в плагине веб-пакета должен взаимодействовать с основным процессом компиляции веб-пакета.Как мы можем гарантировать, что логика компиляции, определенная в нашем плагине, может работать точно в нужное время?
На самом деле, мы узнали о двух важных объектах webpack ранее, объекты компилятора и компиляции играют здесь важную роль.Мы также узнали, что эти два объекта являются экземплярами Tapable.Webpack использует унаследованные методы экземпляров Tapable, соответственно. обработчики событий регистрируются как в объекте компиляции, так и в объекте компиляции, что позволяет разработчикам вставлять свою собственную логику обработки в любой процесс компиляции веб-пакета.
Подход Webpack заключается в использовании экземпляров Tapable.applyPlugins*
метод для предварительной установки этих перехватчиков событий. Конечно, веб-пакет также определяет некоторые внутренние или внешние перехватчики событий в некоторых других объектах экземпляра Tapable. Здесь мы в основном понимаем, какие события разделяют объект компилятора и объект компиляции, связанный с перехватчиком плагина.
ловушка событий компилятора
Чтобы позволить разработчикам легко писать плагины для веб-пакетов, официальный также предоставляет компилятору объектПерехватчики событий.
Здесь мы сосредоточимся на некоторых обработчиках событий, которые мы можем часто использовать в процессе написания плагинов.
хук событий | Время запуска | получить контент | Типы |
---|---|---|---|
entry-option | инициализировать параметры | - | Синхронизировать |
run | начать компиляцию | compiler | асинхронный |
compile | Фактическая компиляция начинается до создания объекта компиляции. | параметр компиляции | Синхронизировать |
compilation | После того, как объект компиляции сгенерирован, вы можете управлять этим объектом. | compilation | Синхронизировать |
make | Рекурсивно анализировать зависимости от записи, готовой к сборке каждого модуля | compilation | параллельно |
after-compile | Процесс сборки компиляции завершается | compliation | асинхронный |
emit | Перед записью содержимого активов в памяти в папку на диске | compilation | асинхронный |
after-emit | После записи содержимого активов в памяти в папку на диске | compilation | асинхронный |
done | Завершить весь процесс компиляции | stats | Синхронизировать |
failed | когда компиляция не удалась | error | Синхронизировать |
Как объект компилятора связывает обработчики событий? Принцип Tapable был представлен ранее, потому что сам webpack передавал различные ключевые точки в объекте компилятора, унаследованном от Tapable.applyPlugins*()
Метод регистрирует хук события. Разработчику нужно только привязать событие. Компилятор выдаст событие, связанное разработчиком, в нужное время. Компилятор связывает хук события следующим образом:
// 前提是先要拿到 compiler 对象,apply 方法的回调中就能拿到,这里假设能拿到 compiler 对象
compiler.plugin('emit', function (compilation, callback) {
// 可以得到 compilation 对象,如果是异步的事件钩子,能拿到 callback 回调。
// 做一些异步的事情
setTimeout(function () {
console.log("Done with async work...");
callback();
}, 1000);
});
Хорошо видно, что обработчик событий компилятора основан на всем процессе компиляции, а гранулярность относительно грубая.Обычно, когда требуется мелкозернистая обработка результата компиляции, обработчик событий, определенный для объекта компиляции, незаменимый.
ловушка события компиляции
Объект компиляции был представлен ранее. Объект компиляции представляет собой процесс сборки и генерации скомпилированных ресурсов для одной версии веб-пакета. Объект компиляции имеет доступ ко всем модулям и их зависимостям (в основном циклическим зависимостям). На этапе компиляции модуль加载
,封闭
,优化
,分块
,哈希
а также重建
И так далее, это будет основное время жизни любой операции при компиляции.
Чтобы иметь дело с логикой на уровне модуля, очень необходимо понимать обработчики событий компиляции.Конечно, многие плагины веб-пакетов ловко используют эти перехватчики событий для выполнения большого количества невероятной работы. Каковы конкретные перехватчики событий компиляции? Давайте выберем некоторые из наиболее распространенных и важных для объяснения.официальная документация
normal-module-loader
Обыкновенный загрузчик модулей, который фактически загружает функции всех модулей в графе модулей (структура данных для всех модулей после анализа) один за другим.
Модули обычно называют модульными модулями, такими как AMD, CMD и т. д.
// 前提是能先取到 complation 对象(可以通过 compiler 事件钩子取到)
compilation.plugin('normal-module-loader', function (loaderContext, module) {
// 这里是所有模块被加载的地方
// 一个接一个,此时还没有依赖被创建,想拿到啥模块直接通过 module 取
});
seal
Начался закрытый компилятор, на этот раз он больше не получает никаких модулей и скомпилирован в закрытую фазу (см. блок-схему веб-пакета).
compilation.plugin('seal', function () {
// 你已经不能再接收到任何模块
// 回调没有参数
});
optimize
Оптимизируйте компиляцию, этот обработчик событий особенно важен, многие плагины будут основаны на этом обработчике событий, что указывает на то, что WebPack вступил в фазу оптимизации.
compilation.plugin('optimize', function () {
// webpack 已经进入优化阶段
// 回调没有参数
});
optimize-modules
оптимизация модуля
compilation.plugin('optimize-modules', function (modules) {
// 等待处理的模块数组
console.log(modules);
});
optimize-chunks
Это важный хук событий, фаза оптимизации чанка webpack. Вы можете получить зависимости модулей, загрузчики и т. д. и обработать их соответствующим образом.
compilation.plugin('optimize-chunks', function (chunks) {
//这里一般只有一个 chunk,除非你在配置中指定了多个入口
chunks.forEach(function (chunk) {
// chunk 含有模块的循环引用
chunk.modules.forEach(function (module) {
console.log(module);
// module.loaders, module.rawRequest, module.dependencies 等。
});
});
});
additional-assets
Это асинхронный обработчик событий. На этом этапе для объекта компиляции могут быть созданы дополнительные ресурсы, что означает, что вы можете асинхронно добавить некоторые пользовательские ресурсы в конечный продукт. Вы можете посмотреть на добавление ресурса svg к активам. Пример:
compiler.plugin('compilation', function (compilation) {
compilation.plugin('additional-assets', function (callback) {
download('https://some.host/some/path/some.svg', function (resp) {
if (resp.status === 200) {
compilation.assets['webpack-version.svg'] = toAsset(resp);
callback();
}
else {
callback(new Error('[webpack-example-plugin] Unable to download the image'));
}
})
});
});
optimize-chunk-assets
Оптимизируйте обработчик событий активов чанка. На этом этапе оптимизации можно изменить активы чанка, чтобы повторно изменить содержимое ресурса. Активы хранятся в this.assets, но не все они являются активами фрагментов. У чанка есть свойство files, которое идентифицирует все файлы, созданные этим чанком. Дополнительные активы хранятся в this.additionalChunkAssets.
Вот пример добавления заголовка комментария к каждому фрагменту:
compilation.plugin("optimize-chunk-assets", function (chunks, callback) {
chunks.forEach(function (chunk) {
chunk.files.forEach(function (file) {
compilation.assets[file] = '/**some comments info**/\n' + compilation.assets[file];
});
});
callback();
});
optimize-assets
Оптимизируйте асинхронные перехватчики событий всех ассетов.На этом этапе вы можете получать все ассеты напрямую через this.assets и выполнять пользовательские операции. аналогичныйoptimize-chunk-assetsНо этот обратный вызов события не может зацепить куски.
compilation.plugin("optimize-assets", function (asstes, callback) {
console.log(assets);
// 可以直接操作 assets 里面的 file
callback();
});
Объект компиляции имеет некоторые другие обработчики событий, которые можно прочитать напрямую.официальная документация по веб-пакету, документация не очень подробная, лучше всего попробовать эти обработчики событий и поместить их в кодconsole.log()
Запустите прогон и посмотрите конкретную реализацию и результаты, чтобы углубить свое понимание.
напиши в конце
Чтобы понять механику плагинов webpack, вам нужно понять несколько вещей:
- форма плагина webpack
- работающий процесс webpack
- Tapable & Tapable Instances и Tapable Instances Methods
- объекты компилятора и компиляции и обработчики событий
Остальное — выяснить ваши потребности и написать соответствующий плагин. Встроенные подключаемые модули веб-пакета и исходный код многих отличных подключаемых модулей веб-пакетов с открытым исходным кодом являются хорошими примерами обучения.
использованная литература
Эта статья является оригинальной статьей, и точки знаний будут часто обновляться, а некоторые ошибки будут исправлены. Поэтому, пожалуйста, сохраняйте исходный источник для перепечатки, чтобы облегчить отслеживание, избежать введения в заблуждение старых неправильных знаний и получить лучший опыт чтения .
При воспроизведении указать источник:Перейти Miaojiang.com/article/I ha…