一门语言。
一个文件。
整个 Web 都在这里。
SpaceFive 是一个用纯 Five 写成、开箱即用的 Web 框架。HTTP、WebSocket、PostgreSQL、bcrypt、AES、多语言,全都由运行时直接完成。不用 Node,不用 FFI,也不用 ORM 服务器。一个静态可执行文件直接对接 Postgres,上面跑着三个真实的应用——此刻正在运行。
—
在册资产
—
资产总值
—
在职员工
1
可执行文件
01 — 在线演示
三个应用, 一套框架,
一种质感。
你点到的每一处,背后都是一个 Five 处理函数:局部刷新的超媒体更新、服务端渲染的表单、CSV 导出、照片上传、实时事件。
02 — 写过 xBase 或 Harbour?
这门语言,你早就会了。
变的只是屏幕。
如果你写过 Clipper、FoxPro 或 Harbour,SpaceFive 的页面读起来就像你写过几百遍的对话框。下面的例子全是真的:右边的控件,就是左边这段代码在本次请求里当场画出来的。
MENU hMenu MENUBAR MENUITEM "Assets" ACTION "/assets" MENUITEM "People" ACTION "/people" MENUITEM "+ New asset" ACTION "/assets/new" GOLD ENDMENU cHtml := MENU_HTML( hMenu )
hStat := DB_ONE( cAssetStats, {} ) DASHBOARD hDash STAT "Total assets" VALUE hStat[ "n" ] GOLD STAT "Total value" VALUE Money( hStat[ "total" ], "USD" ) GOLD STAT "Active" VALUE hStat[ "active" ] OK STAT "In maintenance" VALUE hStat[ "maint" ] WARN ENDDASHBOARD cHtml := DASH_HTML( hDash )
aRows := DB_QUERY( cFirstEmployees, {} ) TABLE hList OF aRows LINK "/people/:id" COLUMN "name" HEADER "Employee" THUMB "photo" SUB "emp_no" COLUMN "position" HEADER "Position" COLUMN "status" HEADER "Status" BADGE COLUMN "salary" HEADER "Salary" MONEY CURRENCY "currency" RIGHT ENDTABLE cHtml := TABLE_HTML( hList )
GALLERY hCards OF aRows LINK "/people/:id" CARD PHOTO "photo" INITIALS "name" CARD BADGE "status" CARD TAG "position" CARD TITLE "name" CARD META "department" CARD VALUE "salary" CURRENCY "currency" ENDGALLERY cHtml := GALLERY_HTML( hCards )
FORM hForm ACTION "/people" OF hReq GET "emp_no" LABEL "Employee no." VALUE "E-2001" GET "name" LABEL "Name" COMBO "status" LABEL "Status" VALUE "active" ITEMS aStatuses GET "salary" LABEL "Salary (annual)" VALUE 90000 BUTTON "Save" GOLD LINK "Cancel" ACTION "/" ENDFORM cHtml := FORM_HTML( hForm )
从 DOS 屏幕到浏览器
| 当年这么写 | 现在这么写 | 作用 |
|---|---|---|
| @ 10, 5 SAY "Name" GET cName | GET "name" LABEL "Name" VALUE cName | 表单里一个带标签的输入框。 |
| MENU oMenu … MENUITEM … ENDMENU | MENU hMenu MENUBAR … MENUITEM … ENDMENU | 页眉按钮、侧栏筛选、选项卡,一套写法全搞定。 |
| TBrowse / dbEdit() | TABLE hList OF aRows … COLUMN … ENDTABLE | 可点击的列表,自带缩略图、徽章和金额列。 |
| USE customers INDEX ON name | aRows := DB_QUERY( cSql, { cName } ) | 参数绑定,直接查 PostgreSQL,没有 ORM 服务器。 |
| SET COLOR TO W+/B | public/skins/<skin>/skin.css | 外观交给皮肤:设计师能直接改的 CSS 和几个小 HTML 模板。 |
| ACTIVATE WINDOW oWnd | FV_SERVE( nPort, "public", {| hReq | APP_DISPATCH( hReq ) } ) | 整个 Web 服务器,就是 main.prg 里的一行。 |
03 — 原理
运行时直接上手, 不靠胶水。
每一层都是 Five 运行时库的调用。除了 PostgreSQL,什么都不用装。
FV_SERVEHTTP 全程自己来
收请求头和 Cookie,回状态码和 set-cookie。每个请求跑在自己的 VM 线程里。
WsServe · WsSend实时
零依赖的 WebSocket 服务器,本页底部的动态流正在监听它。
PG_OPEN · PG_QUERY直连 PostgreSQL
基于 pgx 的参数绑定查询。迁移在启动时自动执行,跑多少次结果都一样。
PWHASH · ENCRYPT · SECEQ默认就安全
bcrypt 密码、AES-256-GCM 会话、恒定时间比较、CSRF 双重提交。
T()内置多语言
目录式翻译,按请求决定语言。你正在看的这一页,就是由 locales/*.json 用六种语言提供的。
hx.js超媒体 UI
54 行的 HTMX 风格小垫片:局部替换、CSRF 头,没有构建步骤,也没有前端框架。
04 — 代码
请求是哈希,响应也是哈希。
处理函数就是一个代码块。
这是正在运行的应用里真实的路由表和真实的处理函数。
// asset manager — gallery, list, detail, CRUD, export ROUTE( "GET", "/assets", {| hReq | ASSET_DASHBOARD( hReq ) } ) ROUTE( "GET", "/assets/cards", {| hReq | ASSET_CARDS( hReq ) } ) ROUTE( "POST", "/assets", {| hReq | ASSET_CREATE( hReq ) } ) ROUTE( "GET", "/assets/export.csv", {| hReq | ASSET_EXPORT( hReq ) } ) // main.prg — the whole server FV_SERVE( hCfg[ "port" ], "public", {| hReq | APP_DISPATCH( hReq ) } ) // a handler: query → hash → JSON. The result lives in a variable; RETURN returns it. FUNCTION ASSET_LIST( hReq ) LOCAL aRows := Rows( hReq, 1000, 0 ) LOCAL hRes := RES_JSON( { "ok" => .T., "assets" => aRows, "count" => Len( aRows ) } ) RETURN hRes






