Mix 工具链与 Elixir 工程化实战

Mix 工具链与 Elixir 工程化实战:Mix 项目结构与任务(mix new/task)、依赖管理与 Hex 生态、编译与配置(Mix.Config/环境)、测试与代码质量(mix test/excoveralls/credo/dialyxir)、发布与部署(mix release/Elixir releases)、CI 集成、常见工作流与陷阱。

引言

Mix 是 Elixir 的构建工具——创建项目、管理依赖、编译、测试、发布,一站式搞定。它背后是 Erlang 生态的成熟工程实践:从 Hex 包仓库到 OTP release。本文讲透 Mix 工作流:项目结构、依赖、环境配置、测试质量、以及生产发布与 CI。

前置:/elixir-intro-phoenix/(Elixir/Phoenix 基础)、/elixir-testing-property/(测试方法论)、/erlang-hot-code-upgrade/(OTP release)。


目录


1. Mix 是什么

1.1 一站式构建工具

✓ 项目脚手架(mix new)
✓ 依赖管理(Hex / mix deps)
✓ 编译(mix compile)
✓ 测试(mix test)
✓ 发布(mix release)
✓ 自定义任务(Mix.Tasks.*)

1.2 Mix 与 OTP 的关系

Mix 构建的应用本质是 OTP 应用(app tree + supervision tree),发布后用 bin/app start 启动,配合热升级/监控。

记忆:Mix = Elixir 的一站式构建工具(脚手架/依赖/编译/测试/发布),构建出的应用是 OTP 应用——与 Erlang 生态无缝衔接。


2. 项目结构与 mix new

2.1 生成项目

mix new my_app                    # 普通应用
mix new my_app --sup              # 带 supervisor(推荐)
mix phx.new my_app                # Phoenix Web 应用

2.2 目录结构

my_app/
├── lib/               # 源码
│   ├── my_app.ex      # 应用模块(use Application)
│   └── my_app/        # 子模块
├── test/              # 测试(my_app_test.exs)
├── config/            # 配置(config.exs / 环境)
├── mix.exs            # 项目定义(依赖/应用/版本)
├── mix.lock           # 依赖锁定版本
└── README.md

2.3 mix.exs 关键配置

defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :my_app,
      version: "0.1.0",
      elixir: "~> 1.14",
      deps: deps(),
      releases: releases()
    ]
  end

  def application do
    [extra_applications: [:logger], mod: {MyApp.Application, []}]
  end

  defp deps do
    [
      {:jason, "~> 1.4"},
      {:plug_cowboy, "~> 2.0"}
    ]
  end
end

记忆:mix new –sup 生成 OTP 应用骨架(lib/test/config + mix.exs/mix.lock);mix.exs 是项目定义——deps 依赖、application 应用模块、releases 发布。


3. 自定义任务 Mix.Tasks

3.1 定义一个任务

# lib/mix/tasks/hello.ex
defmodule Mix.Tasks.Hello do
  use Mix.Task

  @shortdoc "打印问候"
  def run(_args) do
    Mix.shell().info("Hello, Mix!")
  end
end

3.2 使用

mix hello
# → Hello, Mix!

3.3 任务内部访问应用环境

def run(args) do
  Mix.Task.run("app.start")   # 启动应用(能访问 Application env)
  MyApp.some_function()
end

记忆:自定义任务 = use Mix.Task + run/1(Mix.shell().info 输出),需要应用环境时先 Mix.Task.run(“app.start”)——团队脚本标准化的入口。


4. 依赖管理与 Hex

4.1 Hex 生态

Hex 是 Elixir 的包管理器(类似 npm/crates.io),hex.pm 托管。

mix local.hex --force    # 安装 Hex
mix hex.search jason     # 搜索包
mix deps.get             # 拉取依赖
mix deps.update jason    # 更新依赖
mix deps.tree            # 查看依赖树

4.2 mix.lock

锁定精确版本,保证环境一致:

mix deps.get        # 生成/更新 mix.lock
mix deps.compile    # 编译依赖
# mix.lock 必须提交到 git

4.3 依赖来源

{:jason, "~> 1.4"},                    # Hex 包(语义化版本)
{:my_lib, path: "../my_lib"},          # 本地路径(开发)
{:my_lib, github: "user/my_lib"},      # GitHub
{:my_lib, ">= 0.1.0", only: :dev}      # 仅开发环境

记忆:依赖管理走 Hex——mix deps.get 拉取 + mix.lock 锁定 + deps.tree 查树;来源支持 Hex/路径/Git,only: :dev 限定环境——mix.lock 必须入库保证可复现。


5. 配置与环境 Mix.Config

5.1 config 目录

# config/config.exs(公共配置)
import Config
import_config "#{config_env()}.exs"   # 按环境加载

# config/dev.exs
config :my_app, MyApp.Repo, username: "postgres", database: "my_app_dev"

# config/prod.exs(生产)
config :my_app, MyApp.Repo, username: System.fetch_env!("DB_USER")

5.2 运行时读取

# 读取配置
Application.get_env(:my_app, :timeout, 5000)

# 运行时环境变量(生产推荐)
System.get_env("MY_APP_SECRET")

