Как объединить интерфейс и серверную часть в одном репозитории в мире CI/CD.
В прошлом я работал над рядом проектов, в которых для внешнего и внутреннего интерфейса использовались разные изолированные репозитории и конвейеры развертывания. Однако, в зависимости от того, насколько однородно работает команда и насколько динамична коммуникация программных компонентов, это приводит к значительным блокировкам, если соответствующие компоненты внезапно перестают понимать друг друга. Сквозное тестирование также может быть сложным.
Разве не было бы здорово, если бы и клиент, и сервер находились в одном репозитории, используя одно и то же развертывание и тестирование? Полный стек разработчика будет иметь гораздо более быстрый обзор потока данных от серверной части к интерфейсу и обратно.
В классическом CI/CD нам нужны разные общие функции:
build: сборка/компиляция кода и создание исполняемого кода.
test:проверка все условия тестирования для только что сгенерированного кода по-прежнему работают должным образом.
run :запускает соответствующий компонент во время выполнения модуля.
Связанный файл package.json будет выглядеть примерно так…
{ … “scripts”: { … “start”: “…command for starting the frontend in local context…”, “build”: “…run a local build, result would be in /build subfolder …”, “test”: “…running tests…”, … }, … }
При изоморфном подходе предыдущие репозитории для внешнего интерфейса и внутреннего интерфейса преобразуются в подкаталоги репозитория приложений. Все функциональные возможности, созданные ранее и относящиеся к сборке, тестированию или запуску, не изменяются и переносятся без изменений в эти подпапки. На корневом уровне приложения соответствующие универсальные функции (сборка, тестирование и запуск) теперь реализованы как вызовы фреймов, которые затем только параллельно выполняют соответствующие функции во вложенных папках.
Затем во время сборки на верхнем уровне добавляется некоторая магия, чтобы объединить интерфейс и сервер непосредственно в одном контейнере / модуле.
Чтобы понять эту магию, мы сначала исследуем природу двух подкомпонентов нашего приложения.
Внешний интерфейс
В настоящее время интерфейс в основном состоит из одностраничного приложения Javascript, созданного фреймворком (React, Angular, Vue, …). В конечном итоге сборка сводит всю работу фронтенд-разработчиков к 3 статическим файлам: волшебство!
index.html
bundle.css
bundle.js
Бэкэнд
Бэкэнд обычно представляет собой простой сервер отдыха / GraphQL, который также имеет возможность доставки статических файлов. Основная идея состоит в том, чтобы просто скопировать 3 файла, упомянутых выше, в папку static/public серверной службы и доставить их в браузер клиента с помощью соответствующих вызовов URL: Готово!
Соединяем все это изоморфным образом
Связанный "общий" файл package.json на корневом уровне будет выглядеть примерно так…
{ … “scripts”: { … “run”: “cd backend;npm start”, “build:frontend”: “cd frontend;npm run build;cd ..”, “build:backend”: “cd backend;npm run build;cd ..”, “build:copyfe2be”: “cp frontend/build/ backend/build/static/”, “build”: “npm run build:frontend;npm run build:backend;npm run build:copyfe2be”, “test:frontend”: “frontend/npm run test”, “test:backend”: “backend/npm run test”, “test:e2e”: “…run e2er tests…”, “test”: “npm run test:frontend;npm run test:backend;npm run test:e2e”, … }, … }
В целом, конечно, это всего лишь грубая общая схема того, как можно построить изоморфный стек, но основная идея должна быть ясна всем. Тем более, что большое количество возможных фреймворков и компьютерных языков, которые можно здесь переставить, было бы слишком далеко, чтобы представить подробную реализацию для каждого отдельного случая.
Надеюсь, мне удалось донести до вас общую идею такого стека и надеюсь, вам понравится ваша первая реализация.