Комментарии 21
Хм... Я к сожалению только начинающий в web разработке, но успел немного почитать первые статьи Пол Грэма, которые очень много говорят о Lisp, но в довольно старые времена, также Пол Грэм рассказывает о проблемах и перспективах Lisp и Web вцелом, затрагивает проблемы популярности новых ЯП и их использовании в разработке web-приложений. К сожалению проблему, которую обозначил Пол Грэм еще в далекие времена до сих пор актуальна – Web- приложения разрабатываются и поддерживаются на тех яп и технологиях, которые или популярны или по стечению обстоятельств должны использовать только их и никакие иначе, также сюда подключается проблема стоймости разработки, поддержки и переписывания какого-либо уже работающего продукта на непопулярный яп.
В силу недостаточных знаний, в общих чертах я понял Вашу идею. На мой взгляд довольно интересное решение. Очень интересно почитать продолжение Вашей разработки современного web-приложения на Lisp, особенно интересен результат в том на сколько конкурентноспособно будет приложение по сравнению с современными фреймворками? Большой удачи и терпения Вам, надеюсь найдутся компетентные помошники✊
Я не собираюсь конкурировать с другими фреймворками, боже упаси) Вообще, мое глубокое убеждение в том, что с языком, средой и библиотеками не нужно бороться, нужно их использовать! OMG можно прикрутить к любому уже существующему сайту, добавив загрузку одного js-файла и дальше выполнять на странице любой LISP-код, параллельно со всем остальным кодом. Также, поскольку мы имеем полный доступ к DOM и JS, можно использовать любые JS-фреймворки, просто вызывая их функции. Я не стал раздувать статью, но в omgui.lisp есть код, подключающий API YouTube и позволяющий добавить плеер на страницу. То же можно сделать и со всякими React-ами и прочими jquery, не к ночи будь помянуты.
(ql:quickload :omg)
System «omg» not found
а может просто нет там омг
(ql:system-apropos «omg»)
ничего не выдаёт.
а как поместить в local-projects не знаю
сейчас там лежит пустой system-index.txt
УПД
надо было сделать (ql:update-dist «quicklisp»)
Sorry
УПД2
И даже всё работает!
Windows 10, sbcl 2.0.0
О! Библиотека работает на Windows! Неожиданно)
Возможно вас заинтересует PicoLisp (https://picolisp.com), самодостаточный и уже очень давно дружит с вебом и умеет много интересных вещей.
Интересная реализация, спасибо! Но я пока еще не готов заниматься портированием. Есть шанс, конечно, что там всё само заработает, но я сомневаюсь. Похоже, там свой FFI, если он не поддерживается нужными мне пакетами (в основном, clack, bordeaux-threads и пр.), то придется затратить довольно много усилий.
Любопытная статья. Я примерно такое-же реализую, но для Smalltalk.
После создания элемента через OMG он храниться в каком-то серверной версии DOM-дерева? Или всё отправляется в броузер сразу? Как получить у созданного элемента свойство clientHeight/clientWidth через OMG? Надо посылать специальный запрос в броузер?
О, Smalltalk, мое уважение!
Элемент создается кодом, который выполняется в браузере, соответственно, он хранится в браузере и больше нигде. Можно сохранить ссылку на этот объект и использовать ее для получения свойств:
(let ((el (create-element "div" :|innerHTML| "Hello world!")))
(ensure-element el ;; execute the following code when the element really appears
(jslog (jscl::oget el "clientHeight"))))
Если же мне надо будет зачем-то узнать высоту элемента на бэкенде, я должен явно запросить ее у браузера или пусть браузер вызовет RPC и сообщит:
(defun-r rpc-report-height (height)
(format t "The height is ~A px!~%" height))
(defparameter-f *my-div* nil)
(defun-f get-div-height ()
(jscl::oget *my-div* "clientHeight"))
(defun-f make-div ()
(setf *my-div* (create-element "div" :|innerHTML| "Hello world!"))
(ensure-element *my-div*
(rpc-report-height (get-div-height)))
nil)
(make-div) ;; The #'rpc-report-height must be fired
(sleep 1)
(print (get-div-height)) ;; call browser-side function
В принципе, бэкенд не контролирует браузер на 100%, просто дает ему команды и браузер их выполняет. Я даже хочу реализовать "production mode", когда сокет вообще не открывается, а браузер сразу получает весь код, скомпилированный и упакованный, оставив текущую схему для разработки/отладки, а также для приложений, где важна интерактивность.
Ясно.
Честно говоря я слабо знаю Lisp.
Как я понял: создаётся div и сразу после создания на сервер отправляется его clientHeight.
Хорошо. А как запросить у броузера информацию Вы уже продумывали механизм?
Я лично у себя использую websocket-соединение чтоб общаться с броузером. Но он асинхронный. И это создаёт сложности. В данный момент я просто делаю wait в коде пока не придёт ответ от броузера. Других удобных способов я не нашёл пока-что.
У меня, собственно, нет никаких особых протоколов общения -- я через вебсокет посылаю в браузер JS-код, браузер его выполняет и возвращает ответ через тот же вебсокет, всё. А уж код может создать элемент, вернуть высоту элемента, всё что угодно. Код пишется тоже на лиспе и потом компилируется (на хосте) в JS перед отправкой.
Попробуй добавить свой проект на мой Ultralisp.org. Там dist будет обновляться сразу после пуша в Git репозиторий.
А ещё хочу упомянуть пару библиотек – Reblocks (она позволяет писать всю бизнес-логику на Common Lisp и запускает её на бэкенде, а на фронт отдаёт команды, как поменять DOM дерево), а так же CLOG – она вроде больше похожа на твой OMGlib, только более продвинутая на данный момент.
Спасибо за наводку! Добавил два проекта в ultralisp, но с OMGlib там проблемы -- возможно, ultralisp не умеет правильно скачивать сабмодули git, а у меня так JSCL добавлен. У JSCL вообще нет asdf и я использую слегка грязноватый хак для того, чтобы включить его в свой пакет (см. omg.asd). С quicklisp это работает.
Что касается Reblocks и CLOG -- я видел эти проекты, хотя и не погружался в них глубоко. Главное отличие OMG -- возможность переноса практически всей интерфейсной логики на сторону клиента, при этом сохраняя единый lisp-образ на сервере, где его можно модифицировать и это сразу* отображается на стороне клиентов. В принципе, если приложение не зависит от бэкенда (например, оно использует API каких-то чужих сервисов), то его можно (пока это не реализовано, правда) вообще отвязать от сервера, сделав автономным.
Вообще, изначально, я хотел сделать что-то более общее, когда есть мастер-образ lisp, который передает lisp-код в подчиненные lisp-образы, которые запущены на клиентах (например, в мобильниках) и код там выполняется, отрисовывая интерфейсы и исполняя всю интерфейсную логику, какую возможно, локально. Это не обязательно могут быть интерфейсы, скажем, можно так подключить lisp-образы, запускаемые в контейнерах на удаленных серверах и производить там всякие тяжелые вычисления по мере надобности. То есть ботнет-подобная сеть, по сути, но используемая в мирных целях).
Благодаря особенностям Lisp (потому я и выбрал этот язык, хотя слабо им владею) можно всё это делать внутри одного образа, писать, по сути, сплошной код, помечая лишь определенные функции, как выполняемые где-то еще. Пока что эта идея еще в зачаточном состоянии, в основном потому, что у меня нет прикладной задачи, где можно было бы ее применить в полном объеме, но когда такая задача появится, я ее разовью дальше)
Также этот подход (хоть и менее удобно) можно применить в питоне, например, там есть компилятор в JS и можно получить доступ к синтаксическому дереву. Но я не хочу быть тем, кто откроет ящик Пандоры, дав питонистам в руки такую технологию)
Да, сейчас Ultralisp.org действительно не выкачивает GIT сабмодули и я не натыкался на проекты которые бы не работали из-за этого :)
Думаю это не сложно будет поддержать. Попробую добавить на днях.
А вообще идея с использованием JSCL прикольная. У меня для Reblocks иногда приходится писать какой-нибудь JS код, но я для этого использую Parenscript.
Скажи, а как у тебя реализована работа с DOM на стороне клиента? Вызов стандартных JS функций и тд. Я бы с удовольствием тоже заиспользовал JSCL вместо Parenscript.
да прямо как в JS, через FFI JSCL:
((jscl::oget (jscl::%js-vref "document") "body" "appendChild")
((jscl::oget (jscl::%js-vref "document") "createElement") "div"))
Но чтобы не видеть этого безобразия я сделал небольшую библиотечку omgui (часть OMGlib), где это делается так:
(append-element
(create-element "div" :|innerHTML| "Hello world!"
:|style.padding| "1em"
:|style.background| "red"))
Можно сохранять полученные DOM-элементы в локальных (внутри браузера) переменных и потом с ними делать что угодно.
LISP-пакет OMGlib или вперёд к Web 3.0