Files

91 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 模板迁移评估:`.htm` (Lua) → `.ut` (ucode)
> **状态**:评估完成,未执行迁移。原因:本机无 OpenWrt 构建/运行环境,`.ut` 模板无法编译验证,冒然上线未经验证的 `.ut` 比保留 `.htm` 更危险(若 25.12 模板加载器优先 `.ut`,带 bug 的 `.ut` 会直接覆盖原本可用的 `.htm`)。
## 1. 背景
本项目的 LuCI 前端采用 **Lua 兼容模式**(`luci-lua-runtime` + `luci-compat`),模板为 `.htm`(Lua 代码 + `<% %>` / `<%= %>` / `<%: %>` 标签)。
| LuCI 版本 | 模板体系 | 本项目的 `.htm` |
|-----------|----------|------------------|
| 23.05 | Lua(`.htm`) | ✅ 原生支持 |
| 24.10 | ucode(`.ut`)为主,Lua 兼容层保留 `.htm` | ✅ 经 `luci-lua-runtime` |
| 25.12+ | 趋向 ucode(`.ut`),Lua 兼容层可能移除 | ⚠️ 风险点 |
调研结论(来自 LuCI 上游变更):24.10 起 `luci-base` 重写为 ucode,模板加载器优先查找 `.ut`;`.htm` 通过 Lua 兼容层继续工作。25.12 若彻底移除 `luci-lua-runtime`,则 `.htm` 失效,需 `.ut` 模板。
## 2. 涉及文件(5 个模板)
`root/usr/lib/lua/luci/view/substore/` 下:
- `subscriptions.htm` — 订阅列表(表格、token 链接、复制按钮、多表单)
- `form.htm` — 添加/编辑订阅
- `nodes.htm` — 节点查看(GET 表单筛选/排序)
- `output.htm` — 输出页(格式下拉、textarea)
- `settings.htm` — 设置页(cron 选择器、规则)
## 3. `.htm` → `.ut` 语法对照
| 事项 | Lua `.htm` | ucode `.ut` |
|------|-----------|-------------|
| 输出标签 | `<%=expr%>` | `<%= expr %>`(ucode 表达式)或 `{{= expr }}` |
| 翻译标签 | `<%:Text%>` | `<%:Text%>`(保留,语义一致) |
| 引入其它模板 | `<%+header%>` / `<%+footer%>` | `<% include("header") %>` / `<% include("footer") %>` |
| 取 HTTP 参数 | `require("luci.http")` + `http.formvalue(...)` | 预绑定全局 `http`,`http.formvalue(...)` |
| 取查询参数 | `luci.dispatcher.context.query` | 预绑定全局 `REQUEST`,`REQUEST.query` |
| 迭代数组 | `for _, v in ipairs(t) do ... end` | `for (let v in t) { ... }` |
| 条件 | `if cond then ... end` | `if (cond) { ... }` |
| 字符串拼接 | `..` | `+` |
| 三元 | `a and b or c`(有陷阱) | `cond ? a : b` |
| 取长度 | `#t` | `length(t)` |
| 索引 | `t[k]` / `t.k` | `t[k]` / `t.k` |
| 核心库调用 | `require("substore.core")` 后 `core.xxx()` | `core = include("substore/core.lua")` 后 `core.xxx()` |
## 4. 关键决策点
1. **核心库无需改写**:`/usr/share/substore/*.lua` 是纯 Lua,ucode 通过 `include()` 加载 Lua 文件并调用其函数(ucode 内置 Lua 互操作)。这是本方案最有利的一点——迁移成本集中在 5 个模板文件的“胶水代码”,核心逻辑(解析/转换/输出)不受影响。
2. **控制器**:`controller/admin/substore.lua` 目前用 `module()` + `entry()`。24.10 仍支持;若 25.12 要求 ucode 控制器(`.uc`),则需另写 `controller/admin/substore.uc`。与模板一样,属胶水层。
3. **数据存储与下载端点**:`core.lua`、`action_download` 逻辑与模板语言无关,无需迁移。
## 5. 建议的落地策略
按“能验证再迁移”原则,分步:
- **第 1 步(当前)**:保持 `.htm` + `luci-lua-runtime` 依赖,确保 23.05 / 24.10 可用。
- **第 2 步**:在真实 24.10 设备上安装,验证 `.htm` 经兼容层正常渲染。
- **第 3 步**:拿到 25.12 构建环境后,逐模板迁移为 `.ut`(可 `.htm` 与 `.ut` 并存,LuCI 优先 `.ut`),每个模板迁完即在设备上验证页面。
- **第 4 步**:25.12 若移除 Lua 运行时,同步评估控制器 `.uc` 迁移。
## 6. 示例迁移(subscriptions.htm 片段)
Lua 现状:
```html
<%
local core = require("substore.core")
local items = core.list()
for _, it in ipairs(items) do
%>
<tr><td><%=it.name%></td></tr>
<%
end
%>
```
ucode 等价:
```html
<%
let core = include("substore/core.lua");
let items = core.list();
for (let it in items) {
%>
<tr><td><%= it.name %></td></tr>
<%
}
%>
```
> 注:`include("substore/core.lua")` 的路径与 ucode 的 `LUCI_PATH` / `package.path` 解析规则有关,具体以 25.12 目标机的 `include` 路径解析为准,迁移时需在设备上确认。