如何为 appJS/appJVM 交叉构建项目运行 scala sbt-native-packager

Posted

技术标签:

【中文标题】如何为 appJS/appJVM 交叉构建项目运行 scala sbt-native-packager【英文标题】:how to run scala sbt-native-packager for a appJS/appJVM cross-build project 【发布时间】:2020-03-11 18:48:20 【问题描述】:

sbt-native-packager 可以制作一个包含所有依赖项的 zip 文件和一个要运行的脚本_

$ sbt universal:packageBin

我有一个 scala Web 应用程序,使用交叉构建(appJS 用于前端,appJVM 用于后端)。

如何为 appJVM 运行此打包程序? 我试过如下,但它不接受命令:

$ sbt appJVM/universal:packageBin

这里是 build.sbt 项目,来自https://www.scala-js.org/doc/project/cross-build.html

...

lazy val foo = crossProject.in(file(".")).
  settings(
    name := "foo",
    version := "0.1-SNAPSHOT"
  ).
  jvmSettings(
    // Add JVM-specific settings here
  ).
  jsSettings(
    // Add JS-specific settings here
  )

lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js

如何为 appJVM 运行此打包程序?

以及我如何包含sbt appJS/fullOptJS生成的文件?

还有其他一些静态文件?


Ivan 回复更新

build.sbt:

import sbtcrossproject.CrossPlugin.autoImport.crossProject, CrossType

val sharedSettings = Seq(
    scalaVersion := "2.12.8",
)

lazy val app =
    crossProject(JSPlatform, JVMPlatform)
        .in(file("."))
        .settings(sharedSettings)
        .jsSettings(
        )
        .jvmSettings(
            libraryDependencies ++= Seq(
        "com.typesafe.akka" %% "akka-http" % "10.1.9"
      ),
    )

lazy val backend = project
  .enablePlugins(UniversalPlugin)
  .enablePlugins(JavaAppPackaging)
  .dependsOn(app.jvm)
  .settings(
    mainClass in Compile := Some("com.example.EchoServer")
  )

lazy val frontend = project
  .enablePlugins(ScalaJSPlugin)
  .dependsOn(app.js)

backend
  .settings(
      Seq(
      resourceGenerators in Compile += Def.task 
        Seq(
          (fullOptJS in Compile in frontend).value,
          (fastOptJS in Compile in frontend).value
        ).map  js =>
          val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
          IO.write(resource, IO.read(js.data))
          resource
        
      .taskValue
    )
  )

然后运行:

$ sbt backend/universal:packageBin
34: error: type mismatch;
 found   : Seq[sbt.Def.Setting[Seq[sbt.Task[Seq[java.io.File]]]]]
 required: Int
      Seq(
         ^
[error] Type error in expression

【问题讨论】:

【参考方案1】:

我使用了以下结构。

定义一个需要为 JS 和 Scala 交叉编译的共享项目。

lazy val shared = CrossPlugin.autoImport
  .crossProject(JSPlatform, JVMPlatform)
  .crossType(CrossType.Pure)
  .jvmSettings(???)
  .jsSettings(???)

lazy val sharedJvm = shared.jvm

lazy val sharedJs = shared.js

添加包含 Main 类的项目。

lazy val backend = project
  .enablePlugins(UniversalPlugin)
  .enablePlugins(JavaAppPackaging)
  .dependsOn(sharedJvm)

添加包含网页相关代码的web项目。

lazy val web = project
  .enablePlugins(ScalaJSPlugin)
  .dependsOn(sharedJs)

最后,将 web 中编译成 JS 的资源附加到 backend

backend
  .settings(
    Seq(
      resourceGenerators in Compile += Def.task 
        Seq(
          (fullOptJS in Compile in web).value,
          (fastOptJS in Compile in web).value
        ).map  js =>
          val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
          IO.write(resource, IO.read(js.data))
          resource
        
      .taskValue
  )

主类需要服务从public/assets 编译的 JS,如 sbt 中配置的那样,以及来自其类路径的任何其他 Web 资源。

【讨论】:

我已根据您的建议更新了问题,但仍然失败。再次查看问题。 谢谢!我已经用你的信息更新了这个问题。如果我删除resourceGenerators,则运行sbt backend/universal:packageBin 可以工作。否则它会以error: type mismatch; found : Seq[sbt.Def.Setting[Seq[sbt.Task[Seq[java.io.File]]]]], required: Int 失败。我已经阅读了scala-sbt.org/1.x/docs/Howto-Generating-Files.html 上的文档,但我看不到如何在settings 部分中设置资源生成器。

以上是关于如何为 appJS/appJVM 交叉构建项目运行 scala sbt-native-packager的主要内容,如果未能解决你的问题,请参考以下文章

如何为 arm-v7 交叉编译 qt 应用程序

如何为使用 makefile 构建的整个项目生成一个大型依赖映射?

如何为ios构建skia

如何为ios构建skia

如何为 Android 构建 Assimp? [关闭]

如何为 iOS 构建 DLIB