混合光泽与灵药
更新:这只是一个初步探索。现在已经有了一个包含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
如果不行,您可以按照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 ..
现在我们需要创建 mix 编译器任务。我们将其放在一个lib/mix/tasks/compile目录中,该目录的名称与我们需要赋予它的模块名称相同Mix.Tasks.Compile.Gleam。因此,我们创建新目录:
mkdir -p lib/mix/tasks/compile/
并将以下代码添加到名为 . 的文件中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
这样做实际上只是直接运行 gleam 编译器,并使用“build”参数来构建它能找到的所有 gleam 文件。
运行 Elixir 编译器,以便在尝试使用该 mix 任务之前对其进行编译。
mix compile.elixir
现在为了让 Gleam 正常工作,我们需要为其设置一个配置文件。因此,我们在项目根目录下.toml创建一个名为 `.gleam.config` 的文件,并添加以下内容。gleam.toml
name = "my_app"
然后我们创建一个src目录来存放 Gleam 文件。Gleam 编译器要求 Gleam 文件位于一个src目录中。这与 Elixir/mix 不同,后者默认要求文件位于lib目录中。Elixir/mix 可以进行配置,但截至撰写本文时,Gleam 尚不支持此操作。
mkdir src
然后,我们通过创建一个名为 `Gleam` 的文件来创建我们的 Gleam 模块,src/hello_world.gleam并在其中放入以下代码:
pub fn hello() {
"Hello, from gleam!"
}
接下来,我们对文件进行以下更改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(),
我假设 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
这是因为 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>
终于可以运行了:
mix compile
mix phx.server
在浏览器中加载后,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