更改放置某些生成资源的位置

时间:2016-06-29 19:04:58

标签: scala sbt scala.js

我目前有两个项目;一个用于服务器端(Akka-HTTP),另一个用于客户端(ScalaJS)。客户端使用服务器端生成我想要提供的.js个文件。为了让服务器端访问这些文件,我在服务器端项目中添加了这个build.sbt条目:

lazy val server = project.in(file("server"))
  ...
  .settings(
    (resourceGenerators in Compile) <+= Def.task {
      val f1 = (fullOptJS in client).value.data
      val f1sm = f1.getParentFile / (f1.getName + ".map")
      f1 :: f1sm :: (packageMinifiedJSDependencies in client).value :: Nil
    }
  )

但是,这会将.js.map文件放在classes文件夹的根目录中。因为我想像我这样服务我的资产:

pathPrefix("assets") {
  ...
  pathPrefix("client") {
    getFromResourceDirectory("<directory where .js and .map files are placed>")
  }
}

强调#getFromResourceDirectory方法,这不适用于我的classes文件夹根目录中的资源。我的application.conf与生成的文件位于同一目录中,这使得全世界都可以看到它。

我想要的是.js目录的子目录中的.mapclasses个文件。像client/这样的东西,所以我可以使用像#getFromResourceDirectory这样的getFromResourceDirectory("client")方法,不要担心我的配置文件可供外界使用。

我的问题 - 如何实现这一目标?

我已经尝试添加:

lazy val client = project.in(file("client"))
  ...
  .settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
    .map(a => (crossTarget in a) ~= (_ / "client")))
  )

到我的客户端项目,它只将生成的.js.map文件放在客户端项目的客户端文件夹中scala-2.11文件夹中:

client-side target overview

但该设置不会传播到服务器端项目classes文件夹:

server-side target overview

这是理想的情况:

server-side target overview desired

2 个答案:

答案 0 :(得分:3)

潜入SBT让我走下一条路;首先,我检查了server/compile:resourceGenerators(使用sbt inspect server/compile:resourceGenerators):

[info] ...
[info] Dependencies:
[info]  server/compile:discoveredSbtPlugins
[info]  server/compile:resourceManaged
[info]  client/compile:packageMinifiedJSDependencies
[info]  client/compile:fullOptJS
[info] Reverse dependencies:
[info]  server/compile:managedResources
[info] ...

然后我检查了server/compile:managedResources

[info] ...
[info] Dependencies:
[info]  server/compile:resourceGenerators
[info] Reverse dependencies:
[info]  server/compile:resources
[info] ...

然后我检查了server/compile:resources

[info] ...
[info] Dependencies:
[info]  server/compile:managedResources
[info]  server/compile:unmanagedResources
[info] Reverse dependencies:
[info]  server/compile:copyResources
[info] ...

然后我检查了server/compile:copyResources

[info] ...
[info] Defined at:
[info]  (sbt.Defaults) Defaults.scala:295
[info] Dependencies:
[info]  server/compile:classDirectory
[info]  server/compile:resources
[info]  server/compile:resourceDirectories
[info]  server/compile:copyResources::streams
[info] ...

然后我在第295行检查了SBT的Defaults.scala文件:

copyResources <<= copyResourcesTask

然后我检查了这个copyResourcesTask定义:

def copyResourcesTask =
  (classDirectory, resources, resourceDirectories, streams) map { (target, resrcs, dirs, s) =>
    val cacheFile = s.cacheDirectory / "copy-resources"
    val mappings = (resrcs --- dirs) pair (rebase(dirs, target) | flat(target))
    s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t", "\n\t", ""))
    Sync(cacheFile)(mappings)
    mappings
  }

mappings val在这种情况下非常重要。它创建由负责所有资源的各种任务创建的路径与这些资源将在target文件夹中接收的最终路径之间的映射。 #rebase方法(主要)负责这些映射,但如果资源路径中没有单个resourceDirectories条目,则它会回退到#flat方法。只需将我的客户端项目的crossTarget路径添加到resourceDirectories设置,rebase就会替换所有内容,直到client/<filename>.js的{​​{1}}部分为止。文件而不是在.map方法上退回,只替换#flat部分,并结合此设置:

<filename>

正是我想要的行为。

TL; DR

添加到您的客户端项目:

lazy val client = project.in(file("client"))
  ...
  .settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
    .map(a => (crossTarget in a) ~= (_ / "client")))
  )

添加到服务器端项目:

.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
  .map(a => (crossTarget in a) ~= (_ / "client")))
)

答案 1 :(得分:0)

@Martijn,thx为伟大的解决方案。

这对我很有帮助。 这里很少更新。

用于前端/客户端设置。

  .settings(inConfig(Compile)(
    (fullOptJS :: fastOptJS :: packageScalaJSLauncher
     :: packageJSDependencies :: packageMinifiedJSDependencies :: Nil)
      .map(f => (crossTarget in f) ~= (_ / "sjsout"))
  ))

用于后端/服务器设置。

  .settings(
    (resourceGenerators in Compile) += Def.task {
      val fastJsOut = (fastOptJS in Compile in frontend).value.data
      val fastJsSourceMap = fastJsOut.getParentFile / (fastJsOut.getName + ".map")
      val fullJsOut = (fullOptJS in Compile in frontend).value.data
      val fullJsSourceMap = fullJsOut.getParentFile / (fullJsOut.getName + ".map")
      Seq(
        fastJsOut,
        fastJsSourceMap,
        //fullJsOut,
        //fullJsSourceMap,
        (packageScalaJSLauncher in Compile in frontend).value.data,
        (packageJSDependencies in Compile in frontend).value
        //(packageMinifiedJSDependencies in Compile in frontend).value
      )
    }.taskValue,
    (resourceDirectories in Compile) += (crossTarget in frontend).value,
    watchSources ++= (watchSources in frontend).value
  )