1 Star 0 Fork 0

AEI/mdl-00-codebase-frontend

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
WTFPL

前端聚合架构-基础库子模块

名词解释

  1. 聚合架构:将原本臃肿的软件工程拆分为多个简洁的子工程。这些子工程既能够独立工作、又能经简单组合后协同工作。独立的子工程和其任意组合而成聚合工程的这种形式之为『聚合架构』。
  2. 子模块:能够相互组合后协同工作、往往也能够独立工作的工程。在人员编排中通常不同的子模块从属不同的人或项目组负责,他们之间的信息是隔离的,并且由于已经约定了统一的开发规范,不同子模块之间不需要任何额外的信息沟通。
  3. 聚合工程:根据项目需要,通常以简单罗列的方式,将需要的子模块以扁平结构以『引入』的方式组合起来而得的软件系统。这里『引入』是强调聚合工程仅仅是起到配置的作用,真正的编码开发工作在子工程中。

聚合架构的意义和目的

结论先行:聚合架构的意义和目的就在于脱离传统开发模式分工界限模糊的困境

行业常见现状分析:传统开发模式中,往往存在以下情况

  1. 职责不同的开发人员工作在同一代码中,存在权限问题,带来隐患。
  2. 存在内部使用的基础代码库 C,以及基于 C 创建的项目 P1,P2...Pn。
    • 传统做法下 C 被拷贝为 n 个副本 C1,C2...Cn, 即表示为 P1->C1,P2->C2...Pn->Cn。
    • 随着 P1...Pn 的开发工作, C1...Cn 必然被分别加入工作,而这些工作最终都是重复的:都是属于 C 的工作。
    • 不难看出,这导致了更多的成本。
    • 相同工作由不同人员重复产出,千人千面,质量参差不齐直至失控
    • 质量不可控,导致不可能提炼、合并、复用 C1...Cn 的成果,无法产生技术沉淀。
  3. 篇幅有限,更存在一些复杂的实际情况,但无不是本文主要讨论的内容,就不赘述。
  4. 结论:
    • 浪费了成倍的成本。
    • 无法积累技术,丧失行业核心竞争力。

解决该问题的总体思路分析

  1. 管理上将人员细化分配,专人只做专事,解决分工界限模糊的问题。
  2. 技术上将工程细化拆分,与人员组织对应,分而治之。如采用 git submodule 子模块技术结合 access 配置。
  3. 设计和约定子模块之间的协作依据,并编写自动化工具强制遵循这些约定。
  4. 最终目标:产品发布是将子模块使用引用( 而不是传统拷贝 )的方式组合起来。

关于本工程采用的具体方案

  1. 聚合项目目录结构约定

    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
    
  2. 聚合工程与子模块目录结构关系与约定( 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
    

开发准备工作

  1. 创建一个空文件夹作为聚合工程根目录

    mkdir root-folder && cd root-folder
    
  2. 初始化 git

    git init
    
  3. 使用 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
    
  4. (可选) 根据需要和命名规范在 src 目录像创建普通 git 项目一样,创建新的子模块,创建的形式不限,以下代码仅简单举例

    mkdir module-ab-my-module
    cd module-ab-my-module
    # ...
    # 省略 git 初始化和提交脚本
    # ...
    

    最后在聚合项目根目录

    1. 在 .gitmodules 文件中添加子模块映射配置(推荐这种方式)
    2. 使用 git submodule add URL
  5. 子模块的使用不仅于此,更多的细节请参考官方文档,如『追踪分支』而不仅是一个『游离的提交』

开始功能开发:

  1. 实际开发在子中完成,所有 pkg 文件夹都是可选的,最经常涉及的是:

     ├── pkg-05-behavior             // 行为,与固定视图无关的独立模块
     ├── pkg-06-elmt                 // 视图组件
     ├── pkg-07-route                // 页面即路由
    
  2. 在 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();
    
  3. 在 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()]}> />
    
  4. 在 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
    
  5. 保留了 React 脚手架的使用习惯, 使用 yarn start 和 yarn build 在聚合项目根目录启动或打包

    yarn && yarn start
    yarn && yarn build
    

原理介绍

  1. 正在使用的方式:在编译打包阶段,根据开发约定,扫描和匹配源码关键词,实现控制反转-依赖查找。
  2. 暂未采用的可选方式:合理利用 TypeScript 的 『Decorators』特性,可有效降低控制反转的实现复杂度,并一定程度上提高灵活性,但轻度显式地耦合了装饰器实现。
  3. 部分打包脚本的工作可以做成 webpack 插件从而更优雅地实现,但是要考虑到 IOC 容器的 AST 树。

既有类库

  1. 行为,依据初始化优先级以及动态计算的依赖先后关系排序
行为类 作用 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>
  1. 组件
名称 作用 入参
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
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO.

简介

暂无描述 展开 收起
README
WTFPL
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/jhxlhl1023/mdl-00-codebase-frontend.git
git@gitee.com:jhxlhl1023/mdl-00-codebase-frontend.git
jhxlhl1023
mdl-00-codebase-frontend
mdl-00-codebase-frontend
main

搜索帮助