JavaScript 很烂:用 Vite 和 Gleam 来构建网站吧
原文链接: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
核心观点
-
对 JavaScript 的不满:工具链很强,但语言本身从设计上就有缺陷;TypeScript 只是"安全网/胶带",治标不本。作者特别声明并非攻击 JS,只是记录个人痛点及缓解方案。
-
为什么是 Gleam:Gleam 是类型安全的函数式语言,能写出健壮、安全、并发的代码,正是 Web 所需要而 JS 欠缺的。它不像 TS 那样"给烂底子镀金",而是另起炉灶,同时保留与 JS 互操作的通道。
-
为什么配 Vite:Gleam 最初面向 Erlang(BEAM),JS 后端是后来加的,工具链尚不成熟;而 Vite 是插件驱动的"终极胶水"——热更新、打包、资源管理全能,且不在乎你写什么语言,只要最终能编译成浏览器能跑的东西。两者结合 = 函数式的安全 + 现代前端工具链的速度。
-
为什么不用 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.effect:init/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 模式),其余看官方文档即可,并建议直接读源码学习。
加入开源交流群
请加站长微信,免费进入交流群,和开源爱好者一起讨论。