2016-04-29 35 views
1

我知道我可以编写自己的sbt任务,并且我可以在它们之间创建依赖关系。任务层次对我而言似乎有点复杂,这正是我所苦苦挣扎的:我不知道我的任务应该依赖于哪些任务。这是情况。定制sbt任务,编译JavaScript并仅在生产模式下激活

我的Scala/Play网络应用程序有一个用JavaScript/React编写的相当复杂的前端,编写时使用webpack。在开发过程中,我使用webpack-dev-server。速度更快,支持热重载等功能。不过,在生产模式下部署时,我想用sbt来构建我的前端。这意味着对于sbt startsbt dist,我想让我的前端与Scala源码一起编译,但对于sbt run,应该完全省略此阶段(因为它需要相当多的时间并且webpack-dev-server负责)。

我创建了我自己的sbt任务,几乎只是运行npm install && npm run build,但我不知道在哪里挂钩它。

由于“资产”被sbt对待,我认为情况更加复杂。我的项目中有一个public文件夹,其中包含样式,脚本或图像等资源。这些东西通过构建过程被复制到target文件夹中,然后在最终的应用程序中可用。在我目前的解决方案中,原始的React/JavaScript文件保持分离,自定义sbt任务将其编译到public文件夹中,编译后的文件夹被复制到target文件夹中。这就是预期的工作流程,但此时必须手动调用自定义任务。我想让整个过程自动化,但我不知道在将JavaScript复制到target文件夹之前挂钩我的任务以编译JavaScript。我试着去与copyResource任务,像这样:

(copyResources in Compile) <<= (copyResources in Compile) dependsOn buildJs 

,这似乎是工作,但问题是,在开发模式下运行时,自定义任务(buildJs)被触发也(即sbt run。)。这是我想避免的。

我尝试的另一种方法是直接将JavaScript编译为target文件夹。文件出现在正确的位置,但应用程序不知道它们。他们没有。获取这些文件的HTTP请求返回空响应。

任何想法?

回答

2

因此,应该依赖于我的自定义任务(构建JavaScript)的任务是stagedist。这是我的build.sbt

lazy val buildJs = taskKey[Unit]("Build JavaScript frontend") 
buildJs := { 
    println("Building JavaScript frontend...") 
    "npm install" #&& "npm run build" ! 
} 

stage <<= stage dependsOn buildJs 
dist <<= dist dependsOn buildJs 

这个任务被激活仅针对sbt startsbt dist但不是sbt run(=发展模式)。为此,我使用webpack-dev-server的独立实例来处理JavaScript编译。

有可能是一种更简单的方法,但这是对我有用。

如果您决定使用这种方式将webpack整合到sbt中,最后一个缺失的难题是根据当前模式加载正确的JavaScript文件(在生产模式下,您需要编译包,在开发模式下,您需要将页面指向webpack服务器)。重点在于,为了充分利用所有webpack功能(如热重新加载和热React组件替换),您无法通过Scala Play服务器从静态文件提供JavaScript,它必须是webpack服务器。理论上,可以将Scala服务器变成某种代理服务器,不过,下面的解决方案对我来说很简单(index.scala.html的一部分):

@if(play.Play.isDev()) { 
    <script src="http://localhost:9090/webpack-dev-server.js"></script> 
    <script src="http://localhost:9090/build/@{bundleName}.bundle.js"></script> 
} else { 
    <script src="@routes.Assets.versioned("javascripts/" + bundleName + ".bundle.js")"></script> 
} 
相关问题