Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAKING CHANGE] feat: SSR, AppRoot: get rid of classes mutation on html elements #7739

Merged
merged 91 commits into from
Nov 28, 2024

Conversation

andrey-medvedev-vk
Copy link
Contributor

@andrey-medvedev-vk andrey-medvedev-vk commented Oct 11, 2024


  • Unit-тесты
  • e2e-тесты
  • Документация фичи (оформлю отдельным PR)
  • Release notes (дооформлю в процессе ревью)

Описание

На текущий момент при монтировании приложения в режиме full/embedded происходит автоматическое добавление классов:

  • на html элемент добавляются классы:
    • токенов текущей темы,
    • класс .vkui,
    • класс layout режима,
    • класс режима адаптивности.
    • добавляются css-переменные для задания safeAreaInsets
  • на точку монтирования добавляется:
    • класс .vkui__root
    • класс .vkui__embedded для режима embedded
    • класс layout режима,
    • класс режима адаптивности.

В том числе при старте приложения в body тут же добавляется контейнер для монтирования плавающих элементов и в режиме embedded на него также вешаются css-переменные для задания safeAreaInsets

Всё это мешает нормальной работе SSR.

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

Решение

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

В процессе переноса открылись причины установки большинства классов на html:

  • для правильной установки цветовой схемы нам мало только задать правильный фон и цвета элементов в рамках AppRoot.
    Для темной/светлой темы также нужный правильные цвета у системного скроллбара. А задать его можно лишь повесив на html элемент свойство color-scheme со значением токена vkui.
  • А также нужен верный цвет фона у html элеменета:
    • для правильного фона при скролее в SplitLayout,
    • для того, чтобы при bounce эффекте при оверскролле на мобильных устройствах, или Safari появление html элемента не было заметно (так как по умолчанию у него цвет заданные браузером по умолчанию в зависимости от color-scheme)

Изменения

- Классы `.vkui` и `.vkui__root--embedded` теперь всегда выставляют фон.

.vkui {
/*
* TODO [>=8]: Убрать background с html элемента, но для этого надо
* чтобы height у всех родителей Panel вплоть до html имели
* min-height: 100% вместо height: 100% иначе фон html выглядывает в
* многоколоночном режиме если чуть ниже проскролить контент.
*/
background: var(--vkui--color_background);
}

.vkui__root--embedded {
background: var(--vkui--color_background);
}