记忆:配置分层——config.exs 公共 + config_env().exs 按环境;运行时用 Application.get_env 读取、生产密钥用 System.get_env 环境变量注入。


6. 测试与代码质量

6.1 mix test 体系

mix test                      # 跑全部
mix test test/foo_test.exs    # 指定文件
mix test --cover              # 覆盖率
mix test --trace              # 详细输出

6.2 质量工具链

# mix.exs deps
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},    # 代码规范
{:dialyxir, "~> 1.4", only: [:dev], runtime: false},        # 类型分析
{:excoveralls, "~> 0.18", only: [:test], runtime: false}    # 覆盖率
mix credo                     # 规范检查
mix dialyzer                  # Dialyzer 类型分析
mix coveralls.report          # 覆盖率报告

6.3 质量门禁

✓ mix format --check-formatted(格式检查)
✓ mix credo --strict(规范)
✓ mix dialyzer(类型)
✓ mix test --cover(覆盖率阈值)

记忆:质量四件套——mix format 格式、credo 规范、dialyzer 类型、test –cover 覆盖率;CI 里全部门禁,mix.lock 保证测试可复现。


7. 编译与增量构建

7.1 增量编译

Mix 只重新编译变化的文件:

mix compile             # 编译(增量)
mix compile --force     # 全量重编
mix clean               # 清理
mix deps.compile        # 编译依赖

7.2 编译产物

_build/               # 编译产物(dev/prod 分离)
deps/                 # 依赖源码
elixir/               # Elixir 版本管理(mise/asdf)

记忆:Mix 增量编译(只编变化文件)——_build/ 产物按环境分离、deps/ 依赖源码、force 全量重编;配合 .formatter.exs 统一格式。


8. 发布与部署:mix release

8.1 构建 release

# mix.exs
def releases do
  [
    my_app: [
      include_executables_for: [:unix],
      steps: [:assemble]
    ]
  ]
end
MIX_ENV=prod mix release
# → _build/prod/rel/my_app/

8.2 启动与管理

_build/prod/rel/my_app/bin/my_app start    # 启动
_build/prod/rel/my_app/bin/my_app daemon   # 后台
_build/prod/rel/my_app/bin/my_app stop     # 停止
_build/prod/rel/my_app/bin/my_app eval "MyApp.foo()"  # 执行

8.3 release 优势

✓ 自带 OTP VM + 应用,无需源码环境
✓ 部署零依赖(目标机不需要 Elixir)
✓ 配合热升级(release_handler)
✓ 生产配置用环境变量注入

记忆:mix release 打包 OTP VM + 应用(_build/prod/rel/my_app)——目标机零依赖启动 bin/my_app start;配合环境变量注入配置,升级可走热升级。


9. CI 集成与常见陷阱

9.1 GitHub Actions 流水线

- uses: erlef/setup-beam@v1
  with: { otp-version: "26", elixir-version: "1.16" }

- run: mix deps.get
- run: mix format --check-formatted
- run: mix compile --warnings-as-errors
- run: mix test
- run: mix credo --strict

9.2 常见陷阱

✗ 忘提交 mix.lock → 依赖不一致
✗ 测试连外部服务 → 用 :meck / Ecto sandbox
✗ 生产配置硬编码密钥 → 必须环境变量
✗ 发布忘了 config_env → prod 配置不生效
✗ CI 里直接 mix deps.get(无锁文件)→ 用 mix.lock

记忆:CI 流水线 = setup-beam + deps.get + format/compile –warnings-as-errors + test + credo;陷阱——mix.lock 入库、测试隔离外部服务、密钥环境变量注入、发布按 config_env 加载生产配置。


10. 速查表与一句话记忆

场景命令/做法
脚手架mix new –sup
依赖mix deps.get + mix.lock
编译mix compile / –force
测试mix test / –cover
规范mix format / credo
类型mix dialyzer
发布MIX_ENV=prod mix release
启动bin/my_app start
自定义use Mix.Task

一句话记忆:Mix 工程化 = 一站式工具链(mix new 脚手架、mix deps 依赖管理走 Hex + mix.lock 锁定、mix compile 增量编译、mix test + format + credo + dialyzer 质量四件套、mix release 打包 OTP VM 零依赖发布);配置分层 config.exs + config_env().exs、生产密钥环境变量注入;自定义任务 use Mix.Task 标准化脚本;CI 用 setup-beam + deps.get + format/compile –warnings-as-errors + test + credo 全部门禁——构建出的应用是 OTP 应用,与 Erlang 热升级/监控生态无缝衔接。"


延伸阅读

  • /elixir-intro-phoenix/ — Elixir/Phoenix 基础
  • /elixir-testing-property/ — 测试方法论
  • /erlang-hot-code-upgrade/ — OTP release 与热升级
  • /erlang-otp-framework/ — OTP 应用结构
  • /erlang-production-cases/ — 生产实践案例
  • [[devops]] — 部署运维与 CI/CD
  • [[tools]] — 开发工具链
  • Mix 官方文档
  • Hex 包管理文档

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「erlang」更多文章

  1. 自定义 OTP Behaviour 实战:Callback 规范与行为封装
  2. Phoenix Channels 实时通信实战:WebSocket 与 PubSub 深入
  3. LiveView 进阶实战:状态管理、并发与性能优化