Typescript Library Dependencies

This page goes into more detail about configuring third party dependencies for `TypescriptModule`s.

Adding Dependencies

build.mill (download, browse)
package build
import mill._, javascriptlib._

object foo extends TypeScriptModule {
  def npmDeps = Seq("lodash@4.17.21")
  def npmDevDeps = Seq("@types/lodash@4.17.13")
}

You can define npmDeps field to add dependencies to your module and define npmDevDeps field to add dev dependencies to your module, which will be installed via configured registry.

> mill foo.run e b k a l m o p
Sorted with lodash: [a,b,e,k,l,m,o,p]

Unmanaged Packages

build.mill (download, browse)
package build
import mill._, javascriptlib._

object foo extends TypeScriptModule {
  def unmanagedDeps = Seq.from(os.list(millSourcePath / "lib").map(PathRef(_)))
}

You can override unmanagedDeps to point to a source distribution .tar.gz you place on the filesystem, e.g. in the above snippet any files that happen to live in the lib/ folder.

Note: When installing from a .tgz file, Node.js and npm determine the package name and how to import it from the package.json file inside the .tgz archive.

For more info on package.json, see: https://docs.npmjs.com/cli/v10/configuring-npm/package-json?v=true&utm_source=chatgpt.com For more info on creating unmanaged dependecies, see: https://docs.npmjs.com/cli/v10/commands/npm-pack

> mill foo.run e b k a l m o p
Sorted with lodash: [a,b,e,k,l,m,o,p]

Downloading Unmanaged Packages

You can also override unmanagedDeps to point it at wheels that you want to download from arbitrary URLs. requests.get comes from the Requests-Scala library, one of Mill’s Bundled Libraries.

build.mill (download, browse)
package build
import mill._, javascriptlib._

object foo extends TypeScriptModule {
  def unmanagedDeps = Task {
    val name = "lodash-4.17.21.tgz"
    val url = "https://github.com/lodash/lodash/archive/refs/tags/4.17.21.tar.gz"
    os.write(Task.dest / name, requests.get.stream(url))
    Seq(PathRef(Task.dest / name))
  }
}
> mill foo.run e b k a l m o p
Sorted with lodash: [a,b,e,k,l,m,o,p]

Tasks like unmanagedDeps and npmDeps are cached, so your package is downloaded only once and re-used indefinitely after that. This is usually not a problem, because usually URLs follow the rule that Cool URIs don’t change, and so files downloaded from the same URL will always contain the same contents.

An unmanaged depedencies downloaded via requests.get is still unmanaged: even though you downloaded it from somewhere, requests.get does not know how to pull in third party dependencies or de-duplicate different versions.

In case you do want mill to take care of managing dependencies of a package, you shouldn’t get that package in unmanagedDeps (like we did in the example above). Instead, you can declare the dependency as a regular npmDeps and npmDevDeps

Using Custom or Private Registries

build.mill (download, browse)
package build
import mill._, javascriptlib._

object foo extends TypeScriptModule {
  def npmDeps = Seq("lodash@4.17.21")
  def npmDevDeps = Seq("@types/lodash@4.17.13")
}

Mill uses https://registry.npmjs.org to find and install dependencies.

Alternate/Private registries

You can configure registries via a .npmrc file in project root. For more information on npmrc see: https://docs.npmjs.com/cli/v9/configuring-npm/npmrc. The example below uses the alternate registry https://registry.npmmirror.com

> mill foo.run e b k a l m o p
Sorted with lodash: [a,b,e,k,l,m,o,p]
....
{
  version: '4.17.21',
  resolved: 'https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz',
  integrity: ...,
...
}

> cd out/foo/npmInstall.dest && npm config get registry
https://registry.npmmirror.com