40ants / reblocks

A fork of Weblocks Common Lisp web framework
https://40ants.com/reblocks/
Other
57 stars 10 forks source link

no page rendered using defroutes #56

Closed vajrabisj closed 5 months ago

vajrabisj commented 5 months ago

i tried many times, but i only can get page rendered through the init-page method....

i followed the quickstart guide, having: defwidget task, then constructor make-task, then render (task), and then (defroutes tasks-routes ("/tasks/" (make-task-list)) ("/tasks/task/" (make-task)))

the page only showed contents in the init-page function, those contents in the render method never showed...

need guidance...thanks.

svetlyak40wt commented 5 months ago

It is hard to help without being able to look at the actual code.

Could you create a temporary repository with all code you are trying to run?

vajrabisj commented 5 months ago

(defapp tasks :prefix "/")

(defwidget taskw () ((title :initarg :title :accessor title) (done :initarg :done :initform "false" :accessor done)))

(defun make-taskw () (make-instance 'taskw :title "changing the world" :done "false"))

(defmethod render ((task taskw)) "Render a task" (with-html (:span (title task) (format nil "done is") (done task))))

(defroutes tasks-routes ("/tasks/task/" (make-taskw)))

vajrabisj commented 5 months ago

It is hard to help without being able to look at the actual code.

Could you create a temporary repository with all code you are trying to run?

I found there are examples in your doc , maybe you could kindly let me know how to run those examples so I can learn by myself :)

vajrabisj commented 5 months ago

It is hard to help without being able to look at the actual code.

Could you create a temporary repository with all code you are trying to run?

by reviewing your doc example, finally i understood how to use your package :), sorry for disturbing and your package is really great!

svetlyak40wt commented 5 months ago

That is the reason why the documentation exists!

If you will find a way how it could be improved, please, let me know!

vajrabisj commented 5 months ago

Yes, that’s great. I am exploring your task examples. One think would like to check is how I can get synced task list from different devices, eg after I change the task list from laptop the page on my iPhone could get same result or vice versa…

Thanks in advance.

Regards,

Michael

Alexander Artemenko @.***>于2024年6月7日 周五21:00写道:

That is the reason why the documentation exists!

If you will find a way how it could be improved, please, let me know!

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2154788757, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J4NSTQARLCJ7WX6CDTZGGVGVAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJUG44DQNZVG4 . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 5 months ago

For doing this, you'll need each client to establish a connection to the server and also you'll need some event bus to push events to all listening widgets. Usually I'm using https://github.com/40ants/reblocks-websocket for the first task and https://github.com/fukamachi/event-emitter.

More simple solution is to have a small JavaScript code, which will call an action and reload your widget if some changes were discovered on the backend. Here is an example of a render method which implements this approach:

(defmethod render ((widget recent-comments-widget))
  (flet ((update-widget (&rest args)
           (declare (ignore args))
           (reblocks/widget:update widget)))
    (let* ((delay 1000)
           (action-code (fmt "setTimeout(function() {~A}, ~A)"
                             (reblocks/actions:make-js-action #'update-widget)
                             delay))
           (client (chat/client::connect (make-chat-api)))
           (messages (chat/client:get-random-messages client
                                                      :limit 5)))

      (with-html
        (:script
         (:raw action-code))

        (:div :class "xl:text-3xl text-l my-8"
              "Some data to be updated")))))

However it does not check if there were some updates, it refreshes the widget's content every 1 second.

vajrabisj commented 5 months ago

Thx a lot for your prompt reply, it’s helpful!

By learning your reblocks package I found the widget concept is great. One thing I have confuse is if several widgets have to update consequentially how to manage? For example, when :onclick triggered in widget A to show widget B just aside A. In widget A’s render method, it seems not able to pass the instance of widget B to make widget B got updated… any practice to solve this? Thx in advance.

Regards,

Michael

Alexander Artemenko @.***>于2024年6月8日 周六14:50写道:

For doing this, you'll need each client to establish a connection to the server and also you'll need some event bus to push events to all listening widgets. Usually I'm using https://github.com/40ants/reblocks-websocket for the first task and https://github.com/fukamachi/event-emitter.

More simple solution is to have a small JavaScript code, which will call an action and reload your widget if some changes were discovered on the backend. Here is an example of a render method which implements this approach:

(defmethod render ((widget recent-comments-widget)) (flet ((update-widget (&rest args) (declare (ignore args)) (reblocks/widget:update widget))) (let* ((delay 1000) (action-code (fmt "setTimeout(function() {~A}, ~A)" (reblocks/actions:make-js-action #'update-widget) delay)) (client (chat/client::connect (make-chat-api))) (messages (chat/client:get-random-messages client :limit 5)))

  (with-html
    (:script
     (:raw action-code))

    (:div :class "xl:text-3xl text-l my-8"
          "Some data to be updated")))))

However it does not check if there were some updates, it refreshes the widget's content every 1 second.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2155842380, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J6OWAMARSE7OEKLSNLZGKSVDAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJVHA2DEMZYGA . You are receiving this because you authored the thread.Message ID: @.***>

vajrabisj commented 5 months ago

I learned a lot from examples in reblocks and other related packages, really great! Thanks for your work!

If I want to put my reblocks app into production, how to make it standalone app so it can run into the system service in Linux. Should I use roswell? Or there is other solution?

Regards,

Michael

@.***>于2024年6月8日 周六17:53写道:

Thx a lot for your prompt reply, it’s helpful!

By learning your reblocks package I found the widget concept is great. One thing I have confuse is if several widgets have to update consequentially how to manage? For example, when :onclick triggered in widget A to show widget B just aside A. In widget A’s render method, it seems not able to pass the instance of widget B to make widget B got updated… any practice to solve this? Thx in advance.

Regards,

Michael

Alexander Artemenko @.***>于2024年6月8日 周六14:50写道:

For doing this, you'll need each client to establish a connection to the server and also you'll need some event bus to push events to all listening widgets. Usually I'm using https://github.com/40ants/reblocks-websocket for the first task and https://github.com/fukamachi/event-emitter.

More simple solution is to have a small JavaScript code, which will call an action and reload your widget if some changes were discovered on the backend. Here is an example of a render method which implements this approach:

(defmethod render ((widget recent-comments-widget)) (flet ((update-widget (&rest args) (declare (ignore args)) (reblocks/widget:update widget))) (let* ((delay 1000) (action-code (fmt "setTimeout(function() {~A}, ~A)" (reblocks/actions:make-js-action #'update-widget) delay)) (client (chat/client::connect (make-chat-api))) (messages (chat/client:get-random-messages client :limit 5)))

  (with-html
    (:script
     (:raw action-code))

    (:div :class "xl:text-3xl text-l my-8"
          "Some data to be updated")))))

However it does not check if there were some updates, it refreshes the widget's content every 1 second.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2155842380, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J6OWAMARSE7OEKLSNLZGKSVDAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJVHA2DEMZYGA . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 5 months ago

The easiest way is to use roswell. Usually I'm create a script like this one: https://github.com/ultralisp/ultralisp/blob/master/roswell/ultralisp-server.ros

Or you can use asdf:make.

I've described both ways in this video: https://www.youtube.com/watch?v=_V6cpOtP9e8

Usually I make my server to take all configuration parameters from unix environment, which makes it easy to pass these args from systemd or docker. Just use UIOP:GETENV function to retrieve a setting.

vajrabisj commented 5 months ago

thx, this is helpful and really thanks for your reply.

Regards,

Michael

Alexander Artemenko @.***>于2024年6月10日 周一16:40写道:

The easiest way is to use roswell. Usually I'm create a script like this one: https://github.com/ultralisp/ultralisp/blob/master/roswell/ultralisp-server.ros

Or you can use asdf:make.

I've described both ways in this video: https://www.youtube.com/watch?v=_V6cpOtP9e8

Usually I make my server to take all configuration parameters from unix environment, which makes it easy to pass these args from systemd or docker. Just use UIOP:GETENV function to retrieve a setting.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2157720996, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J55EGDS3KKLIUM2DLTZGVQ6LAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJXG4ZDAOJZGY . You are receiving this because you authored the thread.Message ID: @.***>

vajrabisj commented 5 months ago

I added the following code to the end of my tasks.lisp file:

(handler-case (bordeaux-threads:join-thread (find-if (lambda (th) (search "hunchentoot" (bordeaux-threads:thread-name th))) (bordeaux-threads:all-threads))))

And use “clackup tasks.lisp” to launch the app, everything’s fine.

But, when I put the clackup command line into systemd file and start it, you know what, strange things happened, I can successfully launch the webapp which has three routes, one of them is from your task list example. But only other two routes could be reached, the task list route got an error, but the whole web app is still running…

I don’t know why after put it to systemd got such error, whether it related to the code I posted at the beginning…

Regards,

Michael

Alexander Artemenko @.***>于2024年6月10日 周一16:40写道:

The easiest way is to use roswell. Usually I'm create a script like this one: https://github.com/ultralisp/ultralisp/blob/master/roswell/ultralisp-server.ros

Or you can use asdf:make.

I've described both ways in this video: https://www.youtube.com/watch?v=_V6cpOtP9e8

Usually I make my server to take all configuration parameters from unix environment, which makes it easy to pass these args from systemd or docker. Just use UIOP:GETENV function to retrieve a setting.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2157720996, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J55EGDS3KKLIUM2DLTZGVQ6LAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJXG4ZDAOJZGY . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 5 months ago

Probable reasons why a program running under systemd might fail:

vajrabisj commented 5 months ago

Hi, it’s me again :)

I am modifying your task example:) and plan to add a confirmation before proceeding task deletion, code as following:

(:input :type "submit" :class "button" :value "Delete" ;; Using make-js-handler to integrate Parenscript for confirmation dialog :onclick (reblocks-parenscript:make-js-handler :lisp-code ((&key confirmed) (when confirmed (del-task task))) :js-code ((event) (let ((confirmed (confirm "Are you sure you want to delete this task?"))) (parenscript:create :confirmed confirmed))))))

After running, I got an error of “unknown keywords :Action”, when I select ignore all unknown keywords, the deletion processed successfully. I cannot find the error, maybe in the js-code part? Thx in advance.

Regards,

Michael

Alexander Artemenko @.***>于2024年6月11日 周二16:26写道:

Probable reasons why a program running under systemd might fail:

  • it's working dir is different
  • it is runnings under another user (probably root)
  • environment variables are different – you have to specify them in the systemd config.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2160104183, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J4DIMYLTK7WDAVSTI3ZG2YDNAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRQGEYDIMJYGM . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 5 months ago

Change (&key confirmed) to (&key confirmed &allow-other-keys)

vajrabisj commented 5 months ago

Yes, got it ! Thx for your prompt reply on my silly questions:)

Regards,

Michael

Alexander Artemenko @.***>于2024年6月14日 周五18:36写道:

Change (&key confirmed) to (&key confirmed &allow-other-keys)

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2167745004, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J2ISO7YIZPULF6FRYDZHLBTZAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRXG42DKMBQGQ . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 5 months ago

Actually, you might expand reblocks-parenscript:make-js-handler form using SLIME/SLY to see the functions it creates for handling events.

vajrabisj commented 4 months ago

Hi, just curious that Is it possible to use CLOG package in reblocks?

Regards,

Michael

Alexander Artemenko @.***>于2024年6月14日 周五19:10写道:

Actually, you might expand reblocks-parenscript:make-js-handler form using SLIME/SLY to see the functions it creates for handling events.

— Reply to this email directly, view it on GitHub https://github.com/40ants/reblocks/issues/56#issuecomment-2167797498, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHAV3J7D7ABME5H3UL33M4DZHLFTFAVCNFSM6AAAAABI4SHNNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNRXG44TONBZHA . You are receiving this because you authored the thread.Message ID: @.***>

svetlyak40wt commented 4 months ago

I've never tried. In my opinion these frameworks are for different kind of tasks: reblocks is closer to traditional sites whereas CLOG tries to implement a desktop-like interface, but in the browser.

Theoretically, there should be a way to combine them, but I don't see any practical use case.