How do I run webpack from SBT

Nouhoum's answer was working fine until I updated to SBT 1.0.x

Just a few updates were needed:

import scala.sys.process.Process

lazy val webpack = taskKey[Unit]("Run webpack when packaging the application")

def runWebpack(file: File) = {
  Process("npm run build", file) !
}

webpack := {
  if(runWebpack(baseDirectory.value) != 0) throw new Exception("Something went wrong when running webpack.")
}

dist := (dist dependsOn webpack).value

stage := (stage dependsOn webpack).value

We've built sbt-webpack that integrates cleanly with the incremental compilation with Playframework's static assets. I hope that what you want. It works as expected with sbt run and sbt stage.

At GIVE.asia, We are using it for packaging Vue, Axios, and Vue-i18 into a single JS file, which is later included in our HTML file. Then, we use expose-loader to expose the variables Vue, VueI18n, and axios.

The reason to prefer sbt-webpack is that it generates the output file to an appropriate location that can be used by Playframework's routing. Because it integrates with the incremental compilation with Playframework's static assets.

Here's the repo: https://github.com/GIVESocialMovement/sbt-webpack

Or you can jump directly to a working example: https://github.com/GIVESocialMovement/sbt-webpack/tree/master/test-play-project


I managed to have it work by defining a custom sbt task that is used a dependence for dist and stage tasks invoked when you package your application.

The code of the task is straight forward :

lazy val webpack = taskKey[Unit]("Run webpack when packaging the application")

  def runWebpack(file: File) = {
    Process("webpack", file) !
  }

  webpack := {
    if(runWebpack(baseDirectory.value) != 0) throw new Exception("Something goes wrong when running webpack.")
  }

  dist <<= dist dependsOn webpack

  stage <<= stage dependsOn webpack

In dev mode I use play action hooks to run webpack watch when the code changes :

PlayKeys.playRunHooks <+= baseDirectory.map(Webpack.apply)

with Webpackdefined as follows :

import java.net.InetSocketAddress
import play.sbt.PlayRunHook
import sbt._

object Webpack {
  def apply(base: File): PlayRunHook = {
    object WebpackHook extends PlayRunHook {
      var process: Option[Process] = None

      override def beforeStarted() = {
        process = Option(
          Process("webpack", base).run()
        )
      }

      override def afterStarted(addr: InetSocketAddress) = {
        process = Option(
          Process("webpack --watch", base).run()
        )
      }

      override def afterStopped() = {
        process.foreach(_.destroy())
        process = None
      }
    }

    WebpackHook
  }
}

It works like a charm. You find at my github account a sample play project using this technique : https://github.com/nouhoum/play-react-webpack/blob/master/webpack.sbt

I hope this helps ;-)