Elixir Mix project from scratch
Tags: elixir
Published: 2020-11-05 07:58:26

[Mix](https://hexdocs.pm/mix/Mix.html) เป็น build tool ของ elixir และ เป็น dependencies manangement tool ด้วย (ถ้าใครใช้ Node.js มาก็คือเครื่องมือแบบเดียวกันกับ npm หรือ ถ้าใครใช้ Ruby มาก็คือแบบ bundler นั่นเอง)

จริงๆ mix ก็เป็น command line ที่มีคำสั่งย่อยให้เราสร้างโครงของ Elixir Project ได้แหละ แต่บทความนี้เราจะมาดูว่าจริงๆแล้วถ้าเราจะเขียน config file ต่างๆขึ้นมาเองเพื่อให้ mix เริ่มทำงานได้ ต้องทำยังไงบ้าง

## อย่างน้อยที่สุดคือมีไฟล์ mix.exs เพื่อ config Mix.Project

จริงๆแล้ว Mix Project ต้องการแค่ `mix.exs` ไฟล์เดียวนั่นเองซึ่งในนั้นจะต้องเป็น Module ที่ `use Mix.Project` เพื่อที่จะ register ตัวเองให้กับ mix ว่าที่คือ module สำหรับ config project และ ต้องมี function `project/0` เพื่อกำหนด config ของ project ที่ต้องมีอย่างน้อย 2 ค่าคือ `:app` กับ `:version` เช่น

```elixir
defmodule MixFromScratch.MixFile do
  use Mix.Project

  def project do
    [
      app: :mix_from_scratch,
      version: "0.1.0"
    ]
  end
end
```

ตอนนี้ใน directory ของ project เรามีแค่ไฟล์เดียวแบบนี้

```
mix-from-scratch
└── mix.exs
```

ให้เราสั่ง iex ขึ้นมาโดยโหลด project เราโดยสั่ง `iex -S mix` แล้วลองเช็ค project config ด้วยฟังก์ชัน `Mix.Project.config/0`

```
iex(1)> Mix.Project.config
[
  aliases: [],
  build_embedded: false,
  build_per_environment: true,
  build_scm: Mix.SCM.Path,
  config_path: "config/config.exs",
  consolidate_protocols: true,
  default_task: "run",
  deps: [],
  deps_path: "deps",
  elixirc_paths: ["lib"],
  erlc_paths: ["src"],
  erlc_include_path: "include",
  erlc_options: [],
  lockfile: "mix.lock",
  preferred_cli_env: [],
  start_permanent: false,
  app: :mix_from_scratch,
  version: "0.1.0"
]
```

เราจะเห็นค่า default config อื่นๆ ที่สำคัญคือ `elixirc_paths: ["lib"]` นั่นคือเราสามารถสร้าง lib directory แล้วเขียนโค้ด Elixir ในนี้เพื่อให้ mix คอมไพล์และโหลด module ของเราได้ เช่น ถ้าเรามีไฟล์ `lib/message.ex` แบบนี้


```
mix-from-scratch
├── lib
│   └── message.ex
└── mix.exs
```

```elixir
defmodule Message do
  def hello do
    IO.puts "Hello"
  end
end
```

เมื่อเราสั่ง `iex -S mix` อีกรอบ mix จะ compile และ load module ให้เราแล้ว เราสามารถสั่งรัน `Message.hello/0` ได้เช่น

```
iex(1)> Message.hello
Hello
:ok
iex(2)
```

ถ้าเราอย่างเพิ่ม external dependencies ก็ให้แก้ config ที่ mix.exs เช่นจะเพิ่ม package `jason` มาใช้งานก็เพิ่มได้แบบนี้

```elixir
defmodule MixFromScratch.MixFile do
  use Mix.Project

  def project do
    [
      app: :mix_from_scratch,
      version: "0.1.0",
      deps: [
        {:jason, "~> 1.2"}
      ]
    ]
  end
end
```

แต่ตาม convention ที่เราได้เห็นจากเวลา mix generate ให้ มักจะ extract ส่วนของ deps ออกเป็นอีกฟังก์ชัน แบบนี้

```elixir
defmodule MixFromScratch.MixFile do
  use Mix.Project

  def project do
    [
      app: :mix_from_scratch,
      version: "0.1.0",
      deps: deps()    
    ]
  end

  defp deps do
    [
      {:jason, "~> 1.2"}
    ]
  end
end
```

แล้วสั่ง `mix deps.get` เพื่อให้โหลด dependencies ตามที่เรา config

จากนั้นลองสั่ง `iex -S mix` ซึ่งก็จะทำการ compile และ load dependencies module ให้เราแล้ว สามารถลองเล่น Jason ได้แบบนี้

```
iex(1)> Jason.encode(%{message: "Hello"})
{:ok, "{\"message\":\"Hello\"}"}
```

จากที่ลองเล่นก็ทำให้เราใจการทำงานของ Mix และเข้าใจ config ของ Mix.Project มากขึ้น ถ้าอยากรู้ config อื่นๆเอาไว้ทำอะไรบ้างดูต่อได้ที่ document ที่นี่ได้เลย https://hexdocs.pm/mix/Mix.Project.html