发布于 2026-01-06 0 阅读
0

混合光泽与灵药

混合光泽与灵药

更新:这只是一个初步探索。现在已经有了一个包含mix_gleam插件的正式项目。请查看!


Contact Stack,我们选择了 Elixir 和 Phoenix 作为技术栈的核心,并且对这个选择很满意。但是……我们确实怀念一个优秀的类型系统和一个好用的编译器(比如Elm),它们可以指导我们完成开发。

Elixir 的目标平台是 BEAM 虚拟机,而支持 BEAM 的静态类型语言也寥寥无几。本文将介绍如何使用Mix 编译器任务将Gleam集成到 Elixir 项目中

Gleam 是一种静态类型函数式编程语言,其语法对 JavaScript、C 或 Java 程序员来说比某些 ML 类语言更容易上手。Gleam 编译器用 Rust 编写,输出 Erlang 源文件,这些源文件随后可以由 Erlang 编译器编译成 BEAM 文件。

Mix 是一个用于 Elixir 项目的多功能构建工具。它可以管理依赖项、运行测试、执行任务并编译 Elixir 代码。它默认支持编译 Erlang 文件,并且可以通过 Mix 编译器任务扩展以编译其他语言。我们将创建一个用于 Gleam 的 Mix 编译器任务,以便 Mix 可以使用 Gleam 编译器来构建 Gleam 文件。

您可以自行尝试以下步骤,并查看演示存储库:https://github.com/michaeljones/gleam-phoenix-mix

开始了!

我们假设您gleam的环境中已安装了编译器。运行此命令进行检查。

gleam --version
Enter fullscreen mode Exit fullscreen mode

如果不行,您可以按照Gleam 文档中的安装说明进行操作。

现在我们将从零开始搭建一个Phoenix项目。我们不会深入细节,只是为了让我们有一个清晰的基础。

运行以下命令来创建一个空的 Phoenix 项目:

mkdir gleam-phoenix-mix
cd gleam-phoenix-mix
mix phx.new . --app my_app
mix ecto.create
cd assets 
npm install
cd ..
Enter fullscreen mode Exit fullscreen mode

现在我们需要创建 mix 编译器任务。我们将其放在一个lib/mix/tasks/compile目录中,该目录的名称与我们需要赋予它的模块名称相同Mix.Tasks.Compile.Gleam。因此,我们创建新目录:

mkdir -p lib/mix/tasks/compile/
Enter fullscreen mode Exit fullscreen mode

并将以下代码添加到名为 . 的文件中lib/mix/tasks/compile/gleam.ex

defmodule Mix.Tasks.Compile.Gleam do
  use Mix.Task.Compiler

  def run(_args) do
    System.cmd("gleam", ["build"])
    :ok
  end
end
Enter fullscreen mode Exit fullscreen mode

这样做实际上只是直接运行 gleam 编译器,并使用“build”参数来构建它能找到的所有 gleam 文件。

运行 Elixir 编译器,以便在尝试使用该 mix 任务之前对其进行编译。

mix compile.elixir
Enter fullscreen mode Exit fullscreen mode

现在为了让 Gleam 正常工作,我们需要为其设置一个配置文件。因此,我们在项目根目录下.toml创建一个名为 `.gleam.config` 的文件,并添加以下内容。gleam.toml

name = "my_app"
Enter fullscreen mode Exit fullscreen mode

然后我们创建一个src目录来存放 Gleam 文件。Gleam 编译器要求 Gleam 文件位于一个src目录中。这与 Elixir/mix 不同,后者默认要求文件位于lib目录中。Elixir/mix 可以进行配置,但截至撰写本文时,Gleam 尚不支持此操作。

mkdir src
Enter fullscreen mode Exit fullscreen mode

然后,我们通过创建一个名为 `Gleam` 的文件来创建我们的 Gleam 模块,src/hello_world.gleam并在其中放入以下代码:

pub fn hello() {
  "Hello, from gleam!"
}
Enter fullscreen mode Exit fullscreen mode

接下来,我们对文件进行以下更改mix.exs,将我们的编译器任务添加到运行时运行的编译器列表中mix compile,并确保 Mix 的 Erlang 编译器在指定文件gen夹中查找
Erlang 文件。编译器会将指定文件夹中的文件gleam编译成目标文件夹中的文件,因此我们需要 Erlang 编译器能够找到这些文件。.gleamsrc.erlgen

       elixir: "~> 1.5",
       elixirc_paths: elixirc_paths(Mix.env()),
+      erlc_paths: ["src", "gen"],
-      compilers: [:phoenix, :gettext] ++ Mix.compilers(),
+      compilers: [:phoenix, :gettext, :gleam] ++ Mix.compilers(),
       start_permanent: Mix.env() == :prod,
       aliases: aliases(),
Enter fullscreen mode Exit fullscreen mode

我假设 Mix 会从列表开头到结尾依次运行编译器。因此,我们希望条目:gleam位于:erlang现有条目之前Mix.compilers(),以便 Erlang 编译器在 Gleam 编译之后运行,并编译 Gleam 编译器生成的 Erlang 文件。

为了简单演示 Elixir 与编译后的 Gleam 文件之间的互操作性,请进行以下更改lib/my_app_web/controllers/page_controller.ex

 defmodule MyAppWeb.PageController do
   use MyAppWeb, :controller

   def index(conn, _params) do
-    render(conn, "index.html")
+    render(conn, "index.html", title: :hello_world.hello())
   end
 end
Enter fullscreen mode Exit fullscreen mode

这是因为 Gleam 模块被编译成 Erlang 模块,而在 Elixir 中,Erlang 模块可以通过作为其名称的原子来访问。

然后我们做出以下更改lib/my_app_web/templates/page/index.html.eex

 <section class="phx-hero">
-  <h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
+  <h1><%= @title %></h1>
   <p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
 </section>
Enter fullscreen mode Exit fullscreen mode

终于可以运行了:

mix compile
mix phx.server
Enter fullscreen mode Exit fullscreen mode

在浏览器中加载后,http://localhost:4000可以看到 Phoenix 标准欢迎页面中心显示“您好,来自 gleam!”。

如果您感兴趣,可以访问 GitHub 上的这个演示仓库查看最终结果:https://github.com/michaeljones/gleam-phoenix-mix

最后想说的话

令人兴奋的是,使用 Mix 将 Gleam 代码集成到 Elixir 项目中并不难。Mix 在设计之初就考虑到了这种可扩展性,这一点非常棒。当然,还有一些问题需要解答,一些细节需要完善,但能够在 BEAM 上使用强类型语言仍然令人振奋。

文章来源:https://dev.to/contact-stack/mixing-gleam-elixir-3fe3