Раньше это делалось только в режиме адаптивности regular, чтобы у Group в regular в режиме card был правильный фон. (добавлено было в этом PR #1065)

VKUI/src/styles/styles.css

Lines 126 to 128 in b86be10

.vkui-sizeX-regular {
background: var(--background_page);
}

Сейчас в этом для Group нету необходимости, так как фоном для Group управляет Panel
.modeNone .in,
.modePlain .in {
background: var(--vkui--color_background_content);
}
.modeCard .in {
background: var(--vkui--color_background);
}
@media (--sizeX-regular) {
.modeNone .in {
background: var(--vkui--color_background);
}
}

Но совсем убрать фон у .vkui нельзя, так как в многоколоночном режиме SplitLayout видно фон html элемента , если чуть проскролить контент. Это потому, что все вложенные в SplitLayout компоненты вплоть до Panel имеют height: 100%, то есть фон в итоге применяется только на 100% высоты экрана, а ниже фона уже нет. Это можно исправить заменив везде height: 100% на min-height: 100%, но тут нет гарантий, что ещё чего-нибудь не выстрелит, поэтому я бы этот рефакторинг сделал бы отдельно.

⚠️ Из-за этого изменения многие скриншотные тесты, в которых оберткой тестируемых компонентов был лишь AppRoot (без View, Panel), пришлось перезаписать, так как фон html поменялся с дефолтного цвета браузера на токены .vkui.

- В `AppRoot` c помощью свойства `disableSettingVKUIClassesInRuntime` появилась возможность отключить автоматическое выставление классов `.vkui` на `html` и `.vkui__root/.vkui__root--embedded` на точке монтирования приложения в режиме `full/embedded`

Использовать это свойство стоит в режиме SSR, чтобы в рантайме VKUI этим на занимался.
Но можно и не отключать это поведение, главное, чтобы при SSR эти классы уже стояли там куда их выставляет VKUI, чтобы при гидратации изменений в классах страницы не произошло и браузеру не нужно было бы пересчитывать DOM и CSSOM.

В режиме full .vkui класс навешивается на html элемент, а .vkui__root на точку монтирования приложения.
В режиме embedded .vkui__root и .vkui__root--embedded навешиваются на точку монтирования приложения.

- Все остальные классы и токены, требуемые `VKUI`, которые раньше вешались на `html` или точку монтирования приложения, теперь вешаются на контейнер `AppRoot`. Так как `AppRoot` это точка входа в `VKUI` приложение, то такой подход приемлем.

Чтобы компоненты, рендерящиеся через порталы вне DOM дерева AppRoot, тоже имели доступ к токенам и стилям AppRoot был создан компонент AppRootStyleContainer. Он используется как в AppRoot, так и как обертка для порталов (а значит модалок и попапов), в компоненте AppRootPortal.
AppRootStyleContainer через контекст знает какой сейчас режим (mode), какой appearance, поэтому в модалках и других плавающих элементах всегда будет применена верная цветовая схема и токены.

- `AppRootPortal` был переработан

Упрощены проверки cвязанные с usePortal свойством.

portalRoot, контейнер для порталов всех плавающих элементов больше не создается при первом рендере.
Теперь по умолчанию все плавающие элементы рендерятся в document.body через createPortal.
Это возможно за счёт обертки AppRootStyleContainer, которая прокидывается в портал вместе с плавающим элементом и гарантирует наличи нужных токенов и классов у плавающих элементов.
В AppRoot всё также можно передать свой portalRoot как ref, так и как HTML элемент.

- Пропы `popout` и `modal` из `SplitLayout` помечены как `@deprecated`.

Так как мы теперь можем обернуть плавающие элементы в токены и классы AppRoot при рендере через портал, то отпадает надобность в жесткой привязке modal/popout компонентов к SplitLayout (Alert, ScreenSpinner, ActionSheet)
По умолчанию модалки/попапы будут рендерится в document.body.
Это позволяет избавить пользователей от необходимости обязательно передавать ModalRoot в SplitLayout и держать стейт переключения модалок на уровне SplitLayout.
Теперь ModalRoot можно объявить в любой части приложения, как и Alert, ScreenSpinner и ActionSheet.
Также можно иметь несколько ModalRoot если требудется по смыслу разделить модалки. (Есть ограничение на одновременный рендер модалок из разных ModalRoot, так как будет две подложки, их цвета будут складываться и подложка будет темнее.

Тем не менее всё ещё можно рендерить модалки/попапы как раньше используся popout/modal свойства.
Но по умолчанию ModalRoot и Popout будут рендерится в document.body. Чтобы это изменить можно
передать в них usePortal={false}.

Release notes

BREAKING CHANGE

  • AppRoot:
    • переработана логика автоматического добавления классов, необходимых для работы VKUI, на документ. Постарались максимально уменьшить их количество.
      В режиме mode="full" на html-элемент добавляется класс .vkui и класс токенов темы, которая сейчас используется. На точку монтирования приложения добавляется класс .vkui__root.
      В режиме mode="embedded" на точку монтирования добавляются классы .vkui__root и .vkui__root--embedded.
      В режиме mode="partial" дополнительные классы не добавляются.
      Добавление классов можно отключить с помощью нового свойства disableSettingVKUIClassesInRuntime. Это отключит добавление всех классов, кроме класса токенов.
      SSR. Для того, чтобы минимизировать затраты браузера на рендер страницы нужно на стороне сервера проставить все классы самостоятельно.
    • по умолчанию все плавающие элементы (модальные окна, попапы) рендеряться в document.body. Раньше в VKUI дополнительно создавался контейнер для порталов. Мы его убрали, чтобы при старте приложения дополнительно не создавать контейнер в document.body, который может быть не нужен. Переопределить контейнер для рендера порталов всё также можно с помощью portalRoot.
  • SplitLayout:
    • свойства popout и modal помечены как deprecated.
      Это означает что ModalRoot и popout элементы (Alert, ScreenSpinner и ActionSheet) можно объявлять в любой части приложения. Больше нет необходимости объявлять их на верхнем уровне и передавать в SplitLayout. Такие элементы будут по умолчанию рендерится в document.body. Если хочется вернуть старое поведение, то нужно точечно отключить функцию портала, передав, например, в ModalRoot usePortal=false.

Copy link
Contributor

github-actions bot commented Oct 11, 2024

size-limit report 📦

Path Size
JS 385.62 KB (+0.07% 🔺)
JS (gzip) 116.87 KB (+0.06% 🔺)
JS (brotli) 96.18 KB (+0.02% 🔺)
JS import Div (tree shaking) 1.56 KB (0%)
CSS 335.03 KB (+0.02% 🔺)
CSS (gzip) 42.4 KB (-0.05% 🔽)
CSS (brotli) 33.49 KB (+0.22% 🔺)

Copy link

codesandbox-ci bot commented Oct 11, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Copy link
Contributor

github-actions bot commented Oct 11, 2024

e2e tests

Playwright Report

Copy link
Contributor

github-actions bot commented Oct 11, 2024

👀 Docs deployed

Commit fad1174

Copy link

codecov bot commented Oct 11, 2024

Codecov Report

Attention: Patch coverage is 99.33333% with 1 line in your changes missing coverage. Please review.

Project coverage is 95.45%. Comparing base (cb55d05) to head (fad1174).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
packages/vkui/src/components/AppRoot/helpers.ts 90.90% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7739      +/-   ##
==========================================
- Coverage   95.46%   95.45%   -0.02%     
==========================================
  Files         380      382       +2     
  Lines       11324    11312      -12     
  Branches     3777     3781       +4     
==========================================
- Hits        10811    10798      -13     
- Misses        513      514       +1     
Flag Coverage Δ
unittests 95.45% <99.33%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@vkcom-publisher vkcom-publisher added pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности and removed pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности labels Oct 19, 2024
Copy link
Contributor

@inomdzhon inomdzhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как всегда, шикарная работа 👏 👏 👏

Отметил несколько моментов, но на первый взгляд то, что нужно 👍

Также:

  1. нужно ребейзнуть master – там Appearance стал ColorScheme;
  2. нужно в доке Stylegude тоже указать vkui и vkui__root классы в HTML;
  3. нужно будет сразу глянуть почему скриншоты поплыли и не нужно ли из-за ошибок в них всё переделывать

Copy link
Contributor

@inomdzhon inomdzhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Спасибо за правки 🙏 Зарезолвил комменты, а те, что открыты, можешь сам закрыть, оставил их, чтобы было видно где ответил


В Styleguide нужно стили подправить, правый контент не на всю высоту image

@andrey-medvedev-vk andrey-medvedev-vk force-pushed the mendrew/7529/AppRoot-ssr branch 2 times, most recently from d7e603c to 08b428e Compare November 7, 2024 14:44
@vkcom-publisher vkcom-publisher added pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности and removed pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности labels Nov 15, 2024
@andrey-medvedev-vk andrey-medvedev-vk force-pushed the mendrew/7529/AppRoot-ssr branch 4 times, most recently from 669f35c to a3f9cbd Compare November 25, 2024 10:45
@andrey-medvedev-vk andrey-medvedev-vk marked this pull request as ready for review November 25, 2024 16:41
@andrey-medvedev-vk andrey-medvedev-vk requested a review from a team as a code owner November 25, 2024 16:41
@andrey-medvedev-vk andrey-medvedev-vk changed the title [BREAKING CHANGE] feat: SSR, AppRoot: get rid of body classes mutations [BREAKING CHANGE] feat: SSR, AppRoot: get rid of classes mutation on html elements Nov 26, 2024
@BlackySoul
Copy link
Contributor

2024-11-26.22.19.59.mov

Нормально, что подложка исчезла у ActionSheet?

@andrey-medvedev-vk
Copy link
Contributor Author

2024-11-26.22.19.59.mov

Нормально, что подложка исчезла у ActionSheet?

Спасибо, что заметила!
Да, похоже этим PopoutRootиз SplitLayout занимался. Я где-то ему замену делал.

Reuse AppRoot styles in AppRootPortal
to share same tokens
@andrey-medvedev-vk andrey-medvedev-vk marked this pull request as ready for review November 27, 2024 13:46
@andrey-medvedev-vk
Copy link
Contributor Author

2024-11-26.22.19.59.mov

Нормально, что подложка исчезла у ActionSheet?

Исправил ActionSheet, раньше он зависел от PopoutRoot из SplitLayout, который я убрал. Теперь ActionSheet режиме menu также как и ActionSheet в режиме sheet рендерится внутри PopoutWrapper, но, в отличии от режима sheet рендерится с прозрачной подложкой. ⚡ 5beab09

Поправил выставление layout класса на html. Подчистил скриншотные тесты и прокомментировал изменения в скриншотах.

inomdzhon
inomdzhon previously approved these changes Nov 27, 2024
Copy link
Contributor

@inomdzhon inomdzhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥🔥🔥 👏👏👏

колосальный рефактор!!! AppRoot стало гораздо легче читать за счёт выноса распила логики внутри

и документация ❤️ до этого вообще догадки приходилось делать как это работает

🤝

packages/vkui/src/components/AppRoot/AppRoot.tsx Outdated Show resolved Hide resolved
F

Co-authored-by: Inomdzhon Mirdzhamolov <[email protected]>
inomdzhon
inomdzhon previously approved these changes Nov 27, 2024
@andrey-medvedev-vk andrey-medvedev-vk requested a review from a team November 27, 2024 15:09
@BlackySoul
Copy link
Contributor

2024-11-27.22.21.51.mov

Заметила, что в storybook, если выбрать мобильный вид - исчезла какая бы то ни была разница в фоне. Не знаю, насколько это критично х)
Но можно было бы фон storybookа чутка изменить

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants