Николай Ланец
29 мая 2019 г., 18:19

Добавление кастомных компонентов в @prisma-cms/front-editor

Всем привет!

В продолжение прошлого комментария публикую статью как добавлять свои собственные компоненты во фронт-редактор. Сразу скажу, что материал не будет особо сложным, если вы уже боле менее знакомы с react и graphql (хотя второе здесь скорее всего и не обязательно в понимании).

Как развернуть у себя сайт на призме, подробно написано здесь, так что описание процесса установки я пропущу и сразу перейду к процессу кастомизации фронт-редактора, рассчитывая, что у вас уже сайт развернут.

Далее открываем файл /src/components/Renderer/pages/Root/index.js. В нем на сегодня уже прописано 3 кастомных компонента, вот на них вы и можете ориентироваться в качестве примеров. Как наиболее простой, мы рассмотрим /src/components/Renderer/pages/Root/components/pages/Users/User/index.js. Разберем его подробней.

static Name = "UserPage"

Это очень важный момент: я изначально заложил декларативный подход в определении компонентов, чтобы их можно было переопределять, и определение их происходит именно по этому свойству. То есть можно посмотреть имеющиеся базовые компоненты в @prisma-cms/front-editor, в каждом компоненте прописан свой static Name. И если у вас уже есть оформленные шаблоны на базовых компонентах и в какой-то момент вы захотите какие-то из них переопределить, то вам достаточно просто знать их имя и добавить свой компонент с таким именем в CustomComponents. После этого вам с шаблонами делать ничего не надо будет, они будут рендериться уже с вашим компонентом вместо базового.

renderPanelView()

Это оформление кнопки в панели компонентов. Здесь можно как угодно переоформить кнопку, можно вообще что угодно вывести (включая подробное описание и т.п.). Только обязательно рендерьте через super.renderPanelView(), потому что там навешиваются события клика и т.п.

Вообще здесь сразу имеет смысл упомянуть и метод renderSettingsView(), хоть его в примере и нет. Этот блок рендерится, когда вы выделяете какой-либо элемент в редакторе (там выводятся всякие параметры элемента и т.п.). Очень удобно, если вы захотите добавить какой-то кастомный вывод настроек для активного элемента.

renderChildren()

Выводит дочерние компоненты элемента на странице, то есть те, которые вы так же закидываете в режиме редактирования шаблона. В приведенном примере super.renderChildren() не вызывается, соответственно и дочерние компоненты накиданные выводиться не будут, даже если они есть.

Здесь пара важных замечаний по поводу передаваемых параметров при рендеринге компонента:

1.
const { parent, } = this.props;
Это отрендеренный родительский компонент. именно инстанс объекта, а не просто параметры. В данном случае я рассчитываю на то, что родительский элемент является роутером и передает условие с идентификатором запрошенного пользователя. Полный код:
renderChildren() { const { parent, } = this.props; if (!parent) { return false; } const { props: { match, }, } = parent; const { params: where, } = match || {}; if (!where) { return null; } return <CustomUserPage where={where} />; }
2. Свойства самого компонента при рендеринге.

Не знаю как долго будет использоваться этот костыль, но пока что по-другому просто не получилось. Чтобы получить не только входящие свойства компонента, передаваемые из родителя, но и те, что прописаны в настройках самого компонента, сохраняемых в базу данных, надо использовать не this.props, а this.getComponentProps(this), обязательно с передачей текущего инстанса this. Это сделано в том числе и для того, чтобы в панели настроек выводить параметры конкретного инстанса компонента, ведь исходный компонент один (к примеру, TextField), а инстансов на странице может быть несколько, и вот когда мы на странице кликаем конкретный элемент, то при рендеринге панели настроек мы должны получить входящие конкретного инстанса (тогда там передается не this, а activeItem, получаемый из this.getEditorContext()). Этот момент довольно запутанный, но сейчас можно и не разбираться особо, оставив до конкретного случая, если столкнетесь.

