You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Having the build.sc file being monolithic is a problem for larger projects. Huge monolithic build.sc files are confusing to the developer, cause problems for distributing ownership via OWNERs files, compile slowly and non-incrementally, and invalidate the entire project's targets if so much as a newline is added.
None of these are problems for small projects, but become increasingly problematic when the project and engineering organization working on it grows. IMO a lot of the larger OSS projects using Mill already have reached the point where the size of build.sc is starting to become problematic, e.g. the build.sc for Mill itself, Ammonite, Scala-CLI are all over a thousand lines of rather dense code despite some effort to move logic into separate script files.
A lot of progress has already been made to allow Mill builds to be broken down into multiple build files:
Granular cache invalidation with multiple build files #1663 allows the import graph between multiple build files to be used for cache-invalidation purposes, so a change to one build file only invalidates targets defined in downstream builds
These are all big steps towards making per-folder build.sc files a reality, but we're not there yet. The last things that are missing to make "per-folder" build.sc files a first class citizen include:
Enable targets in sub-folders to be run directly from the CLI, perhaps via a syntax such as ./mill foo/bar/baz.qux (if we want to strictly separate sub-folders and sub-modules) or foo.bar.baz.qux (if we don't mind mixing them together) or foo/bar:baz.qux (Bazel/Pants/Buck-style) to run the baz.qux target defined in foo/bar/build.sc
Have a story for discovering/skipping nested folders that contain build files, either opt-in (as is done in Gradle's settings.gradle) or opt out (as is done is Bazel's .bazelignore)
(optional) Allow modules and targets in nested build.sc files to be reference-able without an explicit import $file. e.g. Maybe just being able to say def moduleDeps = Seq($file.foo.bar.build.myModule), or def myTarget = T{... $file.foo.bar.build.myTarget() ...}
Once this is done, breaking up a large build.sc file into multiple smaller per-folder files would have the following benefits:
Avoiding huge multi-thousand-line build.scs in favor of smaller ones
Keeping build logic defined closer to the sub-folder that logic is building, making it easier to find
Allowing Zinc to perform incremental compilation at a per-file granularity
Allowing script-import-based target cache invalidation to avoid invalidating everything every time a build file is touched.
Be more aligned with other tools like SBT/Maven/Gradle/Bazel/Pants/Buck, which all allow per-folder build files
The text was updated successfully, but these errors were encountered:
lihaoyi
changed the title
Allow per-folder build.sc files as a first-class feature to support large projects
Make per-folder build.sc files a first-class feature to support large projects
Jun 27, 2023
Having the
build.sc
file being monolithic is a problem for larger projects. Huge monolithicbuild.sc
files are confusing to the developer, cause problems for distributing ownership viaOWNER
s files, compile slowly and non-incrementally, and invalidate the entire project's targets if so much as a newline is added.None of these are problems for small projects, but become increasingly problematic when the project and engineering organization working on it grows. IMO a lot of the larger OSS projects using Mill already have reached the point where the size of
build.sc
is starting to become problematic, e.g. thebuild.sc
for Mill itself, Ammonite, Scala-CLI are all over a thousand lines of rather dense code despite some effort to move logic into separate script files.A lot of progress has already been made to allow Mill builds to be broken down into multiple build files:
Make builds able to depend on external projects #291 added support for "foreign modules" which are defined in build files that are not the root
build.sc
Granular cache invalidation with multiple build files #1663 allows the import graph between multiple build files to be used for cache-invalidation purposes, so a change to one build file only invalidates targets defined in downstream builds
Remove Ammonite as a dependency, handle script running and bootstrapping ourselves #2377 removes the overhead that previously existed in Ammonite's handling of multiple scripts and making multiple scripts re-compile incrementally on a per-file granularity, making it even faster than re-compiling one monolithic script
These are all big steps towards making per-folder
build.sc
files a reality, but we're not there yet. The last things that are missing to make "per-folder"build.sc
files a first class citizen include:Enable targets in sub-folders to be run directly from the CLI, perhaps via a syntax such as
./mill foo/bar/baz.qux
(if we want to strictly separate sub-folders and sub-modules) orfoo.bar.baz.qux
(if we don't mind mixing them together) orfoo/bar:baz.qux
(Bazel/Pants/Buck-style) to run thebaz.qux
target defined infoo/bar/build.sc
Have a story for discovering/skipping nested folders that contain build files, either opt-in (as is done in Gradle's
settings.gradle
) or opt out (as is done is Bazel's.bazelignore
)(optional) Allow modules and targets in nested
build.sc
files to be reference-able without an explicitimport $file
. e.g. Maybe just being able to saydef moduleDeps = Seq($file.foo.bar.build.myModule)
, ordef myTarget = T{... $file.foo.bar.build.myTarget() ...}
Once this is done, breaking up a large
build.sc
file into multiple smaller per-folder files would have the following benefits:build.sc
s in favor of smaller onesThe text was updated successfully, but these errors were encountered: