fukamachi / ningle

Super micro framework for Common Lisp
http://8arrow.org/ningle/
273 stars 25 forks source link

Setting up routes for static content #36

Closed rajasegar closed 3 years ago

rajasegar commented 3 years ago

How can I serve static content with ningle? I have a static folder under my project root and keep the relevant static files in sub folders like css, js, images, etc., And I want to access them like:

<link rel="stylesheet" href="/css/main/css">
<script src="/js/main.js"></script>
<img src="/images/logo.png"/>
knobo commented 3 years ago

You could use static middleware https://github.com/fukamachi/lack

(setf *app*
  (lack:builder
    :session
    (:static :path "/public/"
             :root #P"/static-files/")
    (lambda (app)
      (lambda (env)
        (prog1 (funcall app env)
          (do-before-responding))))
    *app*))
rajasegar commented 3 years ago

@knobo I am afraid this is not working with my setup, I am actually using ningle instance to define routes, this is my app.lisp

(ql:quickload '(:ningle :djula :lack))
(djula:add-template-directory  #P"templates/")
(defparameter *template-registry* (make-hash-table :test 'equal))

;; render template - copied & modified from caveman
(defun render (template-path &optional data)
  (let ((html (make-string-output-stream))
    (template (gethash template-path *template-registry*)))
    (unless template
      (setf template (djula:compile-template* (princ-to-string template-path)))
      (setf (gethash template-path *template-registry*) template))
    (apply #'djula:render-template* template html data)
    `(200 (:content-type "text/html")
      (,(format nil "~a" (get-output-stream-string html))))))

(defvar *app* (make-instance 'ningle:app))

(setf (ningle:route *app* "/") (render #P"index.html"))
(setf (ningle:route *app* "/about") (render #P"about.html"))
(setf *app*
  (lack:builder
    :session
    (:static :path "/"
             :root #P"/static/")
    (lambda (app)
      (lambda (env)
        (prog1 (funcall app env)
          ;; (do-before-responding)
      )))
    *app*))

*app*

The route definitions are overridden when I setf app with lack builder

knobo commented 3 years ago

I guess #p"/static/" does not exist. try relative path instead.

rajasegar commented 3 years ago

This is the latest code

(ql:quickload '(:ningle :djula :lack))
(djula:add-template-directory  #P"templates/")
(defparameter *template-registry* (make-hash-table :test 'equal))

;; render template - copied & modified from caveman
(defun render (template-path &optional data)
  (let ((template (gethash template-path *template-registry*)))
    (unless template
      (setf template (djula:compile-template* (princ-to-string template-path)))
      (setf (gethash template-path *template-registry*) template))
    (apply #'djula:render-template* template nil data)))

(defvar *app* (make-instance 'ningle:app))

(setf (ningle:route *app* "/") (render #P"index.html"))

(setf *app* (lack:builder
 :session
 (:static :path "/"
          :root #P"static/")
 (lambda (app)
   (lambda (env)
     (funcall app env)))
 *app*))

*app*

Am I missing something?

knobo commented 3 years ago

I don't know. It's several years since I used this. But here is some code from one of my projects.

(defparameter *application-root*   (asdf:system-source-directory :myapp)
(defparameter *static-directory*   (merge-pathnames #P"static/" *application-root*)
;;;
;;;
;;; ....
 (:static
  :path (lambda (path)
          (if (ppcre:scan "^(?:/images/|/css/|/js/|/robot\\.txt$|/favicon\\.ico$)" path)
              path
              nil))
  :root *static-directory*)
knobo commented 3 years ago

You don't have to set the app at the end. builder returns the app. This works fine on my computer:

(ql:quickload '(:ningle :djula :lack))
(djula:add-template-directory  #P"templates/")
(defparameter *template-registry* (make-hash-table :test 'equal))

;; render template - copied & modified from caveman
(defun render (template-path &optional data)
  (let ((template (gethash template-path *template-registry*)))
    (unless template
      (setf template (djula:compile-template* (princ-to-string template-path)))
      (setf (gethash template-path *template-registry*) template))
    (apply #'djula:render-template* template nil data)))

(defvar *app* (make-instance 'ningle:app))

(setf (ningle:route *app* "/") (render #P"index.html"))

(lack:builder
 :session
 (:static :path "/pub/"
          :root #P"static/")
 :
 (lambda (app)
   (lambda (env)
     (funcall app env)))
 *app*)
$ ~/.roswell/bin/clackup app.lisp  --port 8080  
To load "ningle":
  Load 1 ASDF system:
    ningle
; Loading "ningle"
......
To load "djula":
  Load 1 ASDF system:
    djula
; Loading "djula"
......
To load "lack":
  Load 1 ASDF system:
    lack
; Loading "lack"

Hunchentoot server is going to start.
Listening on 127.0.0.1:8080.
127.0.0.1 - [04/Aug/2021:16:48:14 +02:00] "GET /pub/test.txt HTTP/1.1" 200 5 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0"
rajasegar commented 3 years ago

Super Awesome, @knobo Thanks a lot, that worked. Really appreciate the help.

NuclearKev commented 1 week ago

You don't have to set the app at the end. builder returns the app. This works fine on my computer:

(ql:quickload '(:ningle :djula :lack))
(djula:add-template-directory  #P"templates/")
(defparameter *template-registry* (make-hash-table :test 'equal))

;; render template - copied & modified from caveman
(defun render (template-path &optional data)
  (let ((template (gethash template-path *template-registry*)))
    (unless template
      (setf template (djula:compile-template* (princ-to-string template-path)))
      (setf (gethash template-path *template-registry*) template))
    (apply #'djula:render-template* template nil data)))

(defvar *app* (make-instance 'ningle:app))

(setf (ningle:route *app* "/") (render #P"index.html"))

(lack:builder
 :session
 (:static :path "/pub/"
          :root #P"static/")
 :
 (lambda (app)
   (lambda (env)
     (funcall app env)))
 *app*)
$ ~/.roswell/bin/clackup app.lisp  --port 8080  
To load "ningle":
  Load 1 ASDF system:
    ningle
; Loading "ningle"
......
To load "djula":
  Load 1 ASDF system:
    djula
; Loading "djula"
......
To load "lack":
  Load 1 ASDF system:
    lack
; Loading "lack"

Hunchentoot server is going to start.
Listening on 127.0.0.1:8080.
127.0.0.1 - [04/Aug/2021:16:48:14 +02:00] "GET /pub/test.txt HTTP/1.1" 200 5 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0"

hi @knobo , I don't mean to bring up an old thread but I've tried this example and it doesn't seem to work for me now. Did somethign change? I can't seem to get static files working at all with ningle.