首页 > 解决方案 > 如何为 appJS/appJVM 交叉构建项目运行 scala sbt-native-packager

问题描述

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

还有其他一些静态文件?


更新伊万回应

构建.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

标签: scalasbt-native-packager

解决方案


我使用了以下结构。

定义一个需要为 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包含 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/assetssbt 中配置的编译的 JS 以及其类路径中的任何其他 Web 资源提供服务。


推荐阅读