Эта неделя оказалась самой мучительной. Помните, я говорил, что прогон всех тестов занимает полчаса? Подержите немного эту цифру в уме.
Если вы это читаете, то наверняка хотя бы в общих чертах понимаете, что такое CSS. Когда-то каскадные таблицы стилей были придуманы как удобный способ описания представления страниц и прошли через долгий путь эволюции. В чём-то эта история схожа с тем, как развивался JS: каждый браузер мог трактовать правила по-своему и вводить новые. Они могли закрепиться, если веб-разработчики их использовали, а могли и пропасть. Хаос был окончательно подавлен стандартизацией и тотальным доминированием Chromium.
Не удержусь от напоминания: саму концепцию CSS в 1994 году предложил Håkon Wium Lie. Он же с 1998 по 2016 год был CTO Opera Software. Технически нельзя сказать «и это тоже придумали в Опере», но там точно знали, как технологию реализовать.
На какой ступени этой эволюции находится Presto? До сей поры мы даже не могли этого выяснить.
Несмотря на то, что мы научили движок запускать WPT, фактически нам была доступна только малая часть всей сюиты. CSS testharness написан на современном JavaScript, и это была ещё одна причина делать ES6 в первую очередь. Но даже этих доработок недостаточно (использованный в тестах диалект новее), поэтому testharness пришлось транспилировать в ES6 через Babel и подложить к нему полифилл промисов. Дополнительно потребовалось ещё несколько доработок как в самом движке, так и в тестах, но так или иначе нужная для CSS часть сюиты разблокировалась.
Если вам интересно: всего на текущий момент для запуска стал доступен 107 151 тест, и ещё около 25 000 остаются недостижимыми. Из всего этого обилия проходит только ~7 000.
Хорошая новость: Presto полностью (ну, мы и не сомневались) поддерживает спецификацию CSS 2.1. Более того — частично он поддерживает и свойства за пределами спецификации через экспериментальные вендорные префиксы. Тогда это была нормальная практика, все браузеры так добавляли поддержку ещё не закреплённых стандартами свойств. Всё, что оставалось сделать, — переименовать префиксные свойства в стандартные. Без отклонений не обошлось: -o-border-image абсолютно не совпадал с тем, как в итоге был стандартизирован border-image, пришлось писать его заново.
Плохая новость: один полный прогон тестов теперь занимает больше пяти часов, и этот прогон становится почти обязательным. Если его не делать, то можно пропустить регрессию, что на этом этапе крайне вероятно.
Пришлось заняться CI: что-то распараллелить, где-то оптимизировать воркфлоу. Например, вместо прямого слияния готовых фича-веток с dev, они собираются в промежуточные «зонтичные» ветки. Для каждой фичи прогоняется только её локальная область тестов, а полный набор запускается лишь при вливании «зонтика» в основную ветку. Это экономит время, но если на «зонтичном» слиянии вылезет регрессия, то исправлять её будет сложнее.
Понимаю, что это, наверное, самое неинтересное из всего, что я тут рассказываю, но я посчитал это важным, ведь именно эта часть работы заняла больше всего времени.
Вернёмся к CSS. Спецификация CSS 2.1 — это примерно 40% от современных стандартов, если считать по количеству свойств, и меньше 3%, если мерить объёмом самих спецификаций. Разброс удивляет, но тут нужно понимать, что начальные спецификации были про раскладку, позиционирование и базовые концепции селекторов. Современные включают десятки иных вещей (типографику, графику, анимации, взаимодействие с движком рендеринга), и проработаны они детальнее. Это объективная реальность, с которой придётся иметь дело.
И, к сожалению, эта работа на начальных этапах почти не параллелится. Чтобы добавить что-то в одном модуле, требуется сначала доработать что-то в другом, тот тянет доработки ещё в двух, и так далее.
Один пример: CSS-функция calc().
Это сущность, о которой Presto не имеет представления. Её реализация требует добавления совершенно нового типа парсера для математических выражений, самой математики, CSS-переменных, новых типов юнитов для размеров, процентных расчётов из вьюпорта и ещё кучи всего.
Но деваться некуда: начинаем с парсера. Оригинальный C-код парсера генерируется bison и затем проходит обработку скриптом на bash (замена исключений на LEAVE/TRAP и т.п.). Но использовавшийся bison 2.5 уже не годится — он устарел напрочь, а актуальный уже не работает со старыми параметрами грамматики. После актуализации приходится менять и адаптирующий скрипт, поскольку структура нового парсера отличается от того, что он ожидает.
Математика включает в себя не только базовую арифметику, но и функции min(), max(), clamp(), round(), mod(), rem(), abs(), sign() + тригонометрию. Плюс граничные случаи, плюс оптимизаторы.
CSS-переменные уже были реализованы нами некоторое время назад, но и тут всплыла проблема: а что, если функции нужна ещё не вычисленная переменная? Нужно писать механизм отложенной подстановки.
Новые юниты vw/vh/vmin/vmax — это внедрение в VisualDevice, сам механизм в движке есть, но его нужно изучить и понять.
И так далее, и тому подобное. Вы не можете просто взять и сделать одну фичу от и до: каждое изменение почти наверняка порождает каскад новых требований.
Чёрт, когда я писал, что JS — это сложно, я даже не представлял, насколько сложнее окажется CSS!
Весь открывшийся простор работы… ну, он не то чтобы повергает меня в ступор, я за десятилетия насмотрелся всякого. Но он смещает точку зрения: вместо проекта одного чудака это должен быть комьюнити-проект — что затруднительно, учитывая легальный статус исходников.