没有重新启动Web服务器的Compojure开发

aur*_*amo 36 clojure compojure

我之前在Clojure中编写了一个小型Swing应用程序,现在我想创建一个Ajax风格的Web应用程序.Compojure现在看起来是最好的选择,所以这就是我要尝试的.

我想要一个真正的小编辑/尝试反馈循环,所以我不希望在每次小改变后重启web服务器.

实现这一目标的最佳方法是什么?默认情况下,我的Compojure设置(使用带有Jetty的ant deps/ant的标准内容)似乎没有重新加载我所做的任何更改.我将不得不重新启动run-server来查看更改.由于Java遗产和系统启动的方式等.这可能是完全正常的,当我从命令行启动系统时应该是这样.

但是,必须有一种方法可以在服务器运行时动态地重新加载内容.我应该使用REPL的Compojure来实现我的目标吗?如果我应该,我怎么重新加载我的东西?

小智 38

这是一个相当古老的问题,最近有一些变化使这更容易.

您需要两件主要的事情:

  1. 控件应返回到REPL,以便您可以继续与服务器进行交互.这是通过添加{:join?启动Jetty服务器时的选项.
  2. 您希望在文件更改时自动获取某些命名空间中的更改.这可以通过Ring的"wrap-reload"中间件来完成.

玩具应用程序看起来像这样:

(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))
Run Code Online (Sandbox Code Playgroud)

wrap-reload函数使用检测列出的命名空间中的更改的函数来装饰您的应用程序路由.处理请求时,如果磁盘上的这些命名空间已更改,则会在进一步请求处理之前重新加载它们.(我的"视图"命名空间是由Fleet动态创建的,因此,只要它们发生更改,它就会自动重新加载我的模板.)

我添加了一些我发现始终有用的其他中间件.wrap-file处理静态资产.wrap-file-info设置这些静态资产的MIME类型.wrap-stacktrace有助于调试.

从REPL,您可以通过使用命名空间并直接调用start-server来启动此应用程序.:gen-class关键字和-main函数意味着app也可以从REPL之外打包为uberjar用于启动.(在REPL之外还有一个世界?好吧,有些人反正要求它......)

  • 我可以建议每个例子都提到所需的环等版本.谢谢! (2认同)

aur*_*amo 22

以下是我在Compojure Google Group中获得James Reeves的答案(答案在他的允许下):

您可以使用use或require命令上的:reload键在Clojure中重新加载命名空间.例如,假设您有一个包含路线的文件"demo.clj":

(ns demo 
  (:use compojure))

(defroutes demo-routes 
  (GET "/" 
    "Hello World") 
  (ANY "*" 
    [404 "Page not found"])) 
Run Code Online (Sandbox Code Playgroud)

在REPL中,您可以使用此文件并启动服务器:

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

您还可以将run-server命令放在另一个clojure文件中.但是,您不希望将其与要重新加载的内容放在同一文件中.

现在对demo.clj进行一些更改.在REPL类型:

user=> (use 'demo :reload) 
nil 
Run Code Online (Sandbox Code Playgroud)

您的更改现在应显示在http:// localhost:8080上


emi*_*001 13

我想添加一个答案,因为自最新的答案以来我已经有了一些改变,我花了一些时间自己寻找.

  1. 安装leiningen(只需按照那里的说明)

  2. 创建项目

    lein new compojure compojure-test 
    
    Run Code Online (Sandbox Code Playgroud)
  3. 编辑project.clj的ring部分

    :ring {:handler compojure-test.handler/app 
           :auto-reload? true
           :auto-refresh? true}
    
    Run Code Online (Sandbox Code Playgroud)
  4. 在您想要的任何端口上启动服务器

    lein ring server-headless 8080
    
    Run Code Online (Sandbox Code Playgroud)
  5. 检查服务器是否在您的浏览器中运行,默认基本路由应该只是说"Hello world".接下来,去修改你的处理程序(它在src/project_name中).更改hello world文本,保存文件并在浏览器中重新加载页面.它应该反映新的文本.


cem*_*ick 5

继Timothy与Jim Downing设置的链接之后,我最近发布了对该基线的一个重要补充,我发现这对于在开发过程中自动重新部署compojure应用程序是必要的.


Tim*_*ley 3

这高度依赖于配置,但对我有用,我认为你可以调整它:

  1. 将 compojure.jar 和 compojure/deps 目录下的 jar 放在您的类路径中。我使用 clojure-contrib/launchers/bash/clj-env-dir 来执行此操作,您所需要做的就是在 CLOJURE_EXT 中设置目录,它将找到 jar。CLOJURE_EXT 以冒号分隔的目录路径列表,其顶级内容是(直接或作为符号链接)jar 文件和/或路径位于 Clojure 类路径中的目录。

  2. 启动 Clojure REPL

  3. 从 compojure 根目录粘贴 hello.clj 示例

  4. 检查本地主机:8080

  5. 重新定义greeter(defroutesgreeter(GET "/"(html[:h1"Goodbye World"])))

  6. 检查本地主机:8080

还有一些方法可以将 REPL 附加到现有进程,或者您可以将套接字 REPL 嵌入到服务器中,甚至可以定义一个 POST 调用,该调用将动态评估,以允许您从浏览器本身重新定义函数!有很多方法可以解决这个问题。