拷贝
为 n 个副本 C1,C2...Cn, 即表示为 P1->C1,P2->C2...Pn->Cn。相同
工作由不同
人员重复产出,千人千面,质量参差不齐
直至失控子模块
之间的协作依据,并编写自动化工具强制
遵循这些约定。子模块
使用引用
( 而不是传统拷贝
)的方式组合起来。聚合项目目录结构约定
root
└── src
├── module-${子模块优先级1}-${子模块后缀名1}
└── module-${子模块优先级2}-${子模块后缀名2}
优先级格式 ([0-9]|[a-z]){2},如 01, ab, 9c,ASCII 码序号越大优先级越高,即 0 < 9 < a < z
root
└── src
├── module-00-codebase
└── module-99-my-module
聚合工程与子模块目录结构关系与约定( pkg-序号 只是为了 IDE 自动排序方便 )
root
├── src
│ ├── module-00-codebase
│ │ ├── pkg-00-const // 常量配置
│ │ ├── pkg-01-container // IOC 容器
│ │ ├── pkg-02-tool // 自耦工具库(纯函数)
│ │ ├── pkg-03-abstract // 常用抽象类
│ │ ├── pkg-04-virtual // 为实现 IOC 产生的编译过程临时文件
│ │ ├── pkg-05-behavior // 行为,与无关视图独立模块
│ │ ├── pkg-06-elmt // UI 组件
│ │ ├── pkg-07-route // 页面即路由
│ │ ├── pkg-08-entity // 常用数据结构,如 Rpc 请求返回的数据结构
│ │ ├── pkg-09-starter // 软件启动函数
│ │ ├── pkg-99-prebuild-node-script // 聚合打包的脚本
│ │ ├── pkg-a0-default-root-case // 缺省地深拷贝到根目录
│ │ ├── pkg-a1-cover-root-case // 强制地深拷贝到根目录
│ │ └── .gitignore
│ └── module-01-workflow
│ ├── pkg-05-behavior
│ ├── pkg-06-elmt
│ └── pkg-07-route
│
├── .gitignore
├── .gitmodules
├── package.json
├── tsconfig.json
└── yarn.lock
创建一个空文件夹作为聚合工程
根目录
mkdir root-folder && cd root-folder
初始化 git
git init
使用 git submodule 引用既有子模块(如本子模块)到 src/module-优先级-任意命名
git submodule add GIT_URL_1 src/module-01-name1
git submodule add GIT_URL_2 src/module-02-name2
git submodule add GIT_URL_3 src/module-03-name3
(可选) 根据需要和命名规范在 src 目录像创建普通 git 项目一样,创建新的子模块,创建的形式不限,以下代码仅简单举例
mkdir module-ab-my-module
cd module-ab-my-module
# ...
# 省略 git 初始化和提交脚本
# ...
最后在聚合项目根目录
子模块的使用不仅于此,更多的细节请参考官方文档,如『追踪分支』而不仅是一个『游离的提交』
实际开发在子中完成,所有 pkg 文件夹都是可选的,最经常涉及的是:
├── pkg-05-behavior // 行为,与固定视图无关的独立模块
├── pkg-06-elmt // 视图组件
├── pkg-07-route // 页面即路由
在 pkg-05-behavior 文件夹下创建 /**/${BehaviorName
}/index.ts(x) 文件, 新增一个行为
// 该行为的能力定义和实现
export class ClassNameMattersNothing {
public behaviorMethod() {}
}
// 该行为依赖的其它行为类名
export const dependencies = () => ["Rpc", "DateFormat"];
// 在初始化中该行为初始化的优先级
export const order = () => 10;
// 行为初始化逻辑,可理解为异步版构造函数
export const initializing = async () => {};
在任意地方通过 Bi.behaviorName.behaviorMethod() 调用,无需 import
该模块
import { Bi } from "@/pkg-01-containner";
Bi.behaviorName.behaviorMethod();
在 pkg-06-elmt 文件夹下创建 /**/${ElmtName
}/index.tsx 文件, 新增一个组件
export class Any extends BaseElmt<[string, number, Date], Any> {
public elmtView() {
return (
<>
<span>{`${this.getParams(0)}`}</span>
<span>{`${this.getParams(1)}`}</span>
<span>{`${this.getParams(2)}`}</span>
</>
);
}
}
在任意地方通过 Ei.ElmtName 引用该组件, 无需 import
该组件,注意定义时与使用时的类型约束
<Ei.ElmtName params={["string",10,new Date()]}> />
在 pkg-07-route 文件夹下创建 /${route
}/index.tsx 文件, 新增一个 路由
为 route
的页面
export class Any extends BasePage{
public pageView(){
// 当前 pathname === 本页面路径,加载本页面
if(this.pageRoutePath() === Bi.navigate.currentPageRoutePath()){
return <Ei.ElmtName params={["string",10,new Date()]}> />;
}else{
// 当前 pathname indexOf 本页面路径 === 0 加载子页面
return this.childView();
}
}
}
无需主动在其它地方调用或配置,页面将根据文件夹相对路径自动装配路由
childView 是该页面的直接子页面,如 "/a/b" 和 "/a/c" 是 "/a" 的直接子页面之一
└── pkg-07-route
└── a
├── index.tsx /a
├── b
│ └── index.tsx /a/b
└── c
└── index.tsx /a/c
保留了 React 脚手架的使用习惯, 使用 yarn start 和 yarn build 在聚合项目根目录
启动或打包
yarn && yarn start
yarn && yarn build
行为类 | 作用 | API 简要说明 |
---|---|---|
Broker | 订阅发布、状态管理 | read(propertyPath:string) / write(propertyPath:string,value:any) |
DataExchange | 增强的数据交换,替代 JSON.stringify / parse | 略 |
Log | 日志管理 | info / debug / warn / error |
Renderer | 跨端渲染器 ( Web / 多平台小程序 / 混合 App ) | render(content:Element.JSX,container:Element.JSX) |
Utils | 常用工具函数、纯函数 | 大量通用函数无法一一列举 |
StyleRenderer | 样式渲染 | render( style: string| {[key:string]:any}|Array<string|{[key:string]:any}>) |
RootRenderer | 根组件初始化 | 初始化逻辑,无 API |
WebCleaner | 浏览器默认样式清除 | 初始化逻辑,无 API |
CacheManager | 持久化缓存 | read / write / clean |
Cover | 遮罩 | on / off |
Loading | 遮罩+载入中 | on / off |
RpcHandle | Rpc 结果通用处理逻辑 | success |
Rpc | Rpc 远程过程调用 | send(data:any):Promise<RpcResult> |
PropertyDescription | Schema 管理器 | get(resourceName:string,property?:string):FieldI / getProperties(orefType: any, collectType: string): string[] / getPropertyGroup(orefType: any, collectType: string): PropertyGroup |
CurdPageInitializer | 根据 Schema 动态创建初始化 Admin 管理端 UI | 只做初始化用,无 API |
DateFormat | 时间日期格式化 | parse(dateStr:string,format="yyyy-MM-dd HH:mm:ss") / format(date:Date,format="yyyy-MM-dd HH:mm:ss") |
Dialog | 模态弹窗组件 | on(Element.JSX) / off() |
Dict | 数据字典 | get(group:string,code:string):string |
Entrance | 应用启动入口 | enter():Promise<void> |
HistoryFactory | 历史管理 | push(route: string):void / back():void / replace(route: string):void / getLength(): number / getCurrentRoute() :string / getHistory() :History |
I18n | 国际化 | translate(template: string, ...args: any[]):string |
UserManager | 用户管理 | getUser():Promise<User> |
MenuManager | 菜单管理 | getMenus():Promise<Menu[]> |
Navigate | 路由导航管理 | replace(target: string, args?: any):Promise<void> / forward(target: string, args?: any):Promise<void> / getCurrentRoutePath():string / back():void |
PermManager | 权限管理 | has(perm:string):boolean / refresh():Promise<void> |
Sign | 登入登出 | in / out |
Sys | 系统参数读取 | get(key:string):string |
Validator | 表单验证 | validate(type: string, field: Field, data: any):Promise<\string> |
名称 | 作用 | 入参 |
---|---|---|
Layout | 布局容器 | 无 |
DataField | 页面表单输入 | FieldI, any |
DataBoard | 各种数据类型的面板 | FieldI, any |
Button | 按钮 | 无 |
Icon | 内置图标 | string |
Image | 图片 | {src?:string,location?:string} |
List | 列表 | resourceName:string,properties:string[],criterions:Criterion[] |
Map | 地图及锚点显示 | MapPoint[] |
Menu | 管理端导航菜单 | Menu[] |
Text | 文本 | string |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。