Twirl

Twirl templates support.

To declare a module that needs to compile twirl templates you must extend the mill.twirllib.TwirlModule trait when defining your module. Also note that twirl templates get compiled into scala code, so you also need to extend ScalaModule.

build.mill
package build
import mill.scalalib._

import $ivy.`com.lihaoyi::mill-contrib-twirllib:`,  mill.twirllib._

object app extends ScalaModule with TwirlModule {
// ...
}

Details

The following filesystem layout is expected:

build.mill
app/
  views/
    view1.scala.html
    view2.scala.html

TwirlModule adds the compileTwirl task to the module:

mill app.compileTwirl

(it will be automatically run whenever you compile your module)

This task will compile .scala.html templates (and others, like .scala.txt) into the out/app/compileTwirl/dest directory. This directory must be added to the generated sources of the module to be compiled and made accessible from the rest of the code:

build.mill
package build
import mill.scalalib._

import $ivy.`com.lihaoyi::mill-contrib-twirllib:`,  mill.twirllib._

object app extends ScalaModule with TwirlModule {
  def twirlVersion = "1.5.1"
  def generatedSources = Task { Seq(compileTwirl().classes) }
}

Twirl configuration options

def twirlVersion: T[String]

Mandatory - the version of the Twirl compiler to use.

def twirlScalaVersion: T[String]

Mandatory - the Scala version matching the twirlVersion. Older Twirl versions (before 1.4.2) only supported Scala 2.12.

def twirlImports: T[Seq[String]]

The imports that will be added by the twirl compiler to the top of all templates, defaults to twirl’s default imports:

Seq(
  "_root_.play.twirl.api.TwirlFeatureImports._",
  "_root_.play.twirl.api.TwirlHelperImports._",
  "_root_.play.twirl.api.Html",
  "_root_.play.twirl.api.JavaScript",
  "_root_.play.twirl.api.Txt",
  "_root_.play.twirl.api.Xml"
)

To add additional imports to all of the twirl templates, override twirlImports in your build:

build.mill
package build
import mill.scalalib._

import $ivy.`com.lihaoyi::mill-contrib-twirllib:`,  mill.twirllib._

object app extends ScalaModule with TwirlModule {
  def twirlVersion = "1.5.1"
  def twirlScalaVersion = "2.13.8"
  override def twirlImports = super.twirlImports() ++ Seq("my.additional.stuff._", "my.other.stuff._")
  def generatedSources = Task { Seq(compileTwirl().classes) }
}

// out.template.scala
@import _root_.play.twirl.api.TwirlFeatureImports._
// ...
@import _root_.play.twirl.api.Xml
@import my.additional.stuff._
@import my.other.stuff._

To exclude the default imports, simply override twirlImports without calling super:

build.mill
package build
object app extends ScalaModule with TwirlModule {
  // ...
  override def twirlImports = Seq("my.stuff._")
}

// out.template.scala
@import my.stuff._

def twirlFormats: Map[String, String]

A mapping of file extensions to class names that will be compiled by twirl, e.g. Map("html" -> "play.twirl.api.HtmlFormat"). By default html, xml, js, and txt files will be compiled using the corresponding twirl format.

To add additional formats, override twirlFormats in your build:

build.mill
package build
import mill.scalalib._

import $ivy.`com.lihaoyi::mill-contrib-twirllib:`,  mill.twirllib._

object app extends ScalaModule with TwirlModule {
  def twirlVersion = "1.5.1"
  override def twirlFormats = super.twirlFormats() + Map("svg" -> "play.twirl.api.HtmlFormat")
  def generatedSources = Task { Seq(compileTwirl().classes) }
}

def twirlConstructorAnnotations: Seq[String] = Nil

Annotations added to the generated classes' constructors (note it only applies to templates with @this(…​) constructors).

def twirlCodec = Codec(Properties.sourceEncoding)

The codec used to generate the files (the default is the same sbt plugin uses).

def twirlInclusiveDot: Boolean = false

Whether the twirl parser should parse with an inclusive dot.

Example

There’s an example project