Skip to content

Latest commit

 

History

History
48 lines (37 loc) · 6.43 KB

modules.md

File metadata and controls

48 lines (37 loc) · 6.43 KB

Модульная структура транспилируемого кода

На данный момент поддерживаются базовые способы разбиения кода на модули в стиле ES6, а именно:

  • export function() {...}
  • export const = function() {...}
  • export const = () => {...}
  • export const = { ... } — для объектов-данных. Не следует запихивать в объекты какие бы то ни было функции и колбэки, т.к. kphp с большой вероятностью не сможет вывести их тип.
  • export { getFoo, getBar }
  • import { Some } from '../modules/some'
  • import { Some as SomeOther } from '../modules/some'
  • import * as React from 'react' — пока что это костыль именно для React. Для остальных модулей лучше использовать именованные импорты.

НЕ поддерживаются:

  • Всё, что связано с CommonJS require()
  • export default [что бы то ни было]
  • export Some from '../modules/some
  • import Some from '../modules/some
  • import Some = require(...)

Преобразование CommonJS-модулей

При преобразовании кода требуется выполнить несколько простых правил:

  • Отсутствие кода в глобальной области.
  • Один класс - один файл, имя класса == имя файла.

Это ведет нас к тому, что:

  • Каждый CommonJS файл должен на стороне php представляться отдельным классом.
  • Кроме того, логично сделать React-компоненты отдельными классами с общим предком, поскольку у них есть некоторые общие функции, связанные с рендером.
  • Следовательно, нужно уметь извлекать классы React-компонентов из CommonJS-классов в отдельные файлы и разруливать зависимости между ними.

Как порождается CommonJS-класс

  • Все переменные и функции, объявленные в глобальной области видимости, становятся методами и свойствами класса. Присваивание значений переменных и прочий императивный код выносятся в конструктор класса.
  • Фактически, модификатор доступа для всех свойств и методов выставляется в public. Это поведение может быть изменено в будущих версиях и не следует использовать во внешнем коде свойства и методы, не помеченные модификатором export в исходном ts-коде.
  • Вложенные функции (т.е. объявленные не в глобальном модуле) превращаются в функциональные выражения и в них пробрасываются необходимые переменные через use().
  • Импорты других модулей превращаются в инструкции require_once с относительными путями.

Как порождается React-класс

  • Если функция в глобальной области модуля помечена аннотацией @elephizeTarget, она интерпретируется как функциональный React-компонент.
  • Для функционального компонента порождается отдельный класс, в который уходит вся логика, описанная внутри функции.
  • Если функциональному компоненту требуются какие-то данные из внешней области (пример: defaultProps), они получаются из исходного компонента модуля через доступ к его полям.
  • Каждый объект компонента на сервере является синглтоном. Таким образом можно получить объект компонента через статический метод getInstance(), если знать его класс и подключить файл с ним.
  • У каждого компонента декларируется публичный метод render(array $props, array $children). Его можно использовать для подключения изоморфных компонентов во внешнем коде, передавая в качестве $children пустой массив, а в качестве $props - массив с данными, необходимыми для рендеринга компонента. Написание отдельного серверного кода для получения $props, так же как и контроль над соответствием форматов данных, ложится на программиста.

Игнорирование модулей

В случае, если из изоморфного CommonJS-модуля импортируется некий файл, который не предполагается транспилировать, импорт следует занести в секцию ignoreImports (см. также инструкцию по конфигурации). Это однозначно необходимо для функций, которые замещаются кастомными серверными реализациями при помощи опции customGlobals. Необходимо помнить, что все не помеченные такой директивой импорты будут в обязательном порядке пройдены парсером и анализатором typescript, и в случае если они не предназначены для транспиляции - на выходе будет очень много ошибок.