23

我正在尝试创建一个 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)

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

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

我以为我通过运行play获取交互式控制台找到了解决方案,然后

 project web
 run

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

注意:之前在Play Framework 的 Play 2.0 中作为 SBT Non-Root Module提出了类似的问题,但答案并不令人满意,我也不认为它在 Play 2.2 中仍然正确。

4

2 回答 2

15

如果

 play (entering shell)
 project web
 run

工作,那么你可以从命令行使它工作:

 play "project web" "run"

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

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

顺便说一句,我认为热重载的东西与 Play 无关。它是由 Play 使用的 SBT 提供的增量编译。我认为 play 命令只是一些被黑的 SBT 启动器。

以下命令对我来说很好:

 sbt "project web" "run"

它通过热重载启动 Play 项目。


我想你甚至可以使用

 sbt "project web" "~run"

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

于 2013-09-24T08:17:56.143 回答
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
  )
于 2014-12-11T14:54:44.767 回答