Build inputs
Build inputs to the ClojureScript compiler determine what ClojureScript source files get compiled. Figwheel follows a simple heuristic for determining the build inputs based on your configuration.
You can determine the build inputs explicitly with the:build-inputs
config option.
Understanding how build inputs change the ClojureScript compiler’s behavior can be very helpful depending on your compilation goals.
Development
When you supply a directory like src
to the compiler, it will find
all the ClojureScript files (.cljs
and .cljc
) and use them
directly as the initial sources for compilation. All of these
initial sources will be compiled regardless of their relationship to
the :main
. When a namespaces is required but not present in these
initial sources, the compiler will then attempt to find it on the
classpath.
If you provide a single file to the compiler like
src/example/core.cljs
, only that file will be in the initial sources and
all of its dependencies will be resolved via the classpath.
This behavior has various trade-offs that need to be understood in the context of compiling for development and production.
One could not be blamed for coming to the conclusion that it is always better to supply the compiler with a single build input that represents the root namespace of your application. This way the final code base will only include code that is needed by the application.
It’s a temptingly simple heuristic that works for many cases. But let me make an argument why it is better to pass a directory or set of directories to the compiler during development when you are using a hot reloading workflow.
The biggest reason to have all you files under watch while you are developing them is so that you receive feedback on files that are not currently included in the application. I.E you can work and prototype them and Figwheel will give you feedback on how well they are compiling. This feedback is not to be underestimated as it parallels the feedback that every decent IDE gives you about your code’s syntax.
Another major reason to pass your source directories as your build inputs is to support the extra mains feature. If you are simply compiling from a single root namespace, files that you need for your extra main entry point will possibly not be compiled.
When you are developing with :optimizations
level :none
, any extra
source files that are being worked on but are not required by the
running application will not be loaded in the running application. The
cost of supplying a directory of source files to the compiler will
only be high if the unrequired source files have
a long initial compile time. This is a very rare situation. Even if
that situation does occur the cost of compiling is paid only once
during the initial compile.
It is for the above reasons that both figwheel.main
and cljs.main
supply the watched directories to the compiler. They are being watched
so that there is an expectation of feedback. When there is no feedback,
one can mistakenly assume that the code one is writing has no syntax
errors.
Production
Now when we leave development mode the priority changes. We normally
do not want to include extra source files in a deployed artifact and
we have no need for feedback on files that are not getting
deployed. When we compile one big artifact with :optimizations
level :whitespace
we don’t want it to contain unneeded namespaces.
figwheel.main
uses the file containing your :main
namespace as the
single build input when you are not in :optimizations
level
:none
. This will ensure that the deployed bundle of JavaScript only
contains code that is being depended on.
This is less of a problem when you use the :advanced
level as it
will perform dead code elimination from the final artifact.
Overriding build inputs
Now that you understand the trade-offs you can safely use the
:build-inputs
config option to override the default sources passed
to the compiler by Figwheel.
Only sending the main namespace
This will probably be the most common build inputs override.
You can accomplish this with the following config:
:build-inputs [:main]
The :main
keyword will be replaced by the main namespaces.
Only sending the watched directories
:build-inputs [:watch-dirs]
The :watch-dirs
keyword will be replaced by the watched directories.
Compiling a directory that you don’t want to watch
Assuming that ./src-no-watch
is a source directory that you want to
compile but don’t want to watch.
:build-inputs [:watch-dirs "src-no-watch"]
A string is assumed to be a file or a directory.
Watched directories and a specific namespace
:build-inputs [:watch-dirs example.tool.extra]
A symbol is assumed to be a ClojureScript namespace.