Плагин Vite для расширения внешних возможностей

предисловие

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цель расширения.

  1. Поддержка ссылок ESMна продукты и автоматический импорт ссылок. UMDCDN
    • Объяснение:
      Сопровождается ESMспецификацией поддержки браузера старшей версии. Крупные разработчики пакетов также осознают ESMважность , а также предоставляют ESMстандартизированные продукты, и в то же время есть такие CDNпроизводители , как [skypack] (Skypack: поиск миллионов пакетов JavaScript с открытым исходным кодом), которые ESMподдерживают ссылки на продукты. Поэтому ESMкрайне важно, чтобы плагины поддерживали внешние ссылки.
  2. Поддержка 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 链接достижение целей

  1. 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позволим . Поэтому мы должны сказать вам , что это внешняя ссылка, и вы должны прекратить ее парсинг.reacthttps://cdn.skypack.dev/reactRolluphttps://cdn.skypack.dev/react

  2. UMDПоддержка ссылок на продукты Canonical:

    В первые JQueryдни популярности мы обычно используем CDNспособ внедрения JQuery, а затем CDN, после выполнения импортированного продукта, определенное свойство будет внедряться глобально ( windowв ), и разработчики могут получить JQueryвозможность через это конкретное свойство. У вас может быть идея, в среде браузера нам нужно только помочь получить атрибуты, введенные вJQuery , а затем изменить оператор импорта, то есть заменить на . Это также возможно, но требует специальной обработки для различных методов импорта. Здесь мы можем реализовать это проще, с помощью виртуальных модулей . Некоторые студенты могут быть немного незнакомы с определением , на самом деле, как следует из названия, это ложный модуль, модуль, которого нет на диске. Затем мы можем экспортировать содержимое, которое мы определили в , то есть преобразовать вwindowimport jQuery from 'jquery'const jQuery = window['jQuery']虚拟模块虚拟模块import jQuery from 'jquery'

    // virtual: jquery
        
    const jQuery = window['jQuery'];
    export default jQuery;
    

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

  3. Автоматически импортировать 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стандартизированных ссылок, поэтому нам нужно добавить новые атрибуты в конфигурацию . Поскольку внешние ссылки поддерживают асинхронность (процесс настройки внешних ссылок будет в значительной степени связан с платформой), она не поддерживает асинхронную настройку между версиями . Можно добавить только вручную в модуле .ESMCDNRollupexternalESM2.02.2Vitevite.config.*external

заключение

Хорошо, до сих пор обсуждались идеи реализации. Я считаю, что большинство студентов уже могут писать externalплагины такого типа, что довольно интересно. Я закодировал идею реализации, а заинтересованные студенты могут скачать проект clone . Здесь я также жду всех, кто приносит хорошие идеи и вклады на склад.Конечно , было бы здорово оставить свою звезду.Спасибо за чтение!

рекомендация

отblog.csdn.net/Ashen__/article/details/128025431