шаблоны проектирования веб-пакетов
Исходный код Webpack представляет собой архитектуру плагинов, и многие его функции реализованы с помощью множества встроенных плагинов. Webpack написал для этой цели систему плагинов, называемуюTapableВ основном он предоставляет функции регистрации и вызова плагинов.
Tapable
tabpable — это плагин для публикации и подписки на события, он поддерживает как синхронный, так и асинхронный; наследуйте tabpable от класса, который нужно использовать, и используйте его в конструкторе этого классаthis.hooks
Добавьте название события.
this.hooks = {
accelerate: new SyncHook(["newSpeed"]),
break: new SyncHook(),
calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
};
подписка
Чтобы использовать функцию подписки, вам нужно сначала получить экземпляр класса, упомянутый выше, через实例对象.hooks.break.tap
Подписаться.
myCar.hooks.break.tap("WarningLampPlugin", () => warningLamp.on());
выпускать
Вызывается, когда его нужно активироватьthis.hooks.accelerate.call
инициировать подпискуaccelerate
Для всех функций прослушивателя newSpeed является входящим параметром.
setSpeed(newSpeed) {
this.hooks.accelerate.call(newSpeed);
}
Архитектура плагина webpack
Webpack определяет жизненный цикл от инициализации конфигурации до завершения сборки. На каждом этапе этого жизненного цикла определяются некоторые значения выполнения различных функций. Процесс webpack определяет спецификацию, будь то внутренний подключаемый модуль или пользовательский подключаемый модуль. in, если это следует за этой спецификацией, можно завершить построение; как упоминалось выше, webpack представляет собой подключаемую архитектуру, и webpack в основном используетCompiler
а такжеCompilation
Классы контролируют весь жизненный цикл веб-пакета и определяют процесс выполнения; все они наследуют tabpable и регистрируют события, которые каждый процесс в жизненном цикле должен запускать через tabpable. Внутри веб-пакета реализован ряд плагинов. Эти внутренние плагины являются функциональными реализациями в процессе упаковки и сборки веб-пакета. Подписка на интересующие события и вызов различных функций подписки в процессе выполнения составляют полный жизненный цикл веб-пакета.
Обзор процесса веб-пакета
Webpack сначала объединит параметры конфигурации с параметрами командной строки и параметрами по умолчанию, а также инициализирует подключаемые модули, которые будут использоваться, и параметры, необходимые для среды выполнения, такие как подключаемые модули конфигурации; после завершения инициализации будет вызван запуск компилятора. чтобы фактически начать процесс компиляции и сборки webpack, webpack Процесс сборки включает в себя этапы компиляции, создания, сборки, запечатывания и отправки.После выполнения этих этапов процесс сборки завершается.
- Зарегистрируйте соответствующий плагин в соответствии с нашей конфигурацией веб-пакета и вызовите compile.run, чтобы перейти к этапу компиляции.
- На первом этапе компиляции это
compilation
, он пропишет фабрику, соответствующую разным типам модулей, иначе потом не будет знать, как с ней обращаться. - Войти
make
этап, отentry
Начните в два шага: - Первым шагом является вызов загрузчиков для компиляции исходного кода модуля и преобразования его в стандартный код JS.
- Второй шаг — вызвать acorn для разбора JS-кода и сбора его зависимостей. Каждый модуль записывает свои собственные зависимости для формирования дерева отношений.
- последний звонок
compilation.seal
Войтиrender
Этап, в соответствии с ранее собранными зависимостями, решить, сколько файлов генерировать и каково содержимое каждого файла.
инициализация
запускать
Первый вызов webpack-cli из bin/webpack.js插件的
./bin/cli.js`, используйте yargs в cli.js для анализа параметров командной строки и объединения параметров (опций) в файле конфигурации, а затем вызовите lib/webpack.js для создания экземпляра компилятора.
создать экземпляр компилятора
Инстансация компилятора делается в lib/webpack.js.Сначала он проверит корректность параметров конфигурации, затем по переданным параметрам определит, является ли он массивом.Если это массив, несколько компиляторов будет создан, иначе будет создан компилятор, об этом расскажет компилятор, сначала он вызовет WebpackOptionsDefaulter, чтобы объединить входящие параметры и параметры по умолчанию, чтобы получить новые параметры, создать компилятор, создать плагин, который читает и записывает файл объекты и выполняет конфигурацию регистрации, и, наконец, инициализирует кучу внутренних плагинов по умолчанию, необходимых для сборки через WebpackOptionsApply.
воплощать в жизнь
После компилятора экземпляра оцените, запущены ли часы в соответствии с параметрами часов, и вызовите, запущены ли часы.compiler.watch
для мониторинга файлов сборки, в противном случае запуститеcompiler.run
для создания файла.
Скомпилировать и построить
Далее мы официально входим в процесс сборки webpack.Запись процесса сборки webpack это метод run или watch компилятора.Процесс компиляции описан ниже run,в методе run выполняются функции beforeRun и run hook сначала, а затем введите compile, и перед построением могут быть написаны плагины для обработки некоторых данных инициализации.
Объясните оба класса, прежде чем переходить к сборке
- Компилятор: Этот класс является мозговым центром вебпака, с одной стороны все данные конфигурации хранятся на этом инстансе, а с другой стороны он контролирует весь общий процесс в процессе сборки.
- Компиляция: этот класс является техническим директором веб-пакета.Все данные сборки, созданные в процессе сборки, хранятся в этом объекте, который контролирует каждую деталь процесса сборки.
compile
Сначала создайте экземпляр параметров, таких как normalModuleFactory, в run, а затем вызовитеthis.hooks.beforeCompile事件执行一些编译之前需要处理的插件,最后才执行
событие this.hooks.compile (например, в хуке компиляции будет выполнен DllReferencePlugin, и здесь будет зарегистрирован прокси-плагин);this.hooks.compile
После выполнения создайте экземпляр объекта Compilation и вызовитеthis.hooks.compilation
Сообщите заинтересованным подключаемым модулям, например о добавлении классов фабрики зависимостей в компиляцию.dependencyFactories. Фаза компиляции в основном предназначена для подготовки к входу в фазу создания, а фаза создания — для рекурсивного поиска модулей сборки от входа.
make
make — это событие, вызванное завершением инициализации компиляции. Как правило, это событие предназначено для уведомления подключаемого модуля EntryOptionPlugin, зарегистрированного в WebpackOptionsApply. В подключаемом модуле используйте параметр entry для создания зависимости с одной записью (SingleEntryDependency) или несколькими записями (MultiEntryDependency), когда несколько записей находятся в состоянии Зарегистрируйте несколько идентичных слушателей в событии make и выполните несколько записей параллельно; затем вызовитеcompilation.addEntry(context, dep, name, callback)
Официально войдите в стадию создания.
Если в addEntry ничего не делается, он вызывает метод this._addModuleChain, находит соответствующую фабричную функцию в _addModuleChain в соответствии с зависимостью и вызывает функцию создания фабричной функции для создания пустого объекта MultModule и сохраняет объект MultModule в модули компиляции Выполнить MultModule.build после середины, потому что это входной модуль, поэтому afterBuild вызывается напрямую, ничего не обрабатывая в сборке, в afterBuild судят есть ли зависимость, кончается ли конечный узел напрямую, иначе метод processModuleDependencies вызывается для поиска зависимости, так как передается запись A SingleEntryDependency, поэтому нижеследующее формально описывает сборку из SingleEntryDependency.
Упомянутая выше запись создаст SingleEntryDependency для передачи, поэтому в afterBuild, описанном выше, должна быть хотя бы одна зависимость, и будет вызван метод processModuleDependencies; processModuleDependencies ищет все ресурсы, которые необходимо загрузить в зависимости модуля, и соответствующие в соответствии с текущим модулем. class асинхронно, чтобы найти абсолютный путь к ресурсу и местоположение ресурса.Зависит от абсолютного пути всех загрузчиков, создаст соответствующий модуль и возвратит, а затем оценит, был ли загружен ресурс в соответствии с путем к ресурсу модуля в качестве ключа, если загружен, напрямую указать ссылку ресурса на загруженный модуль и вернуться, в противном случае вызвать этот метод .buildModule выполняет module.build для загрузки ресурсов, после завершения сборки получается окончательный модуль, обработанный загрузчиком , а затем afterBuild вызывается рекурсивно, и фаза make не заканчивается, пока не будут загружены все модули.
DllReferencePlugin
На этапе создания веб-пакет создаст экземпляр модуля в соответствии с созданием фабрики модулей (normalModuleFactory); после создания экземпляра модуля будет запущено событие this.hooks.module. Если плагин DllReferencePlugin зарегистрирован в конфигурации сборки, плагин DelegatedModuleFactoryPlugin будет прослушивать событие this.hooks.module. Плагин оценивает, находится ли путь модуля в this.options.content. Если он существует, создается прокси-модуль (DelegatedModule), чтобы переопределить модуль по умолчанию; DelegatedData объекта DelegatedModule хранит соответствующие данные (путь к файлу и идентификатор) в манифесте, поэтому объект DelegatedModule не будет выполняться Bulled.При создании исходного кода вам нужно только ввести соответствующий идентификатор там, где он используется.
build
Сборка упоминается выше на этапе создания, но подробно не объясняется, поскольку сборка выполняется в объекте модуля.В этом разделе отдельно рассказывается о том, как сборка загружает и выполняет загрузчик и, наконец, находит зависимости модуля и возвращает.
В сборке doBuild будет вызываться для загрузки ресурсов, а doBuild будет передавать путь к ресурсу и ресурсы подключаемого модуля для вызова метода runLoaders подключаемого модуля загрузчика-раннера для загрузки и выполнения загрузчика. После завершения выполнения будет возвращен результат, как показано на рисунке ниже.Согласно возвращенным данным, исходный код и sourceMap будут храниться в атрибуте _source модуля, в callback-функции модуля вызывается класс Parser doBuild для создания синтаксического дерева AST, а buildModule будет вызван обратно после того, как зависимости будут сгенерированы в соответствии с синтаксическим деревом AST.Метод возвращает класс компиляции.
поток обработки загрузчика-бегуна
Метод runLoaders вызывает iteratePitchingLoaders для рекурсивного поиска и выполнения загрузчика с атрибутом pitch; если загрузчиков с атрибутом pitch несколько, выполнить по очереди все загрузчики с атрибутом pitch, а после выполнения обратно выполнить все обычные загрузчики с атрибутом pitch аттрибут питч и вернуть результат.Загрузчик без аттрибута питча повторно выполняться не будет, если в лоадерах нет лоадера с атрибутом питча, то лоадер выполнится в обратном порядке, выполнение обычного лоадера завершается в методе iterateNormalLoaders, и результат будет возвращен после обработки всех загрузчиков, например, ниже приведены правила выполнения загрузчика.
Порядок выполнения загрузчика:
|- a-loader `pitch` |- b-loader `pitch` |- c-loader `pitch` |- requested module is picked up as a dependency |- c-loader normal execution |- b-loader normal execution |- a-loader normal execution
Parser
Вызовите подключаемый модуль acorn в классе Parser, чтобы создать синтаксическое дерево AST. Acorn не входит в рамки этой статьи. Если вам интересно, вы можете прочитать ее. После того, как синтаксическое дерево AST будет создано в Parser, метод walkStatements вызывается для анализа синтаксического дерева и рекурсивного поиска в соответствии с типом узла AST.Каждый узел вводит и выполняет различную логику и создает зависимости.
MiniCssExtractPlugin
Если вы используете плагин MiniCssExtractPlugin в webpack для упаковки css в файлы отдельно, он будет настроен в правилах обработки стилейMiniCssExtractPlugin.loader
, при разборе css-файла сначала будет выполняться метод питча, реализованный в загрузчике MiniCssExtractPlugin, а метод питча будет вызываться для каждого модуля css.this._compilation.createChildCompiler
Создайте childCompiler и childCompilation; элемент управления childCompiler возвращается после загрузки и сборки модуля. Модуль, встроенный в childCompilation, называется CssModule и отличается типом = 'css/mini-extract'.
Кроме того, MiniCssExtractPlugin будет различать, основан ли стиль CSS на типе модуля type='css/mini-extract', и обрабатывать его отдельно, в то время как другие шаблоны js не распознают модуль type='css/mini-extract'. тип и будет отфильтрован, так что будет достигнуто разделение стилей.
резюме
После того, как все ресурсные булиды будут завершены, фаза создания веб-пакета завершена.Фаза создания является наиболее трудоемкой, поскольку будут выполняться операции потока ввода-вывода, такие как разбор пути к файлу и чтение файла, после завершения сборки все скомпилированные модули В массиве модулей компиляции все модули в модулях будут образовывать граф.
seal
После того, как все модули и их зависимости собраны, webpack будет слушать
seal
Событие вызывает каждый плагин для инкапсуляции результата после построения.Необходимо разобрать каждый модуль и чанк один за другим, сгенерировать скомпилированный исходный код, слить, разбить и сгенерировать хеш. В то же время это ключевое звено в нашей оптимизации кода и добавлении функций во время разработки.
сработает первым в печатиoptimizeDependencies
Для оптимизации зависимостей используются некоторые типы событий (например, в этом месте выполняется встряска дерева).Всем следует обратить внимание на то, что в плагинах оптимизации не может быть асинхронности, после завершения оптимизации создавать чанки по модуль записи.Если это одна запись, только один фрагмент, несколько записей имеют несколько фрагментов, после этого этапа модуль асинхронного импорта, существующий в модуле, будет искаться в соответствии с рекурсивным анализом фрагмента, и фрагмент будет создан с модулем в качестве узла. Запускается после выполнения всех чанковoptimizeModules
а такжеoptimizeChunks
Подождите, пока события оптимизации уведомят заинтересованные подключаемые модули для обработки оптимизации. После завершения всех оптимизаций сгенерируйте хеш для чанка и затем вызовитеcreateChunkAssets
для создания исходных объектов из шаблонов; используйтеsummarizeDependencies
Кэшируйте все проанализированные файлы и, наконец, вызовите подключаемый модуль для создания soureMap и окончательных данных.На следующем рисунке показана блок-схема этапа уплотнения.
генерировать активы
В процессе упаковки webpack вызовет Compilation в
createChunkAssets
способ генерации упакованного кода. Процесс createChunkAssets выглядит следующим образом.
Из приведенного выше рисунка видно, что разные шаблоны обработки чанка отличаются.По входу чанка судят, следует ли выбрать mainTemplate (шаблон упаковки входного файла) или chunkTemplate (шаблон упаковки js с асинхронной загрузкой); template, объект манифеста генерируется в соответствии с template.getRenderManifest шаблона, метод рендеринга в этом объекте является записью упаковки чанка; единственная разница между mainTemplate и chunkTemplate заключается в том, что mainTemplate имеет больше кода начальной загрузки, выполняемого wepback. При вызове рендера будет вызван метод template.renderChunkModules, который создаст контейнер ConcatSource для хранения исходного кода чанка, затем этот метод пройдёт по модулю текущего чанка и выполнит moduleTemplate.render для получения исходного кода чанка. каждый модуль; в moduleTemplate После получения исходного кода в .render подключаемый модуль будет активирован для инкапсуляции формата кода, требуемого wepack; когда все модули сгенерированы, они будут помещены в ConcatSource и возвращены; и выходной файл имя чанка будет сохранено в активах компиляции в качестве ключа.
печать продукта
Различные оптимизации и окончательные коды, сгенерированные на этапе уплотнения, будут храниться в свойстве активов компиляции. Активы — это объект, в котором хранится выходной объект с окончательным выходным именем в качестве ключа. Каждый выходной файл соответствует выходному объекту, как показано на следующий рисунок.
emit
Последний шаг, webpack вызывает компилятор вemitAssets()
, файл асинхронно выводится по соответствующему пути в соответствии с элементом конфигурации в выводе, так что весь процесс упаковки веб-пакета завершается. Следует отметить, что если вы хотите обработать результат, вам необходимоemit
Расширение пользовательских плагинов после срабатывания.
watch
Когда настроен часы, WebPack-dev-Mardware заменяет оригинальную выходу SEADFILESSYSTEM of WebPack с экземпляром MemoryFileSystem (Plugin Memory-FS).
монитор
При выполнении наблюдения создается экземпляр объекта наблюдения, а мониторинг, сборка и упаковка управляются экземпляром наблюдения; время уведомления об изменении задержки (по умолчанию 200) устанавливается в конструкторе наблюдения, а затем вызывается метод _go; Первая сборка веб-пакета и последующие файлы Изменения и перестроения — это все методы _execute_go, а this.compiler.compile вызывается в методе __go для запуска компиляции. После завершения сборки веб-пакета будет запущен метод _done, метод this.watch будет вызван в методе _done, а папки и каталоги, которые необходимо отслеживать, будут переданы в компиляцию.fileDependencies и компиляция.contextDependencies; this.compiler Метод .watchFileSystem.watch будет вызываться в часах. Официально начинаем создавать монитор.
Watchpack
В this.compiler.watchFileSystem.watch экземпляр Watchpack будет создаваться каждый раз заново, а агрегированные события и триггеры будут отслеживаться после завершения создания.this.watcher.watch(files.concat(missing), dirs.concat(missing), startTime)
метод и закройте старый экземпляр Watchpack; в часах будет вызываться WatcherManager для создания объекта DirectoryWatcher для папки, созданной в каталоге, где находится каждый файл, а в конструкторе часов объекта DirectoryWatcher будет вызываться плагин chokidar для отслеживать папку и привязывать куча вызывает событие и возвращает наблюдателя; Watchpack зарегистрирует прослушиватель событий изменения для каждого наблюдателя, и событие изменения будет запускаться при каждом изменении файла.
Установите таймер для задержки запуска события изменения после изменения файла, отслеживаемого плагином Watchpack, чтобы решить проблему частого запуска во время нескольких быстрых изменений.
вызывать
Когда файл изменяется, агрегированное событие прослушивания в NodeWatchFileStstem получает время последней модификации каждого прослушиваемого файла в соответствии с наблюдателем, сохраняет объект в this.compiler.fileTimestamps и запускает метод _go для сборки.
При компиляции this.fileTimestamps будет присвоен объекту компиляции. Начиная с записи на этапе make, все модули будут собираться рекурсивно. В отличие от первой сборки, методcompile.addModule сначала обращается к кешу для извлечения модуль в соответствии с путем ресурса, а затем возьмите модуль .buildTimestamp (время последней модификации модуля) сравнивается с временем последней модификации файла в fileTimestamps.Если время модификации файла больше, чем buildTimestamp, модуль будет быть перестроен, иначе зависимости модуля будут перебираться рекурсивно.
В процессе сборки веб-пакета синтаксический анализ файлов и построение модулей отнимают много времени, поэтому веб-пакет кэширует абсолютный путь к файлам и модулям во время процесса сборки и манипулирует только измененными модулями во время перестроения, что может значительно улучшить процесс перестроения. вебпак .
Суммировать
Когда я впервые начал читать исходный код веб-пакета, мое сердце бешено колотилось, в MMMP было бесчисленное количество имен событий, бесконечные внутренние плагины и переносы между различными событиями;