предисловие
external
Вы должны быть знакомы с атрибутами в инструменте сборки . При оптимизации требований к объему строительного продукта могут быть введены CDN
для замены некоторые основные модули или наборы инструментов, такие как React
, Vue
, lodash
и так далее.
В последнее время мне нечего делать. В свободное время я изучил внутреннюю реализацию Vite
и Rollup
. Я воспользовался этой возможностью, чтобы изучить, как следующий инструмент сборки обрабатывает external
этот тип внешней ссылки, и external
сделать некоторые расширения возможностей .
как разобратьExternal
Поскольку external
способность в основном отражается на процессе строительства, начнем со сроков строительства. Когда строительство Vite
зависит от Rollup
способности , то есть в конструкции external
в основном отражаются свойства . Это также видно Rollup
из параметров Vite
, переданных в .Rollup
const userExternal = options.rollupOptions?.external
let external = userExternal
const rollupOptions: RollupOptions = {
context: 'globalThis',
preserveEntrySignatures: ssr
? 'allow-extension'
: libOptions
? 'strict'
: false,
...options.rollupOptions,
input,
plugins,
external,
onwarn(warning, warn) {
onRollupWarning(warning, warn, config)
}
}
const {
rollup } = await import('rollup')
const bundle = await rollup(rollupOptions)
Так Rollup
как же он обрабатывает external
информацию о пути?
На этапе подготовки конструкции мы видим, что есть операция инициализации:
function normalizeInputOptions(config) {
const options = {
// ...
external: getIdMatcher(config.external)
};
return {
options, unsetOptions };
}
В функции getIdMatcher
есть config.external
процесс инициализации
const getIdMatcher = (option) => {
if (option === true) {
return () => true;
}
if (typeof option === 'function') {
return (id, ...args) => (!id.startsWith('\0') && option(id, ...args)) || false;
}
if (option) {
const ids = new Set();
const matchers = [];
for (const value of ensureArray(option)) {
if (value instanceof RegExp) {
matchers.push(value);
}
else {
ids.add(value);
}
}
return (id, ..._args) => ids.has(id) || matchers.some(matcher => matcher.test(id));
}
return () => false;
};
Проще говоря, когда пользователь vite.config.*
настраивает в модуле конфигурации build.rollupOptions.external
, он rollup
собирает настроенный путь, чтобы определить, является ли проанализированный путь внешней ссылкой.
options.external = (id, ..._args) => ids.has(id) || matchers.some(matcher => matcher.test(id));
Здесь всем должно быть любопытно, когда произошло обнаружение?
Время обнаружения свертки
С этим любопытством давайте продолжим смотреть вниз.После Rollup
инициализации информации о конфигурации граф зависимостей модуля будет сгенерирован через запись
async generateModuleGraph() {
(
{
entryModules: this.entryModules, implicitEntryModules: this.implicitEntryModules } =
await this.moduleLoader.addEntryModules(normalizeEntryModules(this.options.input), true)
);
}
async build() {
timeStart('generate module graph', 2);
await this.generateModuleGraph();
// ...
}
Каждый должен быть знаком с графом зависимостей модулей, проще говоря, для определения взаимосвязи между модулями. Мы не будем объяснять процесс генерации графа зависимостей модулей по одному по исходному коду, так скучно!
Мы можем успокоиться и подумать, если мы собираемся строить граф зависимостей модулей проекта, что нам делать?
入口
В первую очередь нам обязательно нужно проанализировать из конфигурации (по умолчанию index.html), мы можем проанализировать index.html
, от каких модулей зависит модуль, возможно, некоторые студенты не понимают слова зависимый , поэтому давайте использовать более популярные слова «[мы можем проанализировать, какие index.html
модули импортированы , написаны скрипты и связаны модулем]». После анализа index.html
модуля мы можем проанализировать модули, от которых он зависит.Прежде чем анализировать зависимые модули, мы должны сначала выяснить, где находятся зависимые модули.Ведь зависимые модули, как правило, являются файловыми ресурсами. Найдя расположение зависимого модуля, легко подумать, что он должен прочитать информацию о зависимом модуле, поэтому учащиеся, которые знакомы с ним, могут сразу node
начать fs
! , разве это не похоже index.html
на модуль? Сделайте тот же анализ, а затем проанализируйте зависимости. Внимательные студенты могут обнаружить, что на самом деле это процесс рекурсивного извлечения зависимых модулей, который кажется несложным.
Великолепно! Rollup
Это действительно то, как это обрабатывается, но когда процесс будет обработан, будут введены плагины для помощи в анализе.
Тогда некоторые студенты могут сказать: Кажется, это отступление, эта статья не для анализа external
, как же мы можем говорить о процессе опоры на построение!
Не волнуйтесь, горячий тофу нельзя есть в спешке. Приведенный выше контент предназначен для того, чтобы у всех Rollup
было общее представление о процессе выполнения, и он будет связан с ним в будущем.
Как упоминалось ранее, «найти расположение зависимого модуля» при Rollup
обработке пути зависимого модуля будет определяться, является ли текущий путь модуля external
.
this.resolveId =
async (source, importer, customOptions, isEntry, skip = null) => {
return this.getResolvedIdWithDefaults(
this.getNormalizedResolvedIdWithoutDefaults(
this.options.external(source, importer, false)
? false
: await resolveId(source, importer, this.options.preserveSymlinks, this.pluginDriver, this.resolveId, skip, customOptions, typeof isEntry === 'boolean' ? isEntry : !importer),
importer,
source
)
);
};
Из исходного кода можно узнать, что когда путь определен как внешняя ссылка, он не будет выполнен await resolveId(...)
, а значит, внешняя ссылка Rollup
не будет обработана.
external
Цели расширения и идеи для
Хорошо, давайте сначала остановимся здесь. Давайте сначала определим external
цель расширения.
- Поддержка ссылок
ESM
на продукты и автоматический импорт ссылок.UMD
CDN
- Объяснение:
СопровождаетсяESM
спецификацией поддержки браузера старшей версии. Крупные разработчики пакетов также осознаютESM
важность , а также предоставляютESM
стандартизированные продукты, и в то же время есть такиеCDN
производители , как [skypack] (Skypack: поиск миллионов пакетов JavaScript с открытым исходным кодом), которыеESM
поддерживают ссылки на продукты. ПоэтомуESM
крайне важно, чтобы плагины поддерживали внешние ссылки.
- Объяснение:
- Поддержка
Vite
версии 2.0 и выше.- Объяснение:
Вы можете задаться вопросом, почему2.0
предыдущая версия не поддерживается, потому что2.0
это фактическиVite
первая стабильная версия . Из версии NPM видно2.0
, что предыдущая версия в основном не имеет аудитории, и тратить время на совместимость не имеет особого смысла. При этом при подаче заявки на отличные плагины в библиотеке awesome-viteThe plugin/tool is working with Vite 2.x and onward
также является официальным требованием: то есть поддержкаVite
версии 2.x и выше.
- Объяснение:
Хорошо, теперь мы определили цель. Потом разберем, как это реализовать.
对 ESM 和 UMD 产物链接做支持且自动引入 CDN 链接
достижение целей
-
ESM
Поддержка ссылок на продукты Canonical:Поскольку браузеры более высоких версий поддерживают
ESM
ссылки, нам нужно только заменить исходное имя модуля пакета ссылкамиCDN
. Это какimport react from 'react'
заменить наimport react from 'https://cdn.skypack.dev/react'
. Согласно тому, что мы сказали ранее, когда мы вводимreact
модуль, то на этапе построенияRollup
мы найдем,react
где находится модуль, то есть найдемreact
конкретный путь модуля. Тогда нам нужно только сказатьRollup
,react
что конкретного путиhttps://cdn.skypack.dev/react
недостаточно. Это действительно то, как это обрабатывается, но здесь необходимо упомянуть, чтоRollup
после получения путиexternal
элемент конфигурации будет использоваться для определения того, является ли полученная ссылка внешней ссылкой.Если это не внешняя ссылка, она будет быть далее проанализированы.Продолжить анализ в соответствии с тем, что мы сказали ранееСамое главное, чтобы загрузить ресурсы.Мы ввелиCDN
это, чтобы уменьшить размер пакета.Если мыRollup
позволим . Поэтому мы должны сказать вам , что это внешняя ссылка, и вы должны прекратить ее парсинг.react
https://cdn.skypack.dev/react
Rollup
https://cdn.skypack.dev/react
-
UMD
Поддержка ссылок на продукты Canonical:В первые
JQuery
дни популярности мы обычно используемCDN
способ внедренияJQuery
, а затемCDN
, после выполнения импортированного продукта, определенное свойство будет внедряться глобально (window
в ), и разработчики могут получитьJQuery
возможность через это конкретное свойство. У вас может быть идея, в среде браузера нам нужно только помочь получить атрибуты, введенные вJQuery
, а затем изменить оператор импорта, то есть заменить на . Это также возможно, но требует специальной обработки для различных методов импорта. Здесь мы можем реализовать это проще, с помощью виртуальных модулей . Некоторые студенты могут быть немного незнакомы с определением , на самом деле, как следует из названия, это ложный модуль, модуль, которого нет на диске. Затем мы можем экспортировать содержимое, которое мы определили в , то есть преобразовать вwindow
import jQuery from 'jquery'
const jQuery = window['jQuery']
虚拟模块
虚拟模块
import jQuery from 'jquery'
// virtual: jquery const jQuery = window['jQuery']; export default jQuery;
Затем процесс выполнения заключается
Rollup
в загрузкеjquery
содержимого, которое фактически преобразуется в наш приведенный выше код. -
Автоматически импортировать
CDN
ссылку:Согласно предыдущему процессу, на последнем шаге мы обязательно вручную создадим
script
илиlink
Вставим метку в меткуindex.html
модуляhead
.CDN
Так как этот процесс слишком прост, могут возникнуть определенные накладные расходы, если ссылка не будет удалена после того, как разработчик ее не использует , так чтоCDN
давайте избавляться от этой возможности вместе!html
Нормальная идея Чтобы достичь этого, вы должны сначала найтиhtml
инструмент, который может разобрать модуль,html
преобразовать текст вast
объект структуры, а затемast
рекурсивно проанализировать иhead
вставить узел. Аналогичная возможность была реализована здесь , и заинтересованные студенты могут взглянуть.Но, используя возможности
Vite
встроенного html-плагина , мы можем сделать это проще. Заинтересованные студенты могут щелкнуть, чтобы узнать о конкретной реализации.Здесь я кратко объясню функцию. Плагин будет вызванtransformIndexHtml
, и если возвращаемое значение несет в себе определенный идентификатор, информация будет инжектирована вhtml
конкретное место, а способ использования можно найти в официальной статье . Тогда нам нужно толькоtransformIndexHtml
вернуть информацию в хук,Vite
а встроенный плагин сделает это за нас.
支持 Vite 2.0及其以上版本
Достижение целей:
Как упоминалось выше в [ ESM
Поддержка стандартизированных ссылок на продукты ], нам нужно сказать, что нам не нужно продолжать синтаксический анализ Rollup
стандартизированных ссылок, поэтому нам нужно добавить новые атрибуты в конфигурацию . Поскольку внешние ссылки поддерживают асинхронность (процесс настройки внешних ссылок будет в значительной степени связан с платформой), она не поддерживает асинхронную настройку между версиями . Можно добавить только вручную в модуле .ESM
CDN
Rollup
external
ESM
2.0
2.2
Vite
vite.config.*
external
заключение
Хорошо, до сих пор обсуждались идеи реализации. Я считаю, что большинство студентов уже могут писать external
плагины такого типа, что довольно интересно. Я закодировал идею реализации, а заинтересованные студенты могут скачать проект clone
. Здесь я также жду всех, кто приносит хорошие идеи и вклады на склад.Конечно , было бы здорово оставить свою звезду.Спасибо за чтение!