Очевидно, что как языки Typescript и PHP, хоть и оба относятся к Си-подобным, но по свойствам очень сильно отличаются. Поэтому мы при всем желании не могли бы обеспечить максимально полную транспиляцию, особенно в сжатые сроки - нужно было понять, чем мы можем пожертвовать, а что будем брать в работу.
Безусловно, хотелось обеспечить удобство для фронтенд-разработчиков, чтобы они могли пользоваться привычными идиомами и инструментами. Поэтому минимальный джентльменский набор требований у нас выглядел примерно так:
- Пишем на typescript.
- Наш код, подлежащий транспиляции, должен абсолютно корректно обрабатываться компилятором tsc.
- Но при этом, очевидно, не любой код, корректно обрабатываемый tsc, мы допускаем до транспиляции
- Соответственно, нужны какие-то механизмы или соглашения, по которым мы пишем изоморфный код.
- Используем React.
Чтобы избежать чрезмерного усложнения нашего транспилятора, мы решили, что изоморфные компоненты будут писать только с использованием React Hooks. Т.е. классы мы не поддерживаем - это сложно и долго.
Транспилировать будем только те компоненты, которые непосредственно отвечают за отрисовку. Это требование в некотором смысле диктует архитектуру построения фронтенда - нам нужно иметь изоморфные view-компоненты, максимально простые и глупые, в которые данные приходят снаружи, а верхнеуровневые компоненты, отвечающие за загрузку данных, мы транспилировать не будем. Аналогично, получается, что на бэкенде мы также будем иметь отдельный код, отвечающий за загрузку данных и передающий их в уже оттранспилированные компоненты на php.
Код, преобразующий данные в вид, пригодный для рендеринга, в наших “глупых” компонентах мы все же допускаем. Но не допускаем обращений к браузерным API и асинхронщины - это будет довольно сложно перенести на сторону бэкенда.
Кроме того, мы в ВК вынуждены ориентироваться на компиляцию нашего php-кода в kphp, при чем крайне желательно, чтобы нам не приходилось править сгенерированный код руками - иначе количество затрачиваемых усилий каждый раз было бы неприемлемым. Это означает посильную расстановку аннотаций типов и phpdoc-аннотаций - и тут нам как раз очень поможет вывод типов typescript.
В целом, особо вариантов не было - нужно было писать свой транспилятор, поскольку готовые решения не удовлетворяли нашим потребностям. Сама задача выглядела как довольно существенный челлендж, но при этом также очень интересно было посмотреть что из этого может получиться.
Умозрительно мы решили, что может - хоть и в достаточно узкоспециализированных кейсах, например на таком сочетании кейсов:
- Бэкенд на php (или даже на kphp - мало ли!)
- Нет возможности или желания тащить на бэкенд полноценный рантайм JS
- Разработчики фронтенда хотят писать на React
- Жизненно необходим серверный рендеринг.
Для такого набора требований решение с транспиляцией “глупых” модулей выглядит достаточно выгодно.