Сила «Просто делать это»

В повседневной жизни разработчика программного обеспечения есть проекты, а есть проекты – те, которые ставят перед вами огромные технические задачи, а также предоставляют огромные возможности для расти и действительно прийти в себя. Недавно у меня была возможность сыграть неотъемлемую роль в одном из наших проектов коммерческой платформы с использованием Spryker: создание архитектуры внешнего интерфейса с нуля с использованием фреймворка Vue.js в качестве основы. Вот моя история и техническое пошаговое руководство о том, как я решил эту задачу.

Не так давно, вскоре после того, как я присоединился к новому проекту в Turbine Kreuzberg, передо мной встала новая задача. Я сразу понял, что это будет нелегко, но я также знал, что это возможность для меня выйти за пределы своих ограничений и создать что-то, чем я мог бы гордиться.

Вот ситуация: в проекте, к которому я присоединился, еще не определена архитектура интерфейса. Это была новая отправная точка для меня. Все проекты, над которыми я работал ранее, уже имели большую часть определенной структуры. Я был там, чтобы помочь сохранить и улучшить. Это было другое.

Я был в положении, когда я должен был предложить хорошее техническое решение.

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

Два варианта: теперь выбирайте!

Начнем с моего решения «утону или поплыву». По сути, мне было предложено два варианта начала создания внешнего интерфейса.

  • Вариант 1: первый включал использование Twig, механизма шаблонов для PHP (подробности см. в документации), объединение его с Javascript/Typescript, а затем применение старой модели DOM (объектная модель документа). манипуляция.
  • Вариант 2. Второй вариант подразумевал внедрение Vue.js в Spryker, фреймворк, с которым я уже был знаком и чувствовал себя очень комфортно.

Чтобы не волноваться: я выбрал второе. Я собирался продолжать заниматься Vue.js.

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

Я выбрал Vue.js по целому ряду причин, но самым важным фактором было то, что этот проект требовал быстрой доставки интерфейсных компонентов. Поэтому я выбрал более медленный старт, чтобы потом развиваться намного быстрее. В этом сценарии «кривая доставки» была намного круче.

После обсуждения с владельцем продукта моей команды и получения согласия на предложенный мной подход, «единственным» оставшимся вопросом была фактическая реализация Vue.js в Spryker. И сначала я понятия не имел, с чего начать.

Исследования, а затем: прорыв!

Так что делать? Исследования, конечно. Я начал исследовать реализацию Vue.js в Spryker и попытался собрать всю информацию, которую смог найти. Я был уверен, что модули Spryker останутся функциональными, поскольку команде требовался полноценный интерфейс, который работал без сбоев. Чтобы гарантировать, что мы сможем реализовать проект в заданные сроки, мы планировали постепенно заменять эти модули компонентами Vue один за другим. Что меня удивило, так это отсутствие доступной информации, которая могла бы помочь мне в моих начинаниях, ни в официальной документации Spryker, ни в нашей внутренней документации.

После нескольких дней исследований чувство потерянности меня немного напугало. В такие времена я всегда стараюсь применять метод «имитации», то есть применяя те же шаги, которые я видел раньше в других реализациях — по сути, подход «делай то, что знаешь». Я понял, что мой предыдущий проект имел подходящую структуру для использования в качестве основы.

Моей первой ключевой целью было просто заставить Vue.js работать. Первым шагом было отобразить на веб-сайте то, что было отрисовано из компонента Vue. Как упоминалось ранее, было очень важно, чтобы какую бы стратегию или реализацию я ни нашел, она по-прежнему позволяла нам видеть текущий веб-сайт со всеми его модулями Spryker. Чтобы иметь возможность сделать это, наше приложение должно быть «гибридным», то есть оно должно принимать использование как модулей Spryker, так и Vue.

Тем не менее, мне нужно было больше информации, поэтому я обратился к нашему внутреннему Slack-каналу разработчика интерфейса и попросил несколько советов о том, как начать это делать. Наконец, после некоторой помощи моих коллег, у меня появилась дорожная карта реализации, которой я мог следовать, но мне все еще не хватало довольно важной информации о том, как внедрить Vue.js в существующий репозиторий программного обеспечения. К счастью, один из наших доверенных технических директоров, Озкан Йилмаз, помог мне найти полезную документацию Spryker по добавлению интерфейсных фреймворков в демонстрационный магазин. К сожалению, эта иллюстрация была сделана с использованием React, поэтому благодаря терпению и доброте Озкана мы тщательно изучили ее и обсудили, как ее можно применить к другим интерфейсным фреймворкам. (Если вам интересно, вот документация: Интеграция React в Atomic Frontend | Документация Spryker.) С помощью этого руководства я действительно быстро и легко достигну своей первой цели.

Как внедрить интерфейсную платформу Vue.js в Spryker

Ладно, хватит любезностей. Давайте шаг за шагом углубимся в то, что я сделал. В документации Spryker реализует React с атомарной архитектурой (подробнее: Atomic Frontend — общий обзор | Документация Spryker), поэтому я воспользовался предложенным подходом и попробовал его с Vue.

