Перенос сайта на статику: мотивация, стоимость, работа

Недавно мы сделали то, о чём грезят все программисты и дизайнеры — переписали всё с нуля: полный редизайн нашего сайта и написание «движка» с чистого листа. Ниже поведаем о мотивации и процессе миграции с онлайн-CMS на статику.

w2ykkryu4m7jezbwph0wssozhhq.png

Что за сайт-то?

Сайт-визитка компании. Состоит из ряда информационных страниц (о нас, контакты и т.п.), вакансий и портфолио — большого числа кейсов по нашим проектам, выполненных в едином стиле, но с уникальными особенностями. Никакого интерактива с пользователями. Полная двуязычность (за исключением некоторых страниц).

С контентом работают разные люди — маркетологи, HR-менеджеры, разработчики. У разных людей (и для разных задач) разные предпочтения в инструментах. Если фронтэндщику, верстающему новый кейс в портфолио, удобнее сделать git pull и работать в своём привычном окружении (vim, конечно), то HR’у, исправляющему опечатку в тексте вакансии, проще через веб-морду поменять одну букву, нажать кнопку «сохранить» и заниматься дальше своими делами.

Как было

Исторически сложилось так, что в предыдущей реинкарнации сайт был построен на самодельном движке, основанном на фреймворке Ruby on Rails. В качестве CMS использовался rails_admin. Для редактирования части контента был подключен WYSIWYG-редактор (CKEditor); остальное — в виде голого HTML (CodeMirror).

Мотивация

Зачем трогать, если работает?


  1. Проблема синхронизации данных в репозитории и данных в БД.


    
Банальная CMS на RoR использовала банальную СУБД sqlite (да, это один из тех случаев, когда sqlite идеально годится для продакшена). Соответственно, тот контент, который лежит в БД, не лежит в репозитории в git. Это неудобно для фронтенд-разработчиков, которым необходимо внести серьёзные изменения, например, в кейс портфолио. Дело в том, что первичная версия кейса, создаваемая разработчиком, лежит в виде шаблона в репозитории, а в момент деплоймента шаблон компилируется и пишется в БД, дабы иметь возможность его редактировать в CMS. Обратный процесс нетривиален (а в общем случае хоть и возможен, будет давать не исходный результат, что в итоге создаёт проблемы с патчами, например).

  2. Операционная стоимость.

    

Сайт не требует интерактива от пользователей, но при этом всё равно необходима относительно сложная инфраструктура — как минимум одна машина с реверс-прокси и app-сервер. Как известно, RoR любит покушать RAM, а это стоит денег.

  3. Производительность.

    

Значительно затрудняется оптимизация производительности. Необходимо кэшировать страницы / фрагменты. Кэш надо инвалидировать. Интеграция с CDN требует когнитивных усилий.

  4. Удобство работы.

    

Известный факт: WYSIWYG работает не очень. Часто приходится в нём прибегать к кнопке «показать код» и редактировать HTML. А если этот HTML скомпилирован из шаблона, он бывает не очень красивым, и в окошке браузера работать с ним не комильфо.

Первые три пункта полностью решаются движком, построенным по принципу так называемого генератора статических сайтов. Данные синхронизировать никуда не надо, потому что они лежат в едином хранилище, мощности для хостинга статических страничек не нужны, кэширование и CDN становятся тривиальны.

Другие бонусы решения на статике:


  • Мы в итоге захостились на GitHub Pages, который самостоятельно менеджит SSL-сертификаты от Let’s Encrypt, интегрируется с Akamai CDN и не просит за это ни цента.
  • Все изменения сохраняются в истории репо. Ранее часть изменений была в git log'е, а часть — в истории в Rails Admin.
  • Все изменения можно сперва проверить на тестовом инстансе, куда они автоматом попадают по пушу в репо. Если всё хорошо, то одной кнопкой всё деплоится в прод. Ранее постоянно синхронизировать весь контент между контурами и/или вносить все правки сперва на тест, потом на прод, было настолько неудобно (и необязательно), что никто этого, конечно, не делал. В какой-то момент тест вообще отключили, потому что, опять же, лишние бесполезные ресурсы.


GitHub Pages

Вы перешли только в 2019?

Почему же с такими очевидными плюсами мы осуществили переход только сейчас? Не потому что программисты только из пещеры вылезли. Они уже на протяжении нескольких лет пытались продать начальству своё решение. Но помимо внепланового выделения бюджета, главным препятствием стоял вопрос удобства работы с контентом: как научить главных контентщиков (маркетологов) работать со всей этой историей? Если с редактированием «кода» они более-менее знакомы и привыкли, то обучить работать их с git'ом не всем представлялось целесообразным.

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

Шло время, и появились такие решения, как GitLab и встроенный в него Web IDE. И когда подошло время редизайна сайта, мы наконец создали небольшой прототип, представили его отделу маркетинга на ознакомление, проведя небольшой урок по работе с GitLab. На объяснение потребовалось менее часа. Маркетологам реализация понравилась, и процесс был запущен.

GitLab IDE Interface

Технические подробности

Итак, пара слов о том, как в итоге получилось.

> tree -aL 1 --dirsfirst -C
.
├── .git
├── app
├── images
├── node_modules
├── pages
├── public
├── .gitignore
├── .gitlab-ci.yml
├── .jshintrc
├── README.markdown
├── gulpfile.js
├── makefile
├── package-lock.json
└── package.json

Что видно сразу:


  • генератор написан на Node.js;
  • используется таск-раннер gulp;
  • на верхнем уровне есть директории app (файлы «приложения», то есть шаблоны и исходники js и css), images (очевидно, картинки), pages (контент), public (директория, которая будет сервиться по http).
