更改某些生成资源的放置位置
Change where certain generated resources are placed
我目前有两个项目;一个用于服务器端 (Akka-HTTP) and one for the client-side (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
和 .map
文件位于 classes
目录的子目录中。像 client/
这样我可以像 getFromResourceDirectory("client")
一样使用 #getFromResourceDirectory
方法,不用担心我的配置文件对外界可用。
我的问题 - 我该如何实现?
我已经尝试添加:
lazy val client = project.in(file("client"))
...
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
到我的客户端项目,它只将生成的 .js
和 .map
文件放在客户端项目的客户端文件夹中 scala-2.11
文件夹:
但设置不会传播到服务器端项目的 classes
文件夹:
这是理想的情况:
深入研究 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
文件夹中接收的最终路径之间创建映射。如果资源路径中没有单个 resourceDirectories
条目,则 #rebase
method is (mostly) responsible for these mappings but it falls back on the #flat
方法。通过简单地将我的客户端项目的 crossTarget
路径添加到 resourceDirectories
设置,rebase 将替换所有内容,直到我的 .js
和 .map
的 client/<filename>
部分文件而不是回退到 #flat
方法,只替换 <filename>
部分,结合此设置:
lazy val client = project.in(file("client"))
...
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
正是我想要的行为。
TL;DR
添加到您的客户端项目:
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
添加到您的服务器端项目:
.settings(inConfig(Compile)((resourceGenerators <+= Def.task {
val f1 = (fullOptJS in client).value.data
val f1sm = f1.getParentFile / (f1.getName + ".map")
f1 :: f1sm :: (packageMinifiedJSDependencies in client).value :: Nil
}) :: (resourceDirectories += (crossTarget in client).value) :: Nil))
@Martijn,感谢伟大的解决方案。
这真是帮了我大忙。
这里很少更新。
用于 frontend/client 设置。
.settings(inConfig(Compile)(
(fullOptJS :: fastOptJS :: packageScalaJSLauncher
:: packageJSDependencies :: packageMinifiedJSDependencies :: Nil)
.map(f => (crossTarget in f) ~= (_ / "sjsout"))
))
用于 backend/server 设置。
.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
)
我目前有两个项目;一个用于服务器端 (Akka-HTTP) and one for the client-side (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
和 .map
文件位于 classes
目录的子目录中。像 client/
这样我可以像 getFromResourceDirectory("client")
一样使用 #getFromResourceDirectory
方法,不用担心我的配置文件对外界可用。
我的问题 - 我该如何实现?
我已经尝试添加:
lazy val client = project.in(file("client"))
...
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
到我的客户端项目,它只将生成的 .js
和 .map
文件放在客户端项目的客户端文件夹中 scala-2.11
文件夹:
但设置不会传播到服务器端项目的 classes
文件夹:
这是理想的情况:
深入研究 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
文件夹中接收的最终路径之间创建映射。如果资源路径中没有单个 resourceDirectories
条目,则 #rebase
method is (mostly) responsible for these mappings but it falls back on the #flat
方法。通过简单地将我的客户端项目的 crossTarget
路径添加到 resourceDirectories
设置,rebase 将替换所有内容,直到我的 .js
和 .map
的 client/<filename>
部分文件而不是回退到 #flat
方法,只替换 <filename>
部分,结合此设置:
lazy val client = project.in(file("client"))
...
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
正是我想要的行为。
TL;DR
添加到您的客户端项目:
.settings(inConfig(Compile)((fullOptJS :: packageMinifiedJSDependencies :: Nil)
.map(a => (crossTarget in a) ~= (_ / "client")))
)
添加到您的服务器端项目:
.settings(inConfig(Compile)((resourceGenerators <+= Def.task {
val f1 = (fullOptJS in client).value.data
val f1sm = f1.getParentFile / (f1.getName + ".map")
f1 :: f1sm :: (packageMinifiedJSDependencies in client).value :: Nil
}) :: (resourceDirectories += (crossTarget in client).value) :: Nil))
@Martijn,感谢伟大的解决方案。
这真是帮了我大忙。 这里很少更新。
用于 frontend/client 设置。
.settings(inConfig(Compile)(
(fullOptJS :: fastOptJS :: packageScalaJSLauncher
:: packageJSDependencies :: packageMinifiedJSDependencies :: Nil)
.map(f => (crossTarget in f) ~= (_ / "sjsout"))
))
用于 backend/server 设置。
.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
)