Yamato DaiwaAutomation

Вычисление путей к ресурсам по указателям

Проблематика

Что было до YDA

Абсолютные пути и их подводные камни

Рассмотрим нижеследующие настройки сборки проекта. Согласно таковым, изображения ниже 01-Source/SharedAssets/Images должны быть скопированы в 02-StaticPreviewBuild/images, а http://localhost:3000 будет ссылаться на 02-DevelopmentBuild/StaticPreview:

Структура тестового проекта. В корне находятся папки «01-Source» с исходными файлами и «02-StaticPreviewBuild» c выходными файлами. Ниже «01-Source» находится: файл «Pages/index.pug», пустая папка «Services», изображение «GrayCat.jpg» в поддиректории «SharedAssets/Images/Cats».

Теперь, мы можем ссылаться на файл 01-Source/SharedAssets/Images/Cats/GrayCat.jpg (будет скопирован в директорию 02-StaticPreviewBuild/images/Cats) из Pug-кода по укороченному абсолютному пути:

Допустим, этот код имеется в в файле 01-Source/Pages/index.pug. Тогда, если мы запустим сборку проекта:

то как только первоначальная сборка будет завершена, главная страница (ожидается index.pug по умолчанию) откроется в браузере и изображение отобразится.

Вроде всё нормально. Что же здесь не так?

Во-первых, чтобы указать значение HTML-аттрибута src, нужно было просчитать в голове путь выходного файла (в данном случае путь к изображению, относительный корню проекта, будет 02-StaticPreviewBuild/images/Cats/GrayCat.jpg). Хорошая система сборки проектов должна брать эту рутину на себя.

Во-вторых, изображение будет корректно отображаться до тех пор, пока оно находится (или, как говорят, «хоститься») на том же же сервере, что и HTML-файл — сервере для локальной разработки, или же обычного. В данном случае YDA для обеспечения сервера для локальной разработки под капотом использует утилиту Browsersync, в результате чего укороченный абсолютный путь /images/Cats/GrayCat.jpg соответствует полному абсолютному пути http://localhost:3000/images/Cats/GrayCat.jpg.

А теперь представим, что нам нужно показать промежуточный результат заказчику, для чего отправим ему заархивированную папку 02-LocalDevelopmentBuild (перед отправкой её копию можно переименовать) с содержимым. Если заказчик использует компьютер с операционной системой Windows, то скорее всего он скачает себе этот архив в папку C:\Users\〈UserName〉\Downloads и там его распакует. Однако, Windows он использует или macOS — изображения он не увидит, когда откроет в браузере index.html, в какой директории он бы архив не распаковал. Всё потому, что укороченный абсолютный путь к изображению ссылается уже не на локальный хост http://localhost:3000/, а на локальную файловую систему — в случае с Windows и диском C, на укороченному абсолютному пути /images/Cats/GrayCat.jpg будет соответствовать C:\images\Cats\GrayCat.jpg.

И что Вы скажете Вашему заказчику, когда от него придёт разгневанное сообщение: «У меня картинки не отображаются!!! Что за ерунду ты мне прислал?!»? Вы скажете: «О, это потому что у вас нет локального сервера. Так, подождите минуту, я сейчас отправлю вам приглашение в GitHub — вы там зарегистрируетесь. Потом, установите систему контроля версий Git себе на компьютер и склонируйте репозиторий с проектом. Также, у вас должен быть установлен Node.js. Как только будет готово, откройте терминал и смените директорию на ту, куда Вы склонировали репозиторий. Потом, переключитесь на ветвь «feature/top_page» и установить зависимости командой «npm install» — её тоже через терминал надо вводить. Как только будет готово, запустите «npm run dev», и тогда у вас откроется браузер и вы увидите все изображения!».

Если Вы хоть немного имеете опыт общения с клиентами, то понимаете, что заказчик испытает целую гамму чувств — от ступора и ощущения, что Вы над ним издеваетесь до желания Вас убить. И эти чувства вполне естественны для заказчиков, потому что Вы в данной ситуации заставляете их заниматься работой, требующей профессиональных навыков. Менеджеры и любые другие представителя стороны заказчика не обязаны иметь технологические навыки и специализированное программное обеспечение— будь то Node.js, контроль версий, работа с зависимостями, или сборка проекта; их задача — контролировать выполнение работы в срок и при необходимости менять приоритет задач. Всё, что им для этого нужно — это открыл файл у себя в браузере — и чтобы всё отображалось.

Распространённое решение — использование так называемых облачных сред для разработки. По сути это — веб-сервер с ограниченным доступом, куда можно загружать промежуточный результат с целью показать его заказчику. Подобные услуги часто входят в перечень поставщиков облачных вычислений, таких как AWS и GCP. Однако, такой поход добавляет новые переменные в уравнение — новая услуга, новые траты, новые проблемы, что усложняет организацию разработки. Подобный сервер понадобится для этапов функционального тестирования, инсценирования (стэйджинга), и, конечно же, продакшена, но ещё один сервер для режима разработки — это новая проблема, к решению которой руководство обычно не готово в самом начале проекта. Должно быть какое-то другое решение, которое не вовлекает сторонние сервисы, но при этом не является сложным. Отправка заказчику набора файлов — вполне приемлемое решение, просто оно несовместимо с использованием абсолютных путей.

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

Относительные пути и их подводные камни

Изменение укороченных абсолютных путей на относительные на первый взгляд решит вышеизложенную проблему: изображение будет корректно отображаться что с использованием локального сервера для разработки, что прямом при открывании HTML-файла в браузере на другом компьютере.

