如何创建一个Play 2.2 Scala应用程序作为SBT子项目

时间:2013-09-23 21:10:44

标签: playframework sbt

我正在尝试创建一个包含库项目的Scala应用程序(让我们称之为common),一个Thrift服务器项目(让我们称之为server)和一个Play web应用程序项目(以下称为作为web)。这三个都是用Scala编写的,并用sbt。

构建

我的项目结构如下:

myproject/
-common/
  ...
-server/
  ...
-web/
  -app/
  -conf/
  ...
-project/
  -Build.scala
  -build.properties
-build.sbt

我的build.sbt文件(简化了一下)如下所示:

import play.Project._

name := "myproject"

version := "1.0-SNAPSHOT"

lazy val common = project

lazy val web = project
    .settings(playScalaSettings: _*)
    .dependsOn(common)

lazy val server = project
    .dependsOn(common)

lazy val root = project.in(file("."))
    .aggregate(common, web, server)

这个问题是根项目不是Play项目,因此play命令不起作用(它出错

java.lang.RuntimeException: */*:playRunHooks is undefined.
at scala.sys.package$.error(package.scala:27)

如果我在SBT文件中的playScalaSettings行之后插入行version,我可以通过使根项目看起来像Play项目来解决这个问题,但是我还有另一个问题:{{ 1}}命令尝试运行根项目,而不是play run子项目。显然,web命令在play run子目录中运行时不起作用,因为那里没有SBT文件来描述项目及其依赖项。

我正在寻找一种解决方案,允许我保留这个项目结构(意味着Play项目是我的应用程序中的众多子项目之一),同时保留所有Play框架热点,如代码更改时的热更新(甚至代码)在依赖库中,如web)。

我以为通过运行common来获取交互式控制台,然后

,我找到了解决方案
play

这样可行,但它在命令行上不起作用。 project web run 由于某种原因运行根级play web/run命令,如上所述,该命令不起作用,因为根应用程序不是Play应用程序。

注意:之前在Play Framework as SBT Non-Root Module的Play 2.0上下文中提出了一个类似的问题,但答案并不令人满意,我认为从Play 2.2开始,它仍然没有问题。

2 个答案:

答案 0 :(得分:14)

如果

 play (entering shell)
 project web
 run

工作,然后您可以从命令行使其工作:

 play "project web" "run"

您可以在命令行中执行shell中的任何操作。

我有相同的项目结构,这样做的方式对我来说很好。

顺便说一句,我不认为热重载内容与Play有关。它是由SBT提供的增量编译,由Play使用。 play命令只是我认为的一些黑客SBT发射器。

以下命令对我有效:

 sbt "project web" "run"

它以热重载启动Play项目。


我认为你甚至可以使用

 sbt "project web" "~run"

每次更改源文件时都会尝试重新编译,而不是等待浏览器刷新,并且会赢得一些时间。

答案 1 :(得分:0)

我认为这是Play 2.2中的一个错误,因此我将其报告为Error "/:playRunHooks is undefined" on running as web/run。 它似乎已经在2.3.x中得到修复,因此它很可能不会被修复为2.2。我提出了一些讨厌的解决方法:

lazy val root = (project in file(".")).
  settings(
    playRunHooks := Nil,
    playInteractionMode := play.PlayConsoleInteractionMode,
    playDefaultPort := 9000,
    playMonitoredFiles := (Def.taskDyn {
      val s = state.value
      s.history.current.split("/").headOption match {
        case Some(ref) =>
          Def.task {
            (playMonitoredFiles in LocalProject(ref)).value
          }
        case _ =>
          Def.task {
            playMonitoredFiles.value
          }
      } 
    }).value
  )