Managing local resources with Tilt or how do I setup my local dev environment

Managing local resources with Tilt or how do I setup my local dev environment

I have been working with Tilt for almost a year now and I find it very useful to manage local resources and applications. I'm currently working on a side project called flashcards and I have done the setup of my local environment with Tilt.

What we want to achieve here is to setup:

  • A local database running in a container
  • A bare Phoenix project (API)
  • A bare React project
  • A Tiltfile to rule them all

Here is the tree of my directory:

├── backend
├── docker
│   └── docker-compose.yml
├── env
│   └── postgres.env
├── frontend
└── Tiltfile

Setup the database

Prerequisite:

  • Have Docker installed and running

First let's setup the docker-compose.yml file. I want to have a simple postgres database running in a docker container.

version: '3.8'
services:
  postgres:
    image: postgres:13
    container_name: flashcards_database
    volumes:
      - postgres-data:/var/lib/postgresql/data/
    env_file:
      - ../env/postgres.env
    ports:
      - 5432:5432

volumes:
  postgres-data:

Nothing out of the ordinary here, the only thing I like to do is having the environment variables in an external file.

POSTGRES_USER=geoffroy_baumier
POSTGRES_PASSWORD=password
POSTGRES_DB=flashcards_dev

Perfect, now that this is done I can spin it up in order to setup my Phoenix project.

$ docker-compose -f docker/docker-compose.yml up
[...]
Creating fashcards_database ... done
Attaching to fashcards_database
[...]
fashcards_database | 2021-01-27 18:18:23.825 UTC [1] LOG:  database system is ready to accept connections

The database is now listening on the port default postgres port 5432.

Setup the API

Prerequisites:

  • Have erlang installed
  • Have elixir installed
  • And have the database running

"If we have just installed Elixir for the first time, we will need to install the Hex package manager as well. Hex is necessary to get a Phoenix app running (by installing dependencies) and to install any extra." Source: hexdocs.pm

Let's install the hex package manager:

$ mix local.hex

Now let's install the Phoenix application generator:

$ mix archive.install hex phx_new

I only want to create an API and not use the views in Phoenix. So I do not want to generate the project with views and use webpack. I will use the corresponding options (for more info see here):

mix phx.new flashcards --no-html --no-webpack

Fetch and install dependencies? [Yn] y
    * running mix deps.get
  * running mix deps.compile

Now that our project is generated we can edit the database configuration in config/dev.exs:

# Configure your database
config :flashcards, Flashcards.Repo,
  username: "geoffroy_baumier",
  password: "password",
  database: "flashcards_dev",
  hostname: "localhost",
  [...]

Now we can create the database:

$ mix ecto.create
Compiling 11 files (.ex)
Generated flashcards app
The database for Flashcards.Repo has already been created

Good, now let's start the application:

$ mix phx.server
[info] Running FlashcardsWeb.Endpoint with cowboy 2.8.0 at 0.0.0.0:4000 (http)
[info] Access FlashcardsWeb.Endpoint at http://localhost:4000

Perfect! If you want to see the project running, go to http://localhost:4000/dashboard/home.

Setup the frontend

Prerequisites:

  • Have NodeJS installed
  • Choose a package manager, personally I use yarn

Now we have our database and our API. As you see they already take two tabs of my terminal (dramatic tone, I could also just run in detached mode). We are only missing the frontend, let's jump into it without many details (more info here).

$ yarn create react-app my-app
$ yarn start

Now the frontend is running on http://localhost:3000/. And a third tab in my terminal is being used!

Setup Tilt

Here come the best part, we can regroup and manage those resources all in one place using Tilt. Thanks to Tilt we can automate processes: start of the applications, watch for file changes, build our containers, watch the logs,...

If you are using Homebrew you can install Tilt with this command:

$ brew install tilt-dev/tap/tilt

For the magic to happen, I strongly suggest that you stop your container (even delete it), stop the Phoenix application and also the React application. Stop everything!

Now let's create our Tiltfile at the root of the project.

The first thing we want to do is create and start our database container. All I have to is reference the docker-compose file:

docker_compose('docker/docker-compose.yml')

Then just below let's add our Phoenix application, I will call it 'api':

local_resource(
  'api',
  'cd backend && mix deps.get',
  deps=['backend/config', 'backend/mix.exs', 'backend/mix.lock'],
  serve_cmd='cd backend && mix phx.server',
  resource_deps=['postgres']
)

Let's go through the list of these parameters:

  • The first one is the name
  • Then it is the command to be executed
  • After we find the deps: which is "a list of files or directories to be added as dependencies to this cmd. Tilt will watch those files and will run the cmd when they change."
  • Then we have the serve command which will be run on update
  • And finally the resources of which this current resource depends on. As you can see we can directly reference the docker service.

There are more parameters available: link

And finally we can add our frontend:

local_resource(
  'frontend',
  'cd frontend && yarn install --frozen-lockfile',
  serve_cmd='cd frontend && yarn start',
  deps=['frontend/package.json', 'frontend/yarn.lock'],
  resource_deps=['api']
)

Here is the whole Tiltfile:

docker_compose('docker/docker-compose.yml')

local_resource(
  'api',
  'cd backend && mix deps.get',
  serve_cmd='cd backend && mix phx.server',
  deps=['backend/config', 'backend/mix.exs', 'backend/mix.lock'],
  resource_deps=['postgres']
)

local_resource(
  'frontend',
  'cd frontend && yarn install --frozen-lockfile',
  serve_cmd='cd frontend && yarn start',
  deps=['frontend/package.json', 'frontend/yarn.lock'],
  resource_deps=['api']
)

To run it we simply have to run this command in the root of our directory:

$ tilt up

And everything spins up and we have a nice interface to manage every individual service just in one place. I think that it's wonderful and I gladly recommand using it for local developement. It makes everything easier to start the whole stack with just one command. It also watches the files and does a reload. You can also manually reload a resource. And you have access to all the logs in one tab!

Ho I almost forgot, to stop it you can run:

$ tilt down

More info on managing local resources here.