You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/wiki/development/development.md

207 lines
5.2 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Basic | basic
Hydro 后端使用 NodeJS 编写,前端使用 JQuery + React。
代码风格遵循 airbnb 标准(详见 .eslintrc.js
由于模块中不能使用 require() 引入 Hydro 的文件,因此需要从 global.Hydro 中取出需要的模块。
例:
```js
const { db } = global.Hydro.service;
const { problem } = global.Hydro.model;
```
# Module | module
## 文件架构
Hydro 的模块由以下几个部分组成:
service: 服务
script: 脚本
handler: 访问路由
lib: 库
model: 数据库模型
file: 额外文件
locale: 多国化
template: UI 模板
README.md: 介绍
hydro.json: 声明文件(必须)
## 模块编译
使用 `hydro-build` 进行编译。
安装:`yarn add hydro-build -D`
编译:`hydro-build`
如果命运的齿轮没有出差错,您应该可以找到生成的.hydro文件了。
# Hydro.json | hydro
Hydro.json 是模块的声明文件,格式如下。
```json
{
"id": "模块ID",
"version": "模块版本",
"description": "模块描述"
}
```
# Handler | handler
通常用于提供页面路由。
例:注册新路由:
```js
const { Handler, Route } = global.Hydro.service.server;
const { user, builtin } = global.Hydro.model;
class CustomHandler extends Handler {
async prepare() {
this.checkPriv(builtin.PRIV.PRIV_USER_PROFILE);
// this.checkPerm(), this.user.hasPerm(), this.user.hasPriv(), etc.
}
async get(){
this.response.template = 'user_login.html';
}
async post({ username, password }) {
const udoc = await user.getByUname(username);
udoc.checkPassword(password);
this.response.body = { udoc };
}
async postConfirm() {
// 当提交表单并存在 operation 值为 confirm 时执行。
}
}
async function apply() {
Route('/route/:username', CustomHandler);
}
global.Hydro.handler.handlerName = apply;
```
在路由中定义所有的函数应均为异步函数,支持的函数如下:
prepare, get, post, post[Operation], cleanup
具体流程如下:
先执行 prepare(args) (如果存在)
args 为传入的参数集合(包括 QueryString, Body, Path中的全部参数
再执行 prepare(args) (如果存在)
检查请求类型:
```
为 GET
-> 执行 get(args)
为 POST ?
-> 执行 post(args)
-> 含有 operation 字段?
-> 执行 post[Operation]
```
执行 cleanup()
如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。
* 在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。
`<input type="hidden" name="operation" value="confirm_delete">` 对应 `postConfirmDelete` 函数。
应当提供 `apply` 函数,并与定义的 Handler 一同挂载到 `global.Hydro.handler[模块名]` 位置。
`apply` 函数将在初始化阶段被调用。
### 表单验证
若使用 Typescript 开发插件,可使用 Hydro 提供的验证工具。
`@param` 会修改 arguments首个参数为请求所在的 domainId剩余参数为指定的内容。
```ts
const { Handler, Route, Types, param } = global.Hydro.service.server;
const { user, builtin } = global.Hydro.model;
class CustomHandler extends Handler {
async prepare() {
this.checkPriv(builtin.PRIV.PRIV_USER_PROFILE);
}
async get(){
this.response.template = 'user_login.html';
}
@param('username', Types.String)
@param('password', Types.String)
async post(domainId:string, username:string, password:string) {
const udoc = await user.getByUname(username);
udoc.checkPassword(password);
this.response.body = { udoc };
}
}
export async function apply() {
Route('/route/:username', CustomHandler);
}
global.Hydro.handler.handlerName = apply;
```
若使用 Javascript 开发插件,则可使用 `global.Hydro.lib.validator` 中提供的相关工具。
# Service | service
通常用于提供与其他程序对接的接口或启动其他外部程序。(如内置的 MongoDB / 外置的沙箱模块等)
# Lib | lib
库文件。通常用于提供一些功能(废话)。
# File | file
file 文件夹下的所有文件将被自动解压到 `$TMPDIR/hydro/模块ID/路径` 的位置权限755通常用于启动子进程
# Locale | locale
用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。
# Template | template
页面模板,使用 [nunjucks](https://mozilla.github.io/nunjucks/cn/templating.html) 语法。
传入了 _ 翻译函数与 model 等。
```html
{% set page_name = "page_name" %}
{% extends "layout/basic.html" %}
{% block content %}
<div class="error__container clearfix">
<div class="error__icon-container">
<div class="error__twd2"></div>
</div>
<div class="error__text-container">
<h1>{{ _('Oops!') }}</h1>
<p>{{ _(error.message).format(error.params) }}</p>
<p>{{ _('Technical Information') }}:</p>
<p>{{ _('Type') }}: {{ error.code }}</p>
<p>{{ _('Arguments') }}:
<ol>
{% for param in error.params %}
<li>{{ param }}</li>
{% endfor %}
</ol>
</p>
</div>
</div>
{% endblock %}
```
<blockquote class="note">请不要覆盖已有模板。</blockquote>
# README.md | readme
项目的说明文件。