В принципе, я думаю необходимый минимум я передал. Просто попробуйте сами и наверняка станет более понятно. В принципе, если вам более привычно писать в самостоятельных компонентах все, вы можете задать свои кастомные компоненты, разместить их на странице в нужных местах и забыть про фронт-редактор, программируя свои компоненты. Но лично я считаю, что фронт-редактор решает не мало проблем. Для примера вспомните, как происходит редактирование шаблонов в большинстве случаев: клиент говорит "мне надо на странице вот это изменить, сделайте, плиз". Программист идет в программный код, ищет шаблоны, чанки, сниппеты и т.п., пытается понять откуда что берется и т.п. В случае же использования фронт-редактора, вы сразу видите где что откуда берется и что надо подправить, чтобы изменить шаблонизацию. Так что я буду дальше развивать это направление.
Фишка с редактором шаблонов классная. Учитывая, что у приложений и сайтов зачастую большинство компонентов на странице переиспользуемые, то визуально размещать их куда удобнее. Только тут есть несколько моментов, которые меня очень смущают и заставляют задуматься о выпиливании этого инструмента:
1) В первую очередь, это то, что он кушает много ресурсов процессора. Вот я кликаю на каком-то компоненте, у меня открывается слева панель с непонятными фреймами и 1.4 гигагерцовый процессор моей двенашки начинает мучаться. Не пойму, с чем это связано, но это заметно на прокрутке этого блока слева.
2) Я не совсем понимаю его интерфейс, в первую очередь вот этот выплывающий сайд слева. Что он делает, для чего он? Кнопочки на компонентах, что означает та или иная, ну и т.д.

P.S. Кстати, а почему кнопка "Редактировать шаблон" отображается у всех, включая не-админов?
На счет производительности: есть такое понятие как преждевременная оптимизация. Вот здесь я ее пока избегаю. Весь этот функционал - сплошной эксперимент. Когда я его начинал, у меня были идеи и потребности, но до сих пор нет окончательной мысли как это будет выглядеть в конечном итоге. Нет смысла оптимизировать то, что постоянно меняется и переделывается. Но несколько причин проблемы с производительностью мне известны:
1. React dev tools. На гитхабе не мало issue создано на счет низкой производительности. Скорее всего он использует в работе deep clone + lodash или типа того. react context позволяет передавать любые объекты, в том числе и классы компонентов. И вот так как в @prisma-cms в контекстах довольно много всякого, dev tools становится очень грустным и жутко тормозит. По этой причине он у меня давно уже отключен.
2. Довольно неоптимальный базовый класс компонентов фронт-редактора. Как я и говорил в статье, там не просто this.props используется, а своя костыльная логика, и скорее всего он так же дает лишней нагрузки (но по большей степени только в режиме редактирования. В обычном режиме там особой потери нет). Но повторюсь, когда логика устаканится, займусь его перепиливанием.
3. Работа со строками. Вот глянь вот эту статью: https://habr.com/ru/post/449368/. Уверен, в итоге придется и на этот счет серьезно прошерстить код.

В общем, да, проблемы с производительностью есть, но как и говорил, позже буду их обязательно решать, уверен, можно будет значительно поправить производительность. Сейчас же в режиме редактирования (тем более в dev-режиме, а не в production mode), надо и памяти не мало (в dev надо рассчитывать на гиг-два на вкладку), и процессор помощнее. У меня core i7 и 14Gb оперативы, относительно комфортно себя ощущаю.

На счет непонятных фреймов: вот здесь я писал, что отдельные части шаблонов можно сохранять в самостоятельные сущности и потом использовать на странице. Все их можно увидеть на странице /templates. Вот в редакторе в левой панели они и выводятся. Это для того, чтобы можно было вставить уже готовые блоки на странице. Это такой своего рода minecraft - создаешь отдельные небольшие куски, их можно использовать в формировании более крупных шаблонов, те еще и так далее. При чем там есть важная особенности при вставке: если просто кликнуть какой-либо готовый шаблон, то будет на странице вставлен весь его код (то есть скопирован). А если кликнуть кнопку "Вставить с ID (Insert with ID)" http://joxi.ru/D2PeVyqhqY6KZA, то будет вставлена ссылка на этот шаблон. То есть можно в нескольких частях страницы и на разных страницах повставлять ссылки на готовый шаблон, а потом редактировать в одном месте, и везде будет выводиться актуальный код. (это частичный ответ и на пункт 2 твоего вопроса).

>> Кнопочки на компонентах, что означает та или иная, ну и т.д.
Для этого я и сделал отдельный сайт, чтобы описать все основные компоненты фронт-редактора. В ближайшем будущем прям в кнопки добавлю ссылки на статьи, описывающие эти элементы. И для этого я и примеры привожу, чтобы было видно на более локальных шаблонах что как работает. Постепенно документация будет на каждый элемент. Ну а так, вопросы задавайте или экспериментируйте :) И смотрите исходный код компонентов. Подключенные компоненты перечислены здесь, оттуда можно найти путь до кода каждого компонента в отдельности, чтобы изучить непосредственно его код.
>> P.S. Кстати, а почему кнопка "Редактировать шаблон" отображается у всех, включая не-админов?

Забыл тебе ответить :)
Это я оставил специально, чтобы было видно редактор. А то итак не понятно что это такое, еще и видно не будет :) Но это отключается. В вызов RootConnector передай параметр clonable={false}. Тогда выводиться будет только для судо и для создателя шаблона.

Добавить комментарий