Giter Club home page Giter Club logo

elephize's Introduction

Elephize

Library and tool for transpiling limited set of React & Typescript constructions into PHP for use in server-side rendering.

Usage

NPM:

npm install -D @vkontakte/elephize or yarn add -D @vkontakte/elephize

Check error messages for peerDependencies errors, as elephize requires typescript to work.

Play with lib and demo (github):

git clone https://github.com/VKCOM/elephize.git

cd elephize && yarn

yarn demo_start

This will set up demo files in demo/public folder and run two servers:

  • React node server with native ReactDOM on port 3000
  • Php simple server with transpiled sources on port 8000

To see help, use bin/elephize --help or ./node_modules/.bin/elephize --help if you've installed elephize as a module.

You can use debugger; statement in your ts code to debug transpilation process and check context variables. When run with node debugger, this statement will pause the execution process when source file transpilation reaches the statement. It's useful to combine it with manual breakpoints to check particular cases.

Documentation (ru)

Описание проекта

Documentation (en)

Help wanted! If you have time to translate docs to english, please feel free to send us your PRs.

elephize's People

Contributors

ctizen avatar dependabot[bot] avatar fedorov-xyz avatar fix-fix avatar k-egor-smirnov avatar l1q avatar levenwadim avatar maksimr avatar mrzillagold avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elephize's Issues

Пример использования customGlobals

Не нашел информацию, как сделать имплементацию функции в каждом окружении (client-side и server-side) вручную, без транспиляции модуля

Выпилить warning для использования String.prototype.length

По опыту этот warning не имеет смысла. Чаще всего, длина строчки используется только в кейсе string.length !== 0. Потенциальная проблема еще актуальна, для нее нужно придумать какое-то другое решение отдельно. Например, получать длину строки тем же алгоритмом, что и в JS (тут есть возможные проблемы с кодировкой и emoji)

Удаление неиспользуемых деструктуризаций

Дано:

export const IconLeft = ({ ref }: Props) => {
  const onClick = () => {
    ref?.current?.scroll({ left: ref.current.scrollLeft - 50, behavior: 'smooth' });
  };

  return (
    <div onClick={onClick} className="ico--left">
      <Icon24 fill="rgba(153,162,173, 1)" />
    </div>
  );
};

Ожидаемый результат: переменная ref отсутствует в выводе, т.к. используется только внутри клиентского обработчика.
Фактический результат: в выводе есть присваивание переменной (как результат деструктуризации)

Значения по умолчанию в аргументах функций и деструктуризируемых значениях

Пример нерабочего кода:

function dvf(a: number, b: number = 123, c: boolean = true) {
  console.log(a, b, c);
}

function dvdo({a, b = 123, c = true}: { a: number, b?: number, c?: boolean }) {
  console.log(a, b, c);
}

function dvda([a, b = 123, c = true]: [number, number?, boolean?]) {
  console.log(a, b, c);
}

console.log(dvf(1));
console.log(dvdo({ a: 1 }));
console.log(dvda([1]));

Хочется поддержать эту фичу, т.к. она выглядит как часто используемая

Поддержать дополнительные атрибуты

Некоторые имена атрибутов в react отличаются от html-представления. Сейчас мы поддерживаем только перевод className в class, но это не единственный такой атрибут (есть еще htmlFor, например). Нужно найти список таких атрибутов и поддержать их всех.

Возможность описания правил в `importRules` через glob

Хочется уметь игнорировать целые папки и модули, в которых 100% неподдерживаемый код для транспиляции. Не проверял, возможно ли это сейчас, но было бы круто в этих glob поддержать алисы. Например,
"importRules": { "#helpers": { "ignore": true } }

Проблемы тайпкаста в пропсах

