A REPL for your dev environment
Many of us started programming with a REPL (Read-Eval-Print-Loop), whether we knew it at the time or not. (My own introduction came via Logo and Basic on the Apple II.) The thrill of entering obscure abbreviations and commands into the computer and receiving instant feedback can be a big dopamine hit. It can feel like playing a game with infinite lives, where you always have another chance to slay the boss đ.
REPLs encourage experimentation and learning by efficiently providing a tight feedback loop (almost literally; the PL in REPL being âPrint Loopâ, where âprintâ serves as the feedback mechanism). Tilt, as a tool for scripting and assembling development environments, is all about tight feedback loops. What do REPLs and Tilt have in common, and can we use Tilt like a REPL?
Good REPLs help with exploration by providing completion and context awareness, and always reflecting the result back to you. Hereâs a simple example in Ruby:
Some languages use REPLs as the focal point for writing code (see Smalltalk, and to an extent, any member of the Lisp family), while others (C/C++ and many compiled languages) donât come with any built-in REPL at all. More recently, online services let you try a language or share runnable snippets without having to download any software at all (see Ruby, Go, and JavaScript).
Tilt responds to changes in your environment when you modify your files in the same way that the REPL snaps to action when you hit ENTER. One of the events Tilt responds to is changes to the Tiltfile
, Tiltâs own Starlark-based configuration file. With a little creativity and flexibility, we can run Tilt in a terminal inside or next to our editor (tilt up --stream
) and mimic the feedback and responsiveness of a REPL:
The result is a loop that feels surprisingly responsive: write a bit of code, hit Ctrl-S
or â-S
, and see the result! If youâre exploring Tilt and havenât used Starlark (or Python, Starlarkâs parent language), this can be a great way to fool around and get your bearings with Tiltfile
syntax or builtins.
You may have noticed Tilt complaining at the end of the loop about âNo resources foundâ. We implemented and ran a Fibonacci function in Starlark, but didnât give Tilt anything else to do. Tilt primarily wants to build and run things for you; Starlark is the flexible medium through which you describe what to run and build. Tilt is that eager puppy that will keep fetching the ball, though finding it unsatisfying and wishing it was a bone to chew on instead.
Itâs at this point in the experimentation phase where it helps to view Tilt as a replacement for Bash or your command-line shell of choice. Think about activities you normally would type into your shell and see if you can wire them into your Tiltfile
and have Tilt run them for you. For example, maybe youâre sitting down at the keyboard at the beginning of your work day and would normally use git
to pull new changes to your code. Instead, create a local_resource
to do it for you:
local_resource("update-code", "git pull")
Tilt responds with:
Initial Build
Loading Tiltfile at: /Users/nicksieger/tilt-dev/tilt-avatars/web/Tiltfile
Successfully loaded Tiltfile (413.333Âľs)
update-code â
update-code â Initial Build
update-code â Running cmd: git pull
update-code â Already up to date.
Now Tilt will pull code for you when you tilt up
. Resources are Tiltâs unit of work; in the case of a local_resource
, itâs a command to run on your local machine. Resources are stateful in that Tilt looks for changes to them every time the Tiltfile
is executed. So you can also experiment and iterate on resources; if Tilt detects relevant differences, it will re-execute the resource. Say that you find that git pull
is not quite what you want Tilt to do; instead, you want some conditional logic to check if you have a clean working copy and only pull new changes then. You can change the update-code
resource, all while Tilt is running:
script = """
if [ "$(git status -s)" ]; then
echo "You have local changes:"
git status -s
else
echo "Pulling latest code:"
git pull
fi
"""
local_resource("update-code", script)
Tilt says:
1 File Changed: [Tiltfile]
Loading Tiltfile at: /Users/nicksieger/tilt-dev/tilt-avatars/web/Tiltfile
Successfully loaded Tiltfile (1.407958ms)
update-code â
update-code â 1 File Changed: [Tiltfile]
update-code â Running cmd: sh -c "if [ \"$(git status -s)\" ]; then\n\techo \"You have local changes:\"\n\tgit status -s\nelse\n echo \"Pulling latest code:\"\n\tgit pull\nfi"
update-code â You have local changes:
update-code â ?? Tiltfile
Moving on, letâs say youâre working on a JavaScript project, and the next thing you tend to do is check if package.json
had any updates, then you remind yourself that you need to run yarn install
to pick up any new updates. Letâs create a resource for that too:
local_resource("dependencies", "yarn install")
However, Tilt is designed to be responsive to changes in your environment. For a local resource, the deps
argument tells Tilt which file changes should trigger the resource to be re-executed:
local_resource("dependencies", "yarn install", deps=["package.json", "yarn.lock"])
With this change, the next time you pull or make changes to package.json
while Tilt is running, Tilt will run yarn install
for you.
Of course, if your app runs as a Node.JS server as well, that can be added to the resource with a serve_cmd
. Now the resource is handling more than dependencies: itâs building and running the app.
local_resource(
'local-js-server',
cmd='yarn install',
deps=['package.json', 'yarn.lock'],
serve_cmd='yarn start'
)
Again, all of these changes can be applied while Tilt is running, and you can see Tilt take action immediately:
Summary
While Tilt is great at managing your dev environment when the Tiltfile
is fully baked, donât sleep on the idea of using Tilt and the Tiltfile
in a more dynamic way to experiment with your project. In addition to building and running servers, Tilt can also run tests, linters, debuggers, and other tools alongside your development servers. Using the recently-released disable resources feature, you can add resources for these features such that you can enable them when needed, and they wonât get in the way of existing workflows.
If you and your team already have a Tiltfile
in source control and you want to encourage more customization and experimentation, consider adding some code to check for and include a local.tiltfile
to allow individual developers to experiment with Tilt:
if os.path.exists('local.tiltfile'):
load_dynamic('local.tiltfile')
Looking for ideas on where to go from here?
- Read more on options to manage multiple applications/repositories with Tilt.
- Browse our library of snippets for more things you can do in your
Tiltfile
. - Use our hot-off-the-presses VS Code extension (featured in the gif videos above) to help you write
Tiltfile
s!