Настройка

Вот зависимости, которые необходимо установить в первую очередь:

Webpack — это сборщик модулей в общих чертах, который используется для объединения строк кода JavaScript и других ресурсов (таких как таблицы стилей CSS и изображения) в один файл или набор файлов, которые могут быть загружены веб-браузером. Он поддерживает основные функциональные возможности внешнего интерфейса Spryker. Иногда это может быть сложно настроить, но если этого не сделать, Vue.js не будет работать.

Итак, чтобы использовать vue-loader с webpack, сначала импортируйте это:

В JavaScript объект resolve является частью конфигурации Webpack. Он содержит параметры, определяющие, как Webpack должен разрешать модули и другие зависимости при объединении кода.

Вот как это выглядит:

В этом разрешении псевдоним vue используется для ссылки на файл 'vue/dist/vue.esm-bundler.js', который является основным файлом для платформы Vue.js. Это позволяет вам импортировать компоненты Vue.js, используя псевдоним vue вместо полного пути импорта, что может сделать ваш код более кратким и удобным для чтения.

vue.esm-bundler.js позволяет нам по-прежнему использовать компиляцию шаблона во время выполнения при использовании Wedback в качестве сборщика.

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

Чтобы настроить Webpack для использования vue-loader для всех файлов .vue, добавьте следующий код в массив правил модуля (в котором есть загрузчики vue) прежде всего:

Внутри массива плагинов создайте экземпляр:

Наконец, ваш раздел плагинов должен выглядеть примерно так:

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

Последние две строки (VUE_OPTIONS_API и VUE_PROD_DEVTOOLS) необходимы для предотвращения появления консольных ошибок и предупреждений в консоли браузера devTools из-за «отсутствующей конфигурации».

Использование

Когда дело доходит до применения кода, Spryker рекомендует создавать модули в рамках ShopUI и регистрировать их в файле index.ts. Этот подход включает создание новых экземпляров компонента каждый раз, когда это требуется.

Что-то вроде этого:

Нам нужно поместить vue-product-details в файл Twig, потому что он используется для отображения страницы сведений о продукте на веб-сайте электронной коммерции, а компонент Vue отвечает за динамическое отображение сведений о продукте, таких как имя , цена, изображения и т. д.

Таким образом, Spryker постоянно создает новый экземпляр приложения Vue для каждого созданного компонента.

На мой взгляд, это не идеальное решение. Наряду с тем, что это не лучшая производительность, некоторые потребности межкомпонентной связи будут потеряны, управление состоянием может стать более сложным, проблемы с переводом среди прочего в долгосрочной перспективе.

Всякий раз, когда создается новый компонент Vue, это решение использует один и тот же код. Это приводит к дублированию кода, что также не является идеальным решением. В этом случае я подумал об использовании одноэлементного шаблона проектирования, чтобы избавиться от повторяющихся проблем. Я решил не следовать этому подходу слепо и начал изучать другие идеи.

В моем предыдущем проекте весь интерфейс и структура Vue были отделены от каталога модулей Spryker. Мы использовали корневую папку внешнего интерфейса и хранили в ней все, что связано с внешним интерфейсом. У него были все шансы стать ответом на мои вопросы, но, несмотря на то, что я хотел реализовать эту модель, мне не хватало времени. Вся эта реализация, путь проб и ошибок уже отняли у меня очень много времени, особенно во время спринтов, в которых мы, конечно же, должны представлять результаты клиенту. Поскольку это был проект MVP, заинтересованным сторонам было важно увидеть некоторый прогресс. Так что делать?

Я подумал о применении гибридного решения, похожего на смесь подходов в моем предыдущем проекте, но в стиле Spryker, чтобы сохранить некоторую модульность.

Я создал глобальный корневой компонент Vue-оболочки. Этот компонент включал в себя все приложение, модули Spryker и все остальное, чтобы избежать необходимости создавать экземпляры компонентов Vue каждый раз, когда они используются. При этом все компоненты инициализируются во время создания RootComponent. Таким образом, я мог бы иметь как модули Spryker, так и компоненты Vue внутри этой оболочки.

Поэтому я создал глобальный объект и зарегистрировал все компоненты Vue, которые используются непосредственно в файлах twig.

В экспорте зарегистрируйте общие компоненты с их свойствами. Таким образом, можно легко импортировать и использовать несколько связанных компонентов в других частях приложения с помощью одного оператора импорта.

Затем их можно загрузить, выполнив следующие действия:

Мы создаем все компоненты сразу на базовом уровне в файле vendor.ts.

Второй оператор import делает объект sharedComponents доступным для текущего файла, чтобы содержащиеся в нем компоненты можно было использовать в приложении из любого места.

Третий оператор import предоставляет приложению глобальный компонент значка.

Компонент TjIcon можно использовать откуда угодно без необходимости его импорта. Он доступен по всему миру.

Если вы создаете компонент TjButton, если вы не используете его в файле twig, вам не нужно добавлять его в sharedComponents.

Вот как компоненты регистрируются и создаются:

Давайте подробнее рассмотрим этот фрагмент кода. Что это за префикс "tj-"/"Tj" на самом деле?

После компиляции вроде все заработало. Я добился цели увидеть содержимое компонента на веб-сайте, не испортив ничего остального. Все шло хорошо, пока я не открыл консоль браузера, чтобы проверить наличие ошибок.

И… БУМ!

Было куча предупреждений! О, но предупреждения не имеют большого значения. Они были для меня. Я должен был найти решение, потому что я действительно не оставил бы это так. В ошибках и предупреждениях в консоли инструментов разработчика браузера упоминались некоторые компоненты, которые не были должным образом зарегистрированы в приложении. Vue.js не удалось разрешить модули Spryker в объектной модели документа (DOM).

Модули Spryker выглядят как настраиваемые элементы тегов в DOM, и Vue не знает, что они из себя представляют. Они могут выглядеть как ‹toggler-accordion /›. Поскольку теперь все вызывается внутри оболочки vue-app, Vue видит это и проверяет, является ли это HTML-тегом. Если нет, пытается разрешить их как компоненты Vue. Этот тег не является ни одним из них, поэтому он выдал ошибку.

Чтобы решить эту проблему, необходимо было зарегистрировать эти теги модуля Spryker как элементы костюма. Согласно Документации Vue, вы можете зарегистрировать пользовательский элемент, выполнив следующие действия:

В соответствии с этим следует добавить к каждому тегу модуля Spryker префикс, например, ‹spryker-toggler-accordion›, а затем вернуть tag.startsWith('spryker-'). по методу выше, но это было бы слишком много изменений, поэтому мы можем сделать это наоборот.

Мы ставим перед каждым компонентом Vue префикс Tj и регистрируем все элементы, которые не начинаются с этого префикса, как пользовательские.

После этого на консоли больше не было ни ошибок, ни предупреждений.

Тестирование

Эта базовая функциональность работала очень хорошо до процесса слияния. Я получал красный конвейер из-за неудачных тестов. Чтобы понять почему, я посмотрел на скриншоты (.png), которые делаются каждый раз, когда тест Cest проваливается, но все они были совершенно пустыми.

Сначала я подумал, что, возможно, отсутствует конфигурация, но после небольшого перемещения и отладки оказалось, что проблема возникла из-за оболочки Vue. Содержимое внутри компонента Vue не отображалось. Мне было неудобно проверять это в одиночку, поэтому я еще раз попросил помощи у Озкана. Он сказал, что не сталкивался с подобным в своем магазине Spryker и понятия не имеет, почему это происходит в нашем. Было много поисков и много времени потрачено на эту проблему.

На интернет-форумах люди комментировали ту же проблему, отображая Javascript своих веб-страниц. В некоторых сообщениях было несколько упоминаний о проблемах с веб-драйвером, поэтому я проверил документацию Spryker, чтобы узнать, какой веб-драйвер был предложен (см.: Выполнение тестов с помощью Docker SDK | Документация Spryker). Chromedriver был веб-драйвером по умолчанию, поставляемым с Docker SDK, но по какой-то причине он не работал. Мы также пытались использовать другие веб-драйверы, но безуспешно. Итак, мы решили в последний раз обратиться за помощью: на помощь приходит Хорхе Мурта, еще один технический директор Turbine Kreuzberg!

Оказалось, что в нашем экземпляре магазина Spryker не было настроенного Chromedriver, а не по умолчанию, как мы изначально думали. Codeception был полностью настроен для работы с Chromedriver, но сам сервис не был настроен, поэтому мы сделали, как описано в документации. Мне показалось очень странным, что Spryker использует Chromedriver по умолчанию, но без какой-либо предварительной настройки. Нам потребовалось очень много времени на решение этой проблемы и особенно неприятно, поскольку решение уже было перед нами.

Итак, что же произошло после настройки?

Зеленый трубопровод! 🟢

Заключение

Итак, это был мой подход к этой задаче и то, как я реализовал архитектуру на основе Vue.js в демо-магазине Spryker.

Очень важно подчеркнуть тот факт, что это было «моё» решение. Один проект не похож на другой, и наша зрелость и знания постоянно растут. Я уже начал сомневаться в некоторых решениях, которые я сделал и задокументировал. Был ли лучший способ сделать некоторые детали?

Скорее всего, было, но я сделал все, что мог, с теми знаниями, которые у меня были. И в целом, я все еще убежден в нашей реализации.

Даже если вы считаете, что вам не хватает опыта для решения задачи, с которой вам никогда не приходилось сталкиваться раньше, «просто делать это» будет иметь большое значение. Конечно, всегда помните о том, чего вы не знаете, и никогда не стесняйтесь просить других помочь заполнить пробелы. В конце концов, я не только получил огромное количество технических знаний, но и узнал кое-что о себе.

То, что мы разрабатываем сегодня, всегда может стать лучше завтра. Нам просто нужно перестать бояться, переосмысливать и просто попробовать. Этот процесс убедил меня в полезности экспериментального подхода. Спасибо моей команде и всем, кто доверял мне и помогал мне на этом пути.