Gleam / 博客文章

JavaScript 很烂:用 Vite 和 Gleam 来构建网站吧

07-16 22:50

原文链接:https://hendassa100k.github.io/posts/2026-07-11-gleam-and-vite/

原标题:JavaScript sucks. Here's how to build with Vite and Gleam
发布于:2026-07-11

核心观点

  1. 对 JavaScript 的不满:工具链很强,但语言本身从设计上就有缺陷;TypeScript 只是"安全网/胶带",治标不本。作者特别声明并非攻击 JS,只是记录个人痛点及缓解方案。

  2. 为什么是 Gleam:Gleam 是类型安全的函数式语言,能写出健壮、安全、并发的代码,正是 Web 所需要而 JS 欠缺的。它不像 TS 那样"给烂底子镀金",而是另起炉灶,同时保留与 JS 互操作的通道。

  3. 为什么配 Vite:Gleam 最初面向 Erlang(BEAM),JS 后端是后来加的,工具链尚不成熟;而 Vite 是插件驱动的"终极胶水"——热更新、打包、资源管理全能,且不在乎你写什么语言,只要最终能编译成浏览器能跑的东西。两者结合 = 函数式的安全 + 现代前端工具链的速度。

  4. 为什么不用 WASM:当前 WASM 不适合 Web 开发——DOM 访问受限、启动耗时有问题。JS 是"Web 的 C 语言",是与 DOM 交互最标准、最兼容的方式,不可替代。Gleam 的思路正基于此:不试图取代 JS,而是把 JS 当作 FFI 对象安全地调用。

技术要点

① Gleam FFI 的工作方式

  • 通过 @external(javascript, "路径", "函数名") 声明外部函数,把 JS 实现挂进 Gleam。
  • Gleam 不允许直接引入动态 JS 对象。必须定义一个无构造器的类型(如 pub type DateTime)作为 JS 值的"句柄",把混乱隔离在 FFI 边界之外,应用内部全程类型安全。
  • JS 没有 Result 类型(只有异常),Gleam 提供 gleam.mjs 模块,可在 JS 侧用 Result$Ok / Result$Error 把 try/catch 映射成 Gleam 的 Result

② 用 Lustre 框架写应用

  • Lustre 是成熟的 Gleam 前端框架,采用 Elm 架构(Model-View-Update),类 React 开发者容易上手:Model(状态)+ Message/update(消息驱动更新)+ view(渲染为 Element)。
  • 虽然作者讨厌 Virtual DOM,但承认它比"脆弱的手动 query selector"安全——每个 UI 元素都严格绑定到应用状态。

③ 最大痛点:在 Gleam 里处理 JS Promise

  • 解法是用 lustre.effectinit/update 返回 #(Model, Effect) 元组,副作用在 Effect 中执行。
  • 模式:effect.from(fn(dispatch) { ... }) 内调用返回 Promise 的 FFI 函数,用 promise.map 把结果转成 Lustre 能理解的 Message(如 AssetLoaded),再用 promise.tap(dispatch) 在 Promise resolve 后把消息派回应用循环。
  • 细节:Gleam 没有 return,函数返回最后一个表达式的值;promise.tap 会返回 Promise 本身,但这里不需要,所以末尾显式写 Nil 丢弃。
  • 收益:配合 Vite 实现资源的懒加载(如 SVG 按需加载),消息到达后存入 Dictionary,避免一次性导入全部静态资源。

结论

Gleam(类型安全逻辑)+ Vite(构建管线)是"远离 JS、走向更体面开发"的可行组合。作者开源了模板代码,文章只覆盖了开发中遇到的最难点(FFI 边界、Promise 桥接、Effect 模式),其余看官方文档即可,并建议直接读源码学习。

加入开源交流群

请加站长微信,免费进入交流群,和开源爱好者一起讨论。

站长微信二维码