Проблема даст о себе знать, как только в сайте или приложении начнёт увеличиваться количество страниц, что мы сейчас и инсценируем.

Добавим две новые страницы:

  1. 01-Source/Pages/Animals/Cats.pug
  2. 01-Source/Pages/Animals/Dogs.pug

Важно, что эти файлы находятся не в той же директории, что и index.pug, Организовать HTML-файлы по директориям — это вполне нормально а хорошая система сборки проектов обязана это поддерживать. Однако, на каждой из этих страниц будет шапка с одним и тем же изображением (логотипом). Не проблема, когда мы используем препроцессор Pug: создадим компонент Header с помощью Pug-примеси в 01-Source/SharedComponents/Singletons:

Обновлённая структура тестового проекта. В директорию «01-Source/Pages/Animals» были добавлены файлы «Cats.pug» и «Dogs.pug», а в «01-Source/SharedComponents/Singletons» — «Header.pug».
Текущая структура проекта

Чтобы использовать компонент Header, соответствующий файл необходимо подключить в pug-файлы всех страниц, где он используется — сейчас у нас это index.pug, Cats.pug и Dogs.pug.

Если мы пересоберём проект, то на главной странице логотип будет отображаться корректно. Однако, если мы откроем 02-StaticPreviewBuild/Animals/Cats.html или 02-StaticPreviewBuild/Animals/Dogs.html, то логотип отображаться не будет, потому что относительный путь ./images/NNN_PetShopLogo.svg верен тогда и только тогда когда HTML-файл, в котором этот путь указан, находится в той же директории, что папка images. В случае в index.html это так, а Cats.html и Dogs.html находятся 02-StaticPreviewBuild/Animals.

Собранный проект в текущем состоянии. В корне директории для сборки находится «index.html», а в поддиректории «Animals» — «Cats.html» и «Dogs.html». Также, в поддиректории «images» находятся файлы изображений.
Текущая структура проекта

Мало того, мы заранее не знаем и не должны знать, в каком файле будет использован компонент Header, потому что суть компонентов в том, что их можно использовать неограниченное количество раз на любой странице, причём иногда даже за пределами проекта (если мы, например, разрабатываем компоненты с корпоративным брендингом для их использования в других проектах).

Но что же теперь делать? Укороченные абсолютные пути уже отсеяны, а теперь оказывается, что относительные тоже не подходят. Однако, зорошая система сборки проекта должна вычислять правильные пути для каждого выходного HTML-файла и YDA такую функциональность имеет.

Концепция ссылок на файлы ресурсов в YDA

Суть в том, что используя YDA, в исходных Pug-файлах нужно HTML-аттрибутам, обычно содержащим пути (src, href и т. д.) указывать не обычные абсолютные или относительные пути, а пути в особом формате, который легко распознать по символам @ или $ (они не эквиваленты, но обо всём по порядку). Далее, в зависимости от режима сборки и настроек, YDA вычислит либо относительные пути для каждой HTML-страницы, либо укороченный абсолютные пути.

В случае файла GrayCat.jpg из примера выше, такой путь в особом формате будет:

Здесь @Sharedалиас, состоящий из префикса @ и идентификатора группы изображений, объявленной в фале настроек YDA:

В данном случае можно даже опустить .jpg: YDA понимает, что src внутри img, начинающийся с @, ссылается на конкретную группу изображений одного из поддерживаемых форматов:

@Shared/Cats/GrayCat можно называть «ссылкой на ресурс», однако слово «ссылка» может запутать, так как используется в разных значениях. Другое название — алиасированный путь, означающее, что путь изначально не является ни] абсолютным, ни относительным, а содержит алиас — указатель на главную директорию группы ресурсов, или же на конкретный файл, если он один на группу (с изображениями такого в YDA невозможно, но возможно со стилями).

Абсолютный или относительный путь будет в итоге?

  • Как было сказано выше, укороченные абсолютные пути несовместимы с концепцией статического превью, а потому в режиме статического превью пути всегда будут относительные.
  • По умолчанию, на основе указанных алиасированных путей, YDA попытается вычислить укороченные абсолютные пути для всех режимов сборки, кроме статического превью. Однако, если не указан публичный путь для целевого режима сборки, то укороченный абсолютные абсолютные пути не могут быть вычислены и вместо них будут относительные пути.
  • С помощью настроек, при необходимости можно вычислять относительные пути и на других режимах сборки. Если не не указано ни настроек, ни публичных путей, то хотя относительный путь и будет вычислен, в консоли будет предупреждение.

Терминология

Обрабатываемые файлы

Обрабатываемыми файлами являются все, которые не связаны с задачей простое копирование. Алиасированный путь в данном случае будет начинаться с @.

Группа произвольного количества файлов
Префикс алиаса (Alias Prefix)
Указывает, что данный путь является не обычным абсолютным или относительным путём, а путём в форма YDA.
ID группы ресурсов (Resources Group ID)
Должны совпадать с ключами ассоциативного массива entryPointsGroups или assetsGroups
Алис группы ресурсов
Ссылается на sourceFilesTopDirectoryRelativePath группы
Путь, относительный sourceFilesTopDirectoryRelativePath
Необязательное расширение имени файла
Если файл имеет несколько расширений, то последнее можно опустить.
Группа одного файла
Префикс алиаса (Alias Prefix)
Указывает, что данный путь является не обычным абсолютным или относительным путём, а путём в форма YDA.
ID группы ресурсов (Resources Group ID)
Должны совпадать с ключами ассоциативного массива entryPointsGroups или assetsGroups.
Алис группы ресурсов
Ссылается на sourceFilesTopDirectoryRelativePath группы

Необрабатываемые файлы