First of all, what is Mix? According to the Introduction to Mix page on elixir-lang.org,
Mix is a build tool that provides tasks for creating, compiling, testing (and soon releasing) Elixir projects. Mix is inspired by the Leiningen build tool for Clojure and was written by one of its contributors.
That sounds super, doesn’t it? At the end of the day, you will use Mix for a number of reasons in your project. The first way we will use Mix today is to have it create our initial project for us with mix new --sup [project name]
.
$ mix new --sup your_project
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/your_project.ex
* creating test
* creating test/test_helper.exs
* creating test/your_project_test.exs
Your mix project was created successfully.
You can use mix to compile it, test it, and more:
cd your_project
mix test
Run "mix help" for more information.
$ cd your_project
$ ls -la
total 16
drwxr-xr-x 11 shane staff 374 Feb 14 16:40 .
drwxr-xr-x 23 shane staff 782 Feb 14 16:25 ..
-rw-r--r-- 1 shane staff 41 Feb 14 16:25 .gitignore
-rw-r--r-- 1 shane staff 428 Feb 14 16:25 README.md
drwxr-xr-x 2 shane staff 23 Feb 14 16:25 config
drwxr-xr-x 4 shane staff 28 Feb 14 16:25 lib
-rw-r--r-- 1 shane staff 705 Feb 14 16:31 mix.exs
drwxr-xr-x 4 shane staff 56 Feb 14 16:25 test
See that mix.exs
file Mix generated for us? It contains project-level configurations, one of which is the project dependencies. We need to ensure Sugar is returned by the deps/0
function, such as:
def deps do
[ {:sugar, github: "sugar-framework/sugar"} ]
end
If you’re running Elixir v0.13.2 or higher, hex is the preferred way of adding the dependency. For a general overview of this process, checkout the hex usage page. Here’s the tuple needed for hex:
def deps do
[ { :sugar, "~> 0.5" } ]
end
so open it up, add one of the tuples for Sugar, and save it.
You’ll also need to add the Sugar application to the application/0
function in that same file, like so:
def application do
[ applications: [:sugar],
mod: {YourProject, []} ]
end
As of Elixir 1.4.0, the above step is unnecessary if you’re using extra_applications
instead of applications
(the default for new Mix projects), since Mix will automatically find Sugar in your project’s dependencies and do the necessary work to make sure Sugar starts when your application starts.
With all that done, we’re going to use Mix to pull down a copy of Sugar and its dependencies and compile them, using mix do deps.get, deps.compile
. This could also be accomplished in two commands, mix deps.get
and mix deps.compile
, but mix do
allows us to chain commands, one after the other. This process can take a bit of time depending on the speed of your internet connection and computer.
$ mix do deps.get, deps.compile
* Getting sugar (git://github.com/sugar-framework/sugar.git)
Cloning into '/Volumes/Data/Code/elixir/your_project/deps/sugar'...
remote: Counting objects: 564, done.
remote: Compressing objects: 100% (255/255), done.
remote: Total 564 (delta 334), reused 464 (delta 277)
Receiving objects: 100% (564/564), 68.83 KiB | 0 bytes/s, done.
Resolving deltas: 100% (334/334), done.
Checking connectivity... done
* Getting mime (git://github.com/dynamo/mime.git)
Cloning into '/Volumes/Data/Code/elixir/your_project/deps/mime'...
remote: Reusing existing pack: 46, done.
remote: Total 46 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (46/46), 29.10 KiB | 0 bytes/s, done.
Resolving deltas: 100% (14/14), done.
Checking connectivity... done
* Getting cowboy (git://github.com/extend/cowboy.git)
Cloning into '/Volumes/Data/Code/elixir/your_project/deps/cowboy'...
remote: Reusing existing pack: 5810, done.
...
# The rest of the project dependencies are downloaded and compiled
...
* Compiling sugar
Compiled lib/mix/tasks/sugar/gen/router.ex
Compiled lib/mix/tasks/sugar/gen/config.ex
Compiled lib/mix/tasks/server.ex
Compiled lib/mix/tasks/sugar/gen/controller.ex
Compiled lib/sugar.ex
Compiled lib/mix/tasks/sugar/init.ex
Compiled lib/mix/tasks/sugar/gen/view.ex
Compiled lib/sugar/app.ex
Compiled lib/sugar/supervisor.ex
Compiled lib/sugar/controller.ex
Compiled lib/sugar/router.ex
Generated sugar.app
If everything goes to plan, no errors will be raised, and Generated sugar.app
will be displayed, letting you know all of the dependencies have been compiled correctly.
With mix
being the extensible build tool that it is, developers often add specialized mix
tasks to their projects, adding functionality that makes using the project easier. Sugar is no exception. Let’s see what’s available.
$ mix help
mix # Run the default task (current: mix run)
mix archive # Archive this project into a .ez file
mix clean # Clean generated application files
mix cmd # Executes the given command
mix compile # Compile source files
mix deps # List dependencies and their status
mix deps.clean # Remove the given dependencies' files
mix deps.compile # Compile dependencies
mix deps.get # Get all out of date dependencies
mix deps.unlock # Unlock the given dependencies
mix deps.update # Update the given dependencies
mix dialyzer # Runs dialyzer with default or project-defined flags.
mix dialyzer.plt # Builds PLT with default erlang applications included.
mix do # Executes the tasks separated by comma
mix escriptize # Generates an escript for the project
mix help # Print help information for tasks
mix local # List local tasks
mix local.install # Install a task or an archive locally
mix local.rebar # Install rebar locally
mix local.uninstall # Uninstall local tasks or archives
mix new # Create a new Elixir project
mix run # Run the given file or expression
mix server # Runs Sugar and children
mix sugar.gen.controller # Creates Sugar controller files
mix sugar.gen.router # Creates Sugar router files
mix sugar.gen.view # Creates Sugar view files
mix sugar.init # Creates Sugar support files
mix test # Run a project's tests
iex -S mix # Start IEx and run the default task
All of the mix
tasks available to your project will be listed along with a short description of what it does. Note that all of the Sugar tasks start with sugar.*
.
Since sugar.init
add in the necessary files for Sugar, let’s run it.
$ mix sugar.init
* creating lib/your_project/router.ex
* creating lib/your_project/controllers
* creating lib/your_project/controllers/main.ex
* creating lib/your_project/models
* creating lib/your_project/views
* creating lib/your_project/views/main/index.html.eex
* creating priv
* creating priv/static
Awesome! Now we have our config module, a router, our first controller, and a view. The sugar.init
task follows a few conventions regarding module names and file locations. For instance, lib/your_project/controllers/main.ex
contains the YourProject.Controllers.Main
module. Take a look around your project if you’re unfamiliar with Elixir. Don’t worry. We’ll be here when you get back.
A web application wouldn’t serve much of a purpose if it couldn’t map URLs to a particular function or set of expressions. It would essentially sit there, thinking it was doing its job when it was really doing anything but.
Enter the router. You define the routes for your web application, and the router makes sure the application does what it’s supposed to when a user hits a page.
Let’s see what Sugar put in our router.
defmodule YourProject.Router do
use Sugar.Router
plug Sugar.Plugs.HotCodeReload
if Sugar.Config.get(:sugar, :show_debugger, false) do
plug Plug.Debugger, otp_app: :your_project
end
plug Plug.Static, at: "/static", from: :you_project
# Uncomment the following line for session store
# plug Plug.Session, store: :etc, key: "sid", secure: true, table: :session
# Define your routes here
get "/", YourProject.Controllers.Main, :index
end
Routes are defined with the form method route [guard], controller, action
, so when get "/", YourProject.Controllers.Main, :index
is used in the router, we are telling our application to call the index
function (action) defined in the YourProject.Controllers.Main
module (controller) whenever the "/"
URL is accessed.
Along with defining routes, the router can also contain two other configurations: plugs and filters. Both of these allow for the modification of response on a much broader scale than what is possible with a single controller action.
To see the different ways routes can be defined or routers can be configured, checkout the documentation on routing.
Mix.Config
If you were to try to run your project at this time, it would probably fail. This is because the proper application environment vairables have not been set yet. Open up your config/config.exs
file, and add these lines:
config :sugar,
router: YourProject.Router
config :sugar, YourProject.Router,
https_only: false,
http: [ port: 4000 ],
https: false
This let’s the Sugar internals know about the YourProject.Router
module and sets the port number on which the HTTP server will listen.
Now we’re ready to run mix server
. You should see some output in your terminal window:
...
Generated index.html.eex
Generated show.html.eex
== Sugar running in http://127.0.0.1:4000 ==
Now you can access your application at http://127.0.0.1:4000
.
One controller isn’t enough to properly organize your application, you say? Good to hear! I suppose you’d like to know how to create a new controller, right? Well, look no further than your friend Mix.
$ mix sugar.gen.controller pages
* creating lib/your_project/controllers/pages.ex
Success! A new YourProject.Controller.Pages
controller has been created for you.
defmodule YourProject.Controllers.Pages do
use Sugar.Controller
def index(conn, []) do
raw conn |> resp(200, "Hello world")
end
end
Now it’s your turn to take this controller and mould it to do your will. Check out the controllers documentation for more information about controllers.
Sugar is released under the MIT License.
Theme based on Bolt by BlackTie.co.