Building Javascript with Mill
Simple Typescript Module
package build
import mill.*, javascriptlib.*
object foo extends TypeScriptModule {
  def npmDeps = Seq("immutable@4.3.7")
  object test extends TypeScriptTests, TestModule.Jest
}
Documentation for mill.example.javascriptlib
> ./mill foo.run James Bond prof
Hello James Bond Professor
> ./mill foo.test
PASS .../foo.test.ts
...
Test Suites:...1 passed, 1 total...
Tests:...3 passed, 3 total...
...
> ./mill show foo.bundle
Build succeeded!
> node out/foo/bundle.dest/bundle.js James Bond prof
Hello James Bond Professor
React Module
package build
import mill.*, javascriptlib.*
object foo extends RsWithServeModule {
  override def forkEnv = super.forkEnv() + ("PORT" -> "3000")
}
Documentation for mill.example.javascriptlib
> ./mill foo.test
PASS src/test/App.test.tsx
...renders learn react link...
Test Suites:...1 passed, 1 total
Tests:...1 passed, 1 total
Snapshots:...
Time:...
Ran all test suites...
> ./mill show foo.bundle # build the react app with react-scripts # `foo.run` serves static html using serve
...
Custom Build Logic
package build
import mill.*, javascriptlib.*
object foo extends TypeScriptModule {
  /** Total number of lines in module source files */
  def lineCount: T[Int] = Task {
    sources()
      .flatMap(pathRef => os.walk(pathRef.path))
      .filter(_.ext == "ts")
      .map(os.read.lines(_).size)
      .sum
  }
  /** Generate resource using lineCount of sources */
  def resources = Task {
    os.write(Task.dest / "line-count.txt", "" + lineCount())
    super.resources() ++ Seq(PathRef(Task.dest))
  }
  object test extends TypeScriptTests, TestModule.Jest
}
Documentation for mill.example.javascriptlib
> ./mill foo.run
Line Count: 21
> ./mill show foo.bundle
Build succeeded!
> node out/foo/bundle.dest/bundle.js
Line Count: 21
Multi Module Project
package build
import mill.*, javascriptlib.*
object foo extends TypeScriptModule {
  object bar extends TypeScriptModule {
    def npmDeps = Seq("immutable@4.3.7")
  }
}
object qux extends TypeScriptModule {
  def moduleDeps = Seq(foo, foo.bar)
  object test extends TypeScriptTests, TestModule.Jest
}
Documentation for mill.example.javascriptlib This example demonstrates inter-related typescript modules
> ./mill qux.run James Bond prof
Hello James Bond Professor
> ./mill show qux.bundle
Build succeeded!
> node out/qux/bundle.dest/bundle.js James Bond prof
Hello James Bond Professor
> ./mill qux.test
PASS .../qux.test.ts
...
Simple Client-Server
package build
import mill.*, javascriptlib.*
object client extends ReactScriptsModule
object server extends TypeScriptModule {
  /** Bundle client as resource */
  def resources = Task {
    os.copy(client.bundle().path, Task.dest / "build")
    super.resources() ++ Seq(PathRef(Task.dest))
  }
  override def forkEnv = super.forkEnv() + ("PORT" -> "3000")
  object test extends TypeScriptTests, TestModule.Jest
}
Documentation for mill.example.javascriptlib
This example demonstrated a js client module and js server module,
wired up and interacting
Runninng mill server.run serves bundled static HTML files through the server.
> ./mill client.test
PASS .../App.test.tsx
...
> ./mill client.bundle   # bundle the react app;
...
> ./mill show server.bundle # bundle the node server
...
Build succeeded!
Realistic Client-Server Example Project
package build
import mill.*, javascriptlib.*
object client extends ReactScriptsModule
object server extends TypeScriptModule {
  def npmDeps =
    Seq("@types/cors@^2.8.17", "@types/express@^5.0.0", "cors@^2.8.5", "express@^4.21.1")
  def npmDevDeps =
    super.npmDevDeps() ++ Seq("@types/supertest@^6.0.2", "supertest@^7.0.0")
  def bundleExternal = super.bundleExternal() ++ Seq(ujson.Str("express"), ujson.Str("cors"))
  def forkEnv = super.forkEnv() + ("PORT" -> "3001")
  /** Bundle client as resource */
  def resources = Task {
    os.copy(client.bundle().path, Task.dest / "build")
    super.resources() ++ Seq(PathRef(Task.dest))
  }
  object test extends TypeScriptTests, TestModule.Jest
}
Documentation for mill.example.javascriptlib
This example demonstrates how to set up a simple React web app running on an Express JS server
implementing the popular Todo-MVC demo application. It includes a test suite
for both client and server modules.
Runninng mill app.run serves bundled static HTML files through the server.
> ./mill client.test
PASS src/test/App.test.tsx
...
> ./mill client.bundle   # bundle the react app;
...
> ./mill server.test
PASS .../server.test.ts
...
Test Suites:...1 passed, 1 total...
Tests:...3 passed, 3 total...
...
> ./mill show server.bundle # bundle the express server
...
Build succeeded!