> tree -aL 3 --dirsfirst -C pages/
pages/
├── en
...
└── ru
    ├── portfolio
    │   ├── projects
    │   └── index.pug
    ├── vacancies
    │   ├── klgd
    │   ├── msk
    │   ├── spb
    │   └── index.pug
    ├── 404.pug
    ├── about.pug
    ├── contacts.pug
    ├── education.pug
    ├── events.pug
    ├── faq.pug
    ├── index.pug
    └── process.pug

Контент структурирован интуитивно понятным образом, так что (даже без знания английского языка) можно найти нужный файл, исходя из URL страницы. Используется шаблонизатор Pug (синтаксис проще и чище, чем HTML).

Со сбором js, css и картинок всё банально. Посмотрим на недословную выжимку кода из gulpfile’а, собирающего странички:

gulp.task('pug', () => {
  // Preload shared data only once.
  let sharedData = {};
  for (let lang of ["en", "ru"]) {
    sharedData[lang] = loadSharedData(lang);
  }
  // Load necessary data from other files for each file render.
  let dataGetter = (file) => {
    let content = frontmatter(String(file.contents));
    file.contents = new Buffer(content.body);
    let data = content.attributes;
    data.lang = file.relative.split(path.sep)[0];
    data.env = process.env.NODE_ENV;
    loadPageData(data, sharedData);
    return data;
  };
  // Remove html file extensions in URLs.
  let renamer = (filepath) => {
    if (filepath.basename === '404') {
      return;  // special case for Github Pages
    }
    if (filepath.basename !== 'index') {
      filepath.dirname = path.join(filepath.dirname, filepath.basename);
      filepath.basename = 'index';
    }
  };
  return gulp
    .src('./pages/**/*.pug')
    .pipe(data(dataGetter))
    .pipe(pug(pugOptions))
    .pipe(rename(renamer))
    .pipe(gulp.dest('./public'));
});

Для подгрузки данных при рендеринге шаблонов используется gulp-data. Метаданные файлов лежат в самих шаблонах в формате front-matter, откуда соответствующим пакетом подгружаются. «Смежные» данные, например, список кейсов для индексной страницы портфолио или список вакансий, подгружаются специальным дата-геттером, который собирает необходимый набор данных для каждой отдельной страницы.

Помимо этого используется gulp-rename для облагораживания URL’ов — все странички помещаются в одноимённые директории под названием index.html. Таким образом, исходная страничка faq.pug доступна по URL /faq/, а не /faq.html.

pwnltoyslzvdrqx4snuqilt_pqq.png

Второй интересный момент, который стоит рассмотреть, это конфигурация GitLab CI/CD:

stages:
  - build
  - deploy

build_sites:
  stage: build
  tags:
    - npm
  before_script:
    - make deps
  script:
    - make build
  variables:
    NODE_ENV: production
  artifacts:
    when: on_success
    expire_in: 7 days
    paths:
      - public

deploy_staging:
  stage: deploy
  tags:
    - npm
  only:
    - master
  environment: staging
  dependencies:
    - build_sites
  script:
    - make deploy_server
  variables:
    SSH_USER: elegion

deploy_production:
  stage: deploy
  when: manual
  tags:
    - npm
  only:
    - master
  environment: production
  dependencies:
    - build_sites
  script:
    - make -j2 deploy_ghpages

Тут стоит обратить внимание на следующие вещи:


  • Сборка происходит при пуше в любую ветку. Так, при работе в feature-бренчах люди получают фидбек, если где-то накосячили на столько, что сломали билд.
  • При пуше в master, автоматом происходит деплой на тестовое окружение. Для деплоя используется примитивный rsync --archive --compress --delete --copy-links ./public ${SSH_USER}@${SSH_HOST}: (да, ещё один бонус сайта на статике — сверхшустрые и беспроблемные деплои).
  • Джоба на деплой в прод становится доступна после успешной сборки и деплоймента в тест и запускается по нажатию одной кпопки в UI.
    GitLab CI UI
  • Благодаря возможностям make, деплой сразу двух сайтов на двух языках (www.e-legion.com и www.e-legion.ru) делается параллельно.

Заключение

На разработку прототипа ушло 2 дня. Доведение движка до ума заняло ещё 3 дня. Настройка CI/CD заняла менее 1 дня. Остальное потраченное время было необходимо в любом случае — создание дизайна, рерайт контента, вёрстка. В итоге довольны все: разработчики, потому что simple is better than complex и поддержка стала в разы проще; админы, потому что они перестали быть нужны вообще, контентщики, потому что стало удобнее. Цитата маркетолога: «Знаю, что мне теперь не хочется закрыть глаза или убежать, когда нужно что-то на сайте поправить». Заодно и на хостинг теперь уходит 0 ₽ в месяц, примерно на 750 ₽ меньше, чем раньше.


p_4kv1zmyad-1z5zbtcugkchgje.png

Если вы в своей IT-компании до сих пор не используете статику для сайтов-визиток, лендингов и подобных штук по причине того, что переживаете за способности ваших контентщиков, спешим переубедить вас и ваше начальство по опыту нашей истории успеха. Современный UI GitLab и пободных ему git-хостингов при должной конфигурации проекта более удобен для работы наших маркетологов и HR’ов, чем старая CMS на rails_admin. Даже если первые пару раз у людей будут возникать вопросы, помочь с ответом сможет любой подручный разработчик, знакомый с git, потому что всё максимально просто и понятно.

© Habrahabr.ru