编辑2:观察和问题
-
我很确定与贾斯汀下面的评论者一起,问题是由于错误的
build.sbt
配置造成的。但是,这是我第一次看到错误的build.sbt
配置,它实际上适用于除选择器之外的其他所有内容。也许那是因为他们使用宏,而我通常避免使用它们。 -
为什么使用
Flow.merge
与Flow.map
是否与sbt
有关
? 可疑的构建.sbt 提取
lazy val server = project .dependsOn(sharedJvm, client)
可疑堆栈跟踪
所以这是堆栈的顶部:它从我找不到的方法到链接环境再到字符串编码实用程序。 好的。
server java.lang.RuntimeException: stub
哼? stub
?
server at scala.sys.package$.error(package.scala:27)
server at scala.scalajs.runtime.package$.linkingInfo(package.scala:143)
server at scala.scalajs.runtime.package$.environmentInfo(package.scala:137)
哼?
server at scala.scalajs.js.Dynamic$.global(Dynamic.scala:78)
???
server at boopickle.StringCodec$.encodeUTF8(StringCodec.scala:56)
编辑1:我的大而漂亮的build.sbt可能是问题所在
你看不到的是我在project
文件夹中组织
- 具有常规 Jvm 依赖项的
JvmDependencies.scala
-
SjsDependencies.scala
JsModuleID
s 上有Def.settingsKey
s 的libraryDependencies
-
WebJarDependencies.scala
具有JavaScript和css的
build.sbt
lazy val shared = (crossProject.crossType(CrossType.Pure) in file("shared"))
.configure(_.enablePlugins(ScalaJSPlugin))
.settings(SjsDependencies.pickling.toSettingsDefinition(): _*)
.settings(SjsDependencies.tagsAndDom.toSettingsDefinition(): _*)
.settings(SjsDependencies.css.toSettingsDefinition(): _*)
lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js
lazy val cmdlne = project
.dependsOn(sharedJvm)
.settings(
libraryDependencies ++= (
JvmDependencies.commandLine ++
JvmDependencies.logging ++
JvmDependencies.akka ++
JvmDependencies.serialization
)
)
lazy val client = project
.enablePlugins(ScalaJSPlugin, SbtWeb, SbtSass)
.dependsOn(sharedJs)
.settings(
(SjsDependencies.shapeless ++ SjsDependencies.audiovideo ++ SjsDependencies.databind ++ SjsDependencies.functional ++ SjsDependencies.lensing ++ SjsDependencies.logging ++ SjsDependencies.reactive).toSettingsDefinition(),
jsDependencies ++= WebjarDependencies.js,
libraryDependencies ++= WebjarDependencies.notJs,
persistLauncher in Compile := true
)
lazy val server = project
.dependsOn(sharedJvm, client)
.enablePlugins(SbtNativePackager)
.settings(
copyWebJarResources := { streams.value.log("Copying webjar resources")
val `Web Modules target directory` = (resourceManaged in Compile).value / "assets"
val `Web Modules source directory` = (WebKeys.assets in Assets in client).value / "lib"
final class UsefulFileFilter(acceptable: String*) extends FileFilter {
// TODO ADJUST TO EXCLUDE JS MAP FILES
import scala.collection.JavaConversions._
def accept(file: File) = (file.isDirectory && FileUtils.listFiles(file, acceptable.toArray, true).nonEmpty) || acceptable.contains(file.ext) && !file.name.contains(".js.")
}
val `file filter` = new UsefulFileFilter("css", "scss", "sass", "less", "map")
IO.createDirectory(`Web Modules target directory`)
IO.copyDirectory(source = `Web Modules source directory`, target = `Web Modules target directory` / "script")
FileUtils.copyDirectory(`Web Modules source directory`, `Web Modules target directory` / "style", `file filter`)
},
// run the copy after compile/assets but before managed resources
copyWebJarResources <<= copyWebJarResources dependsOn(compile in Compile, WebKeys.assets in Compile in client, fastOptJS in Compile in client),
managedResources in Compile <<= (managedResources in Compile) dependsOn copyWebJarResources,
watchSources <++= (watchSources in client),
resourceGenerators in Compile <+= Def.task {
val files = ((crossTarget in(client, Compile)).value ** ("*.js" || "*.map")).get
val mappings: Seq[(File,String)] = files pair rebase((crossTarget in(client, Compile)).value, ((resourceManaged in Compile).value / "assets/").getAbsolutePath )
val map: Seq[(File, File)] = mappings.map { case (s, t) => (s, file(t))}
IO.copy(map).toSeq
},
reStart <<= reStart dependsOn (managedResources in Compile),
libraryDependencies ++= (
JvmDependencies.akka ++
JvmDependencies.jarlocating ++
JvmDependencies.functional ++
JvmDependencies.serverPickling ++
JvmDependencies.logging ++
JvmDependencies.serialization ++
JvmDependencies.testing
)
)
编辑0:一个非常晦涩的聊天线程有一个人说我的感受:不,不是**** scala,而是
马克·艾贝斯 @i-am-the-slime 十月 15 2015 09:37 @ochrons我还在战斗。我似乎不能再腌制任何东西了。 https://gitter.im/scala-js/scala-js/archives/2015/10/15
我有一个相当简单的要求 - 我在akka
http服务器上有一个AkkaServerLogEventToMessageHandler()
定义的Web套接字路由:
object AkkaServerLogEventToMessageHandler
extends Directives {
val sourceOfLogs =
Source.actorPublisher[AkkaServerLogMessage](AkkaServerLogEventPublisher.props) map {
event ⇒
BinaryMessage(
ByteString(
Pickle.intoBytes[AkkaServerLogMessage](event)
)
)
}
def apply(): server.Route = {
handleWebSocketMessages(
Flow[Message].merge(sourceOfLogs)
)
}
}
这以最明显的方式适合一小部分路线。
现在为什么我不能boopickle
、upickle
或prickle
来序列化像这个愚蠢的案例类这样简单的东西?
sealed case class AkkaServerLogMessage(
message: String,
level: Int,
timestamp: Long
)
- 无嵌套
- 所有基元类型
- 无泛型
- 只有三个
这些都产生了大致相同的错误
- 使用所有三种常见的腌制器来书写
- 使用
TextMessage
而不是BinaryMessage
以及相应的upickle
或prickle
writeJs
或任何方法 - 将
case class
更改为无(无,如无成员) - 将输入本身改变到
case class
- 导入
Implicits
和下划线内容的各种排列
。具体来说,他们给了我同一个愚蠢错误的变化(不是同一个错误,但非常相似)
server [ERROR] [04/21/2016 22:04:00.362] [app-akka.actor.default-dispatcher-7] [akka.actor.ActorSystemImpl(app)] WebSocket handler failed with stub
server java.lang.RuntimeException: stub
server at scala.sys.package$.error(package.scala:27)
server at scala.scalajs.runtime.package$.linkingInfo(package.scala:143)
server at scala.scalajs.runtime.package$.environmentInfo(package.scala:137)
server at scala.scalajs.js.Dynamic$.global(Dynamic.scala:78)
server at boopickle.StringCodec$.encodeUTF8(StringCodec.scala:56)
server at boopickle.Encoder.writeString(Codecs.scala:338)
server at boopickle.BasicPicklers$StringPickler$.pickle(Pickler.scala:183)
server at boopickle.BasicPicklers$StringPickler$.pickle(Pickler.scala:134)
server at boopickle.PickleState.pickle(Pickler.scala:511)
server at shindig.clientaccess.handler.AkkaServerLogEventToMessageHandler$$anonfun$1$Pickler$macro$1$2$.pickle(AkkaServerLogEventToMessageHandler.scala:35)
server at shindig.clientaccess.handler.AkkaServerLogEventToMessageHandler$$anonfun$1$Pickler$macro$1$2$.pickle(AkkaServerLogEventToMessageHandler.scala:35)
server at boopickle.PickleImpl$.apply(Default.scala:70)
server at boopickle.PickleImpl$.intoBytes(Default.scala:75)
server at shindig.clientaccess.handler.AkkaServerLogEventToMessageHandler$$anonfun$1.apply(AkkaServerLogEventToMessageHandler.scala:35)
server at shindig.clientaccess.handler.AkkaServerLogEventToMessageHandler$$anonfun$1.apply(AkkaServerLogEventToMessageHandler.scala:31)
这奏效了
- 不使用
Flow.merge
(违背了目的,我想继续发送带有日志的放置) - 使用静态值
- 其他无用的东西
上诉
请让我知道我在哪里以及为什么愚蠢...我今天花了四个小时以不同的形式讨论这个问题,这让我发疯了。
在你的build.sbt
中,你有:
lazy val shared = (crossProject.crossType(CrossType.Pure) in file("shared"))
.configure(_.enablePlugins(ScalaJSPlugin))
不要这样做。您永远不能在跨项目上启用 Scala.js 插件。这也将其添加到JVM端,这将造成严重破坏。最值得注意的是,这将导致%%%
解决 JVM 项目中依赖项的 Scala.js 工件,这真的很糟糕。这就是导致您的问题的原因。
crossProject
已经将 Scala.js 插件添加到 JS 部分,而且只有那个。因此,只需删除该enablePlugins
行即可。
谜团解开了。感谢@Justin du Coeur为我指出正确的方向。
boopickle
不起作用的原因是,在依赖项链中,我在server
项目中同时包含sjs
和jvm
版本的boopickle
。
我删除了client
和sharedJs
的server
dependsOn
,并从共享依赖项中删除了boopickle
。现在它起作用了。