三层架构
在Oak框架中,前端部分的结构可以由高到低分为三个层次,如下图所示:

namespace
namespace是指应用在最顶层被划分成几个命名空间,每个命名空间中包含若干页面,命名空间一般按顶层路由来划分,同一个命名空间中的整体布局是相同的。例如,一个典型的网站会分为frontend和console两个命名空间,分别代表普通用户访问的前端和管理人员访问的控制台。前者有统一的header(页头)和footer(页脚),而后者还会有统一的menu(菜单)。这些跨页面级别的组件摆放是在命名空间里处理的。
一般而言一个应用不会有过多的命名空间,命名空间被放置在web/src/app/namespaces目录下。目录名称是命名空间的key;web端实际路由前缀默认由目录名称决定,也可以通过命名空间配置中的route.path覆盖。
当前版本中,命名空间目录下使用index.config.ts配置此命名空间。例如web/src/app/namespaces/frontend/index.config.ts中,往往有如下配置:
import { CreateNamespaceConfig } from '@oak-frontend-base/config';
export default CreateNamespaceConfig({
route: {
path: '/',
first: 'home',
notFound: '/result/notFound',
},
access: {
unconfiguredAccess: 'allow',
},
});
这代表此命名空间的路由前缀是根目录,首页指向home页面,也就是*/home*;当应用出现无法识别的路由时,会自动指向*/result/notFound*。access.unconfiguredAccess用于声明未单独配置访问规则的页面默认如何处理,常见取值为allow、deny或login。
管理端命名空间还可以在index.config.ts里声明菜单分组和运行时feature配置,例如:
import { CreateNamespaceConfig } from '@oak-frontend-base/config';
export default CreateNamespaceConfig({
menu: {
groups: [
{
name: 'System',
icon: 'setup_fill',
order: 0,
},
],
},
access: {
unconfiguredAccess: 'deny',
},
features: {
console: {
contextEntities: ['system'],
},
},
});
页面可以在自己的index.config.ts中声明menu和route.access,Oak CLI会把页面配置和命名空间配置合并生成web/src/app/namespaces/allNamespaceConfigs.ts。这个文件是生成物,不应手工修改;应用入口应通过web/src/app/namespaces/index.ts导出它,并在web初始化时把namespaceConfigs传给oak-frontend-base/platforms/web/initialize。
一个命名空间下有哪些页面?在Oak框架中这是由src/pages目录下的目录结构自动决定的,在pages目录下,第一层目录是和命名空间名称对应的,其下的每个目录中的page就会被自动编译到对应的namespace下。
命名空间之间的跳转建议在全局统一且唯一(例如在frontend命名空间可以通过点击页上的“控制台”进入console命名空间),不要在普通页面之间跳转的时候跨越命名空间,这会容易让用户思维陷入混乱。
在大部分情况下,命名空间应该只存在于web端,对于小程序和App,一般不宜设计namespace,免得应用过于复杂。
page
一个page是前端的一个页面。page编写在src/pages/${namespace}目录下,每一个页面对应目录下的一个子目录。其路由和目录名保持相同。例如,在src/pages/frontend/home目录下的页面就会匹配到/home或/(参见上一小节中frontend命名空间的配置)。
虽然并非强制,但推荐在src/pages/${namespace}下的page目录的第一层用该页面相关的entity名称命名,第二层可以用list/detail/upsert之一,或者该entity的某个Action来加以命名(如果页面的功能就是对此entity进行此action的话),这样此页面的功能看上去就一目了然。当然,对于像首页这样的复合性页面(并不是限定在某个entity上),您可以自由对之进行命名,只要这个命名让用户看上去很容易理解。
component
一个component代表一个固定功能的组件。组件编写在src/components目录下,同样是一个子目录代表一个组件。编写组件的目的是:
- 为了在多个page之间复用代码
- 避免page过于复杂
在Oak中,一个page可以包含多个component,一个component也可以引用其它component,但在component之间不能出现循环引用。
page之间不要相互引用,尽管这样做也不会错,但会让整个项目变得更加混乱,难以维护。