A Forth-inspired language for writing websites
A Forth-inspired language for writing websites
一种受 Forth 语言启发、用于编写网站的编程语言
I don’t remember where the idea came from, but I decided that it would be cool if I could write websites using a stack-based language. Something like this: 我不记得这个想法最初是怎么来的了,但我决定,如果能用一种基于栈(stack-based)的语言来编写网站,那一定会很酷。就像这样:
: h1 ( s -- ) "<h1>" emit . "</h1>" emit ;
"Hello, World!" h1
So I wrote Forge. I quickly built a library of word definitions that let me easily add microformats to the HTML: 于是我编写了 Forge。我很快构建了一个词汇定义库,让我可以轻松地将微格式(microformats)添加到 HTML 中:
: post-content "Hello, world! This is my first post with Forge!" p ;
: post-body
h-entry-start
"<p class='byline'>" emit "2026-05-21T14:00:00Z" "May 21, 2026" dt-published " · by " emit "Beto" "/about" p-author "</p>" emit
h-entry-end
"On building a tiny stack-based web language." p-summary
"post-content" e-content
"/hello-world" "permalink" u-url ;
"Hello, world!" "post-body" blog-post
Each site is a collection of pages, a library of words, and a stylesheet: 每个网站都是由页面集合、词汇库和样式表组成的:
my-site
├── lib.forge
├── style.css
└── pages
├── about.forge
├── hello.forge
└── notes.forge
A single binary runs the website: 只需一个二进制文件即可运行该网站:
forge --log forge.log my-site/
The binary does a lot. It has a webassembly compiler that generates HTML from .forge files. When you visit a page the compiler runs on the backend, and you get the actual HTML in the source code, as well as the original .forge source. But when you navigate between pages, a service worker captures the network request to the page, say, /notes, fetches the source (/notes.forge), and builds the HTML on the fly by running the compiler on the browser. So we have server-side rendering for crawlers and WebMentions, and client-side rendering for a SPA experience.
这个二进制文件功能强大。它内置了一个 WebAssembly 编译器,可以将 .forge 文件生成为 HTML。当你访问页面时,编译器会在后端运行,你不仅能获得源代码中的实际 HTML,还能获得原始的 .forge 源文件。但当你切换页面时,Service Worker 会捕获对页面(例如 /notes)的网络请求,获取源文件(/notes.forge),并通过在浏览器中运行编译器来即时构建 HTML。因此,我们既为爬虫和 WebMentions 提供了服务端渲染(SSR),又为单页应用(SPA)提供了客户端渲染体验。
I love the limitations of the language. You can persist things to state, localStorage, or to an append-only log on the server. For example, I can add a “like” button to posts like this: 我喜欢这种语言的局限性。你可以将数据持久化到状态、localStorage 或服务器上的追加日志(append-only log)中。例如,我可以像这样给文章添加一个“点赞”按钮:
: like-button ( -- ) "❤" "do-like" on-click ;
: do-like "1" "likes:demo" log-append ;
: body "I liked this!" p like-button ;
When you click it, it appends the value “1” to the topic “likes:demo” in the log. It’s just JSONL (one JSON document per line). Forms can submit to other .forge pages, and they simply put the contents in the stack for them. It’s up to the target to use log-append to store in the backend.
当你点击它时,它会将值“1”追加到日志中名为“likes:demo”的主题下。这只是 JSONL 格式(每行一个 JSON 文档)。表单可以提交到其他 .forge 页面,它们只需将内容放入栈中即可。至于如何存储到后端,则由目标页面决定是否使用 log-append。
I like how weird it is. I might use it for my site, who knows? For now I’m just exploring some ideas. 我喜欢这种怪异感。谁知道呢,也许我会用它来搭建我的网站?目前我只是在探索一些想法。