При деструктуризации пропсов, в PHP переменная кастится к базовому типу, даже если там пришел null (например, для типа foo?: string в PHP будет генерироваться код $foo = (string)$props['foo'].

Отличается результат сборки build и watch режима

В watch режиме некоторые mixed значения в PHPDoc заменяются другими (в моем случае, кажется, проставился @return string в месте, где ожидается mixed), а некоторые JSX тэги оборчиваются в IntrinsicElement::escape.

Возможно, причина первой ошибки в том, что у меня кастомный IntrinsicElement, где JSX возвращает mixed вместо string, а по-дефолту Elephize из JSX возвращает именно string

False positive ошибка компиляции props

При компиляции возникают ошибки вида Identifier "props" was used but was never declared. This is compile error
Проявляется для кода следующего вида:

interface Props { /* ... */ }

// @elephizeTarget
export const Component: React.FC<Props> = (props: Props) => { ... };

Лечится убиранием аннотации :Props из сигнатуры функции. Не очень нормальная ситуация, такая сигнатура должна быть допустима.

Ошибка при использовании компонента раньше его определения

При использовании компонента-функции до его определения, Elephize ругается, что не может найти ее определения. Баг НЕ воспроизводится при таких же условиях, если функции не являются React-компонентами

Воспроизведение (псевдокод):

// @elephizeTarget
function Usage() {
  return <Component />
}

// @elephizeTarget
function Component() {

}

Улучшить вывод типов

Комплексные типы вроде { [key: string]: string } могут быть более точно представлены как string[] на стороне php. Подумать какие еще варианты комплексных типов можно представить более точно. Рассмотреть возможные использования конструкции tuple()

Улучшить санитизацию пропсов

Такая защита от дурака наверно недостаточна, так как тут например может быть массив или ещё какое значение приводимое к опасной строке.

Вот пример TS-компонента, при котором использование компонента в PHP может привести к небезопасной вставке строки:

@@ -4,10 +4,15 @@
 const injection = `<img src=x onerror=alert()>`;
 
 // @elephizeTarget
-export const EscapeHtmlChars = ({ children }: { children: React.ReactNode[] }) => {
+export const EscapeHtmlChars = ({
+  children,
+  // Dangerous string from input or server, received from props
+  mixedValue = [injection]
+}: { children: React.ReactNode[], mixedValue?: string[] }) => {
   const arr = [1, 2, 3, 4];
   return (
     <div className="App">
+      <div>{mixedValue}</div>
       <h1>Hello CodeSandbox</h1>
       <h2>Start editing to see some magic happen!</h2>
       {arr.map((v) => <span>{injection}{v}</span>)}

Конкретных решений не предложу.

Может тогда вынести этот вопрос отдельным issue?

Originally posted by @fix-fix in #112 (comment)

Поддержать React.Context

  • Происследовать ограничения
  • Подготовить прототип
  • Согласовать с командой VKUI

Ошибочный генерированный код при обращении к this.

При обращении к свойствам this генерируется невалидный PHP-код.
Выражение вида this.property преобразуется в property["undefined"]

Пример TS input:

function test() {
  console.log(window.setTimeout); // OK
  // @ts-ignore
  console.log(this.setTimeout);
}

Пример PHP output:

public function test() {
    \VK\Elephize\Builtins\Console::log($window["setTimeout"]);
    \VK\Elephize\Builtins\Console::log(setTimeout["undefined"]);
}

Судя по доке this не поддерживается, но он всё равно может где-то использоваться в коде. И если его не запретить на уровне транспайлинга в PHP, то нужно поддерживать его кодген.
Само использование this почти всегда скорее невалидно, если не поддержаны классы, так что возможно вообще стоит при использовании this завершать транспайлинг ошибкой.

Сейчас же из-за ошибки генерируется невалидный PHP-код, который может не скомпилироваться в KPHP.

Улучшенная поддержка useMemo

Сейчас вызов useMemo просто отбрасывается, но это можно улучшить, если отбрасывать только мемоизацию, но оставить мемоизируемый на клиенте код.

Примерная схема работы:

  • взять первый аргумент useMemo - порождающую функцию
  • вытащить ее в анонимную функцию модуля
  • по месту использования вызвать ее для получения значения
  • остальные аргументы и сам вызов - дропнуть

Поддержать index-файлы

Сейчас мы требует четкого указания конкретного файла в импорте. Т.е. если имеем файл ./foo/index.ts, то

import { Foo } from './foo/index'; // работает
import { Foo } from './foo'; // не работает

Хочется поддержать это в сокращенной форме, не затаскивая полный резолвинг модулей из ноды.

  • Поддержать имена index.ts, index.tsx. Опционально: index.js, index.jsx
  • Обратить внимание на производительность, замерить время компиляции до и после правок
  • Может быть нетривиальная интеграция в ModuleRegistry и его окрестности, поскольку местами имя php-класса может зависеть от имени исходного файла, а имя php-файла - в свою очередь от имени php-класса. Надо проверять тут тщательным образом.
  • Опционально (но очень полезно): выдавать ошибку/предупреждение в случае, если найдено более одного файла с указанными именами одновременно. В общем случае это undefined behavior и ничего хорошего тут ждать нельзя

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.