summaryrefslogtreecommitdiff
path: root/docs/pages/7 - Extending Mill.md
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-04-10 12:11:33 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2018-04-10 14:33:33 -0700
commitb41a09426c03167a883cfb8a3ac3165d99aac056 (patch)
treea485038eb091c59a15c6e828521138ea9071b0de /docs/pages/7 - Extending Mill.md
parent0b11197c99caa61213ffccbc03b913b5a148d426 (diff)
downloadmill-b41a09426c03167a883cfb8a3ac3165d99aac056.tar.gz
mill-b41a09426c03167a883cfb8a3ac3165d99aac056.tar.bz2
mill-b41a09426c03167a883cfb8a3ac3165d99aac056.zip
update changelog for 0.2.00.2.0
Diffstat (limited to 'docs/pages/7 - Extending Mill.md')
-rw-r--r--docs/pages/7 - Extending Mill.md183
1 files changed, 183 insertions, 0 deletions
diff --git a/docs/pages/7 - Extending Mill.md b/docs/pages/7 - Extending Mill.md
new file mode 100644
index 00000000..75b7643a
--- /dev/null
+++ b/docs/pages/7 - Extending Mill.md
@@ -0,0 +1,183 @@
+There are many different ways of extending Mill, depending on how much
+customization and flexibility you need. This page will go through your options
+from the easiest/least-flexible to the hardest/most-flexible.
+
+## Custom Targets & Commands
+
+The simplest way of adding custom functionality to Mill is to define a custom
+Target or Command:
+
+```scala
+def foo = T{ ... }
+def bar(x: Int, s: String) = T.command{ ... }
+```
+
+These can depend on other Targets, contain arbitrary code, and be placed
+top-level or within any module. If you have something you just want to *do* that
+isn't covered by the built-in `ScalaModule`s/`ScalaJSModule`s, simply write a
+custom Target (for cached computations) or Command (for un-cached actions) and
+you're done.
+
+For subprocess/filesystem operations, you can use the
+[Ammonite-Ops](http://ammonite.io/#Ammonite-Ops) library that comes bundled with
+Mill, or even plain `java.nio`/`java.lang.Process`. Each target gets it's own
+[T.ctx().dest](http://www.lihaoyi.com/mill/page/tasks#millutilctxdestctx) folder
+that you can use to place files without worrying about colliding with other
+targets.
+
+This covers use cases like:
+
+### Compile some Javascript with Webpack and put it in your runtime classpath:
+
+```scala
+def doWebpackStuff(sources: Seq[PathRef]): PathRef = ???
+
+def javascriptSources = T.sources{ millSourcePath / "js" }
+def compiledJavascript = T{ doWebpackStuff(javascriptSources()) }
+object foo extends ScalaModule{
+ def runClasspath = T{ super.runClasspath() ++ compiledJavascript() }
+}
+```
+
+### Deploy your compiled assembly to AWS
+
+```scala
+object foo extends ScalaModule{
+
+}
+
+def deploy(assembly: PathRef, credentials: String) = ???
+
+def deployFoo(credentials: String) = T.command{ deployFoo(foo.assembly()) }
+```
+
+
+## Custom Workers
+
+[Custom Targets & Commands](#custom-targets--commands) are re-computed from
+scratch each time; sometimes you want to keep values around in-memory when using
+`--watch` or the Build REPL. e.g. you may want to keep a webpack process running
+so webpack's own internal caches are hot and compilation is fast:
+
+```scala
+def webpackWorker = T.worker{
+ // Spawn a process using java.lang.Process and return it
+}
+
+def javascriptSources = T.sources{ millSourcePath / "js" }
+
+def doWebpackStuff(webpackProcess: Process, sources: Seq[PathRef]): PathRef = ???
+
+def compiledJavascript = T{ doWebpackStuff(webpackWorker(), javascriptSources()) }
+```
+
+Mill itself uses `T.worker`s for it's built-in Scala support: we keep the Scala
+compiler in memory between compilations, rather than discarding it each time, in
+order to improve performance.
+
+## Custom Modules
+
+```scala
+trait FooModule extends mill.Module{
+ def bar = T{ "hello" }
+ def baz = T{ "world" }
+}
+```
+
+Custom modules are useful if you have a common set of tasks that you want to
+re-used across different parts of your build. You simply define a `trait`
+inheriting from `mill.Module`, and then use that `trait` as many times as you
+want in various `object`s:
+
+```scala
+object foo1 extends FooModule
+object foo2 extends FooModule{
+ def qux = T{ "I am Cow" }
+}
+```
+
+You can also define a `trait` extending the built-in `ScalaModule` if you have
+common configuration you want to apply to all your `ScalaModule`s:
+
+```scala
+trait FooModule extends ScalaModule{
+ def scalaVersion = "2.11.11"
+ object test extends Tests{
+ def ivyDeps = Agg(ivy"org.scalatest::scalatest:3.0.4")
+ def testFrameworks = Seq("org.scalatest.tools.Framework")
+ }
+}
+```
+
+## import $file
+
+If you want to define some functionality that can be used both inside and
+outside the build, you can create a new `foo.sc` file next to your `build.sc`,
+`import $file.foo`, and use it in your `build.sc` file:
+
+```scala
+// foo.sc
+def fooValue() = 31337
+```
+```scala
+// build.sc
+import $file.foo
+def printFoo() = T.command{ println(foo.fooValue()) }
+```
+
+Mill's `import $file` syntax supports the full functionality of
+[Ammonite Scripts](http://ammonite.io/#ScalaScripts)
+
+## import $ivy
+
+If you want to pull in artifacts from the public repositories (e.g. Maven
+Central) for use in your build, you can simple use `import $ivy`:
+
+```scala
+// build.sc
+import $ivy.`com.lihaoyi::scalatags:0.6.2`
+
+
+def generatedHtml = T{
+ import scalatags.Text.all._
+ html(
+ head(),
+ body(
+ h1("Hello"),
+ p("World")
+ )
+ ).render
+}
+```
+
+This creates the `generatedHtml` target which can then be used however you would
+like: written to a file, further processed, etc.
+
+If you want to publish re-usable libraries that *other* people can use in their
+builds, simply publish your code as a library to maven central.
+
+For more information, see Ammonite's
+[Ivy Dependencies documentation](http://ammonite.io/#import$ivy)
+
+## Evaluator Commands
+
+You can define a command that takes in the current `Evaluator` as an argument,
+which you can use to inspect the entire build, or run arbitrary tasks. For
+example, here is the `mill.scalalib.GenIdea/idea` command which uses this to
+traverse the module-tree and generate an Intellij project config for your build.
+
+```scala
+def idea(ev: Evaluator[Any]) = T.command{
+ mill.scalalib.GenIdea(
+ implicitly,
+ ev.rootModule,
+ ev.discover
+ )
+}
+```
+
+Many built-in tools are implemented as custom evaluator commands:
+[all](intro.html#all), [inspect](intro.html#inspect),
+[resolve](intro.html#resolve), [show](intro.html#show). If you want a way to run Mill
+commands and programmatically manipulate the tasks and outputs, you do so with
+your own evaluator command.