View Source The Uniform System: How It Works
With the Uniform System, multiple apps are maintained together in a single Elixir codebase. When you're ready to deploy an app, it's "ejected" out into separate codebases that only contains the code needed by the app.
what-is-a-base-project
What is a Base Project?
A Base Project is the single Elixir application that houses all of the applications. When you run the Base Project in your development environment, you are running your entire portfolio of applications simultaneously.
Since Uniform projects are just an Elixir application, the lib
directory is
central. It contains directories for:
- Ejectable Apps
- Lib Dependencies (shared libraries)
It also contrains a Blueprint module configuring which files are copied to ejected repositories.
A Base Project directory structure might look like this.
+ my_base_app
+ lib
+ my_first_app
+ my_second_app
+ utilities
+ ui_components
what-is-ejecting
What is "Ejecting"?
For the purposes of this documentation, ejecting an app means
Copying the code used by the application to a separate, standalone code repository, without including code that the application doesn't need.
Ejecting is done like this:
mix uniform.eject MyAppName
See mix uniform.eject
for more details. This task essentially makes code
repositories "out of thin air" by taking only the relevent code from your Base
Project.
We use Continuous Integration (CI) and Continuous Deployment (CD) tools to automate the process of committing code to ejected repos and deploying to live environments. A single merged code change can result in dozens of apps being safely deployed without any human involvement.
what-is-an-ejectable-app
What is an Ejectable App?
An Ejectable App is simply an application that can be ejected from the Base Project.
Each Ejectable App is stored in a sub-directory of lib
.
To identify a directory inside lib
as an Ejectable App, create an
uniform.exs
file inside the directory.
uniform-exs-options
uniform.exs Options
uniform.exs
files must contain a keyword list, in this structure:
# lib/my_app/uniform.exs
[
mix_deps: [:gql, :timex],
lib_deps: [:some_lib_directory],
extra: [
some_data: "just for this app"
]
]
mix_deps
- Mix Dependencies of the app; each must exist inmix.exs
.lib_deps
- Lib Dependencies of the app; each must exist as a directory inlib/
.extra
- additional user-defined data to configure the app.
The purpose of the :extra key
mix uniform.eject
does not by change its behavior based on the data inextra
, but it is placed inapp.extra
so that you can use it to make decisions in templates or in the base_files or modify sections in your Blueprint module.For 'global' values available to all ejectable apps, use the
Uniform.Blueprint.extra/1
callback implementation.
No Keys in uniform.exs are required
Note that
uniform.exs
does not need to includemix_deps
,lib_deps
, orextra
. They all default to an empty list.By implication,
[]
is a validuniform.exs
file.
how-files-are-included-excluded-by-mix-uniform-eject
How files are included/excluded by mix uniform.eject
Whenever you run mix uniform.eject MyApp
, there are 4 simple rules that the
library uses to decide which files to include or exclude from the ejected
codebase.
- All files specified by the base_files section of the Blueprint are included. These are files to include with every app.
- All files in
lib/my_app
andtest/my_app
are included. - For every Lib Dependency, all files in
lib/dep_name
andtest/dep_name
are included. - A small handful of files common to most Elixir projects are always included.
There are some caveats to these rules.
The files in rule 2 are subject to the lib_app_except callback.
The files in rule 3 are subject to only and except instructions.