clojure compojure

clojure - Desarrollo de Compojure sin reinicios del servidor web



(8)

He escrito una pequeña aplicación Swing antes en Clojure y ahora me gustaría crear una aplicación web estilo Ajax. Compojure parece la mejor opción en este momento, así que eso es lo que voy a probar.

Me gustaría tener un verdadero ciclo de retroalimentación de edición / prueba, así que preferiría no reiniciar el servidor web después de cada pequeño cambio que hago.

¿Cuál es la mejor manera de lograr esto? De manera predeterminada, mi configuración de Compojure (las cosas estándar con hormigas / hormigas con Jetty) no parece volver a cargar los cambios que hago. Tendré que reiniciar con el servidor de ejecución para ver los cambios. Debido a la herencia de Java y la forma en que se inicia el sistema, etc. Esto es probablemente perfectamente normal y como debería ser cuando inicio el sistema desde la línea de comandos.

Aún así, debe haber una manera de volver a cargar cosas dinámicamente mientras el servidor se está ejecutando. ¿Debo usar Compojure de REPL para lograr mi objetivo? Si debería, ¿cómo recargo mis cosas allí?


Aquí hay una respuesta que obtuve de James Reeves en Compojure Google Group (la respuesta está aquí con su permiso):

Puede volver a cargar un espacio de nombre en Clojure usando la tecla: recargar en los comandos de uso o requerimiento. Por ejemplo, supongamos que tiene un archivo "demo.clj" que contiene sus rutas:

(ns demo (:use compojure)) (defroutes demo-routes (GET "/" "Hello World") (ANY "*" [404 "Page not found"]))

En REPL, puede usar este archivo e iniciar un servidor:

user=> (use ''demo) nil user=> (use ''compojure) nil user=> (run-server {:port 8080} "/*" (servlet demo-routes)) ...

También podría poner el comando run-server en otro archivo clojure. Sin embargo, no desea colocarlo en el mismo archivo que las cosas que desea volver a cargar.

Ahora realice algunos cambios en demo.clj. En el tipo REPL:

user=> (use ''demo :reload) nil

Y sus cambios ahora deberían aparecer en http: // localhost: 8080


Compojure usa el ring interno (por el mismo autor), las opciones del servidor web en anillo permiten el realojado automático. Entonces dos alternativas serían:

lein ring server lein ring server-headless lein ring server 4000 lein ring server-headless 4000

Tenga en cuenta que :

Necesitas tener una línea en tu archivo project.clj que se ve así:
: ring {: handler your.app/handler}


Esta es una pregunta bastante antigua, y ha habido algunos cambios recientes que hacen esto mucho más fácil.

Hay dos cosas principales que desea:

  1. El control debe regresar a REPL para que pueda seguir interactuando con su servidor. Esto se logra agregando {: join? falso} a opciones al iniciar el servidor Jetty.
  2. Desea detectar cambios automáticamente en ciertos espacios de nombres cuando cambian los archivos. Esto se puede hacer con el middleware "wrap-reload" de Ring.

Una aplicación de juguete se vería así:

(ns demo.core (:use webui.nav [clojure.java.io] [compojure core response] [ring.adapter.jetty :only [run-jetty]] [ring.util.response] [ring.middleware file file-info stacktrace reload]) (:require [compojure.route :as route] view) (:gen-class)) ; Some stuff using Fleet omitted. (defroutes main-routes (GET "/" [] (view/layout {:body (index-page)}) (route/not-found (file "public/404.html")) ) (defn app [] (-> main-routes (wrap-reload ''(demo.core view)) (wrap-file "public") (wrap-file-info) (wrap-stacktrace))) (defn start-server [] (run-jetty (app) {:port 8080 :join? false})) (defn -main [& args] (start-server))

La función de ajuste y recarga decora las rutas de su aplicación con una función que detecta cambios en los espacios de nombres listados. Al procesar una solicitud, si esos espacios de nombres han cambiado en el disco, se vuelven a cargar antes de solicitar más procesamiento. (Mi espacio de visualización "de mi vista" es creado dinámicamente por Fleet, por lo que esto recarga automáticamente mis plantillas siempre que cambien).

Agregué algunas otras piezas de middleware que encontré consistentemente útiles. wrap-file maneja los activos estáticos. wrap-file-info establece el tipo MIME en esos activos estáticos. wrap-stacktrace ayuda en la depuración.

Desde REPL, puede iniciar esta aplicación utilizando directamente el espacio de nombres y llamando al servidor de inicio. La palabra clave gen-class y la función -main significan que la aplicación también se puede empaquetar como un uberjar para el inicio desde fuera del REPL, también. (¿Hay un mundo fuera del REPL? Bueno, algunas personas lo han pedido de todos modos ...)


Esto depende mucho de la configuración pero funciona para mí y creo que puedes adaptarlo:

  1. Coloque compojure.jar y los archivos jar en el directorio compojure / deps en su classpath. Yo uso clojure-contrib / launchers / bash / clj-env-dir para hacer esto, todo lo que necesitas hacer es establecer el directorio en CLOJURE_EXT y encontrará los archivos jar. CLOJURE_EXT Lista delimitada por dos puntos de las rutas a directorios cuyos contenidos de nivel superior son (ya sea directamente o como enlaces simbólicos) archivos jar y / o directorios cuyas rutas estarán en el classpath de Clojure.

  2. Lanzamiento clojure REPL

  3. Pegue el ejemplo hello.clj del directorio raíz de compojure

  4. Ver localhost: 8080

  5. Redefina el greeter (defroutes greeter (GET "/" (html [: h1 "Adiós mundo"])))

  6. Ver localhost: 8080

También hay métodos para adjuntar un REPL a un proceso existente, o puede mantener un socket REPL incrustado en su servidor o incluso podría definir una llamada POST que evaluará sobre la marcha para permitirle redefinir funciones desde el navegador mismo. Hay muchas formas de abordar esto.


Me gustaría hacer un seguimiento de la respuesta de mtnygard y publicar el archivo project.clj completo y el archivo core.clj que funcionan. Se hicieron algunas modificaciones, y es más barebones

comandos de preconfiguración

lein new app test-web cd test-web mkdir resources

project.clj

(defproject test-web "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.5.1"] [compojure "1.1.6"] [ring "1.2.1"]] :main ^:skip-aot test-web.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})

core.clj

(ns test-web.core (:use [clojure.java.io] [compojure core response] [ring.adapter.jetty :only [run-jetty]] [ring.util.response] [ring.middleware file file-info stacktrace reload]) (:require [compojure.route :as route]) (:gen-class)) (defroutes main-routes (GET "/" [] "Hello World!!") (GET "/hello" [] (hello)) (route/not-found "NOT FOUND")) (def app (-> main-routes (wrap-reload ''(test-web.core)) (wrap-file "resources") (wrap-file-info) (wrap-stacktrace))) (defn hello [] (str "Hello World!")) (defn start-server [] (run-jetty #''app {:port 8081 :join? false})) (defn -main [& args] (start-server))

Preste atención al cambio de (defn aplicación ...) a (def aplicación ...)

Esto fue crucial para hacer que el servidor Jetty funcione correctamente


Quería agregar una respuesta, ya que las cosas han cambiado un poco desde la última respuesta y había pasado un poco de tiempo buscándolo yo mismo.

  1. Instale leiningen (solo siga las instrucciones)

  2. Crear proyecto

    lein new compojure compojure-test

  3. Edite la sección de anillo de project.clj

    :ring {:handler compojure-test.handler/app :auto-reload? true :auto-refresh? true}

  4. Inicie el servidor en el puerto que desee

    lein ring server-headless 8080

  5. Verifique que el servidor se esté ejecutando en su navegador, la ruta base predeterminada debería simplemente decir "Hola mundo". A continuación, vaya a modificar su controlador (está en src / project_name). Cambie el texto de Hello World, guarde el archivo y vuelva a cargar la página en su navegador. Debería reflejar el nuevo texto.



Tengo un script de shell que se ve así:

#!/bin/sh CLASSPATH=/home/me/install/compojure/compojure.jar CLASSPATH=$CLASSPATH:/home/me/clojure/clojure.jar CLASSPATH=$CLASSPATH:/home/me/clojure-contrib/clojure-contrib.jar CLASSPATH=$CLASSPATH:/home/me/elisp/clojure/swank-clojure for f in /home/me/install/compojure/deps/*.jar; do CLASSPATH=$CLASSPATH:$f done java -server -cp $CLASSPATH clojure.lang.Repl /home/me/code/web/web.clj

web.clj se parece a esto

(use ''[swank.swank]) (swank.swank/ignore-protocol-version "2009-03-09") (start-server ".slime-socket" :port 4005 :encoding "utf-8")

Cada vez que quiero actualizar el servidor, creo un túnel ssh desde mi máquina local a la máquina remota.

Enclojure y Emacs (que ejecutan SLIME + swank-clojure) pueden conectarse a la REPL remota.