Files
DDDMicroFrontend/README.md

259 lines
10 KiB
Markdown
Raw 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.

## DDD领域驱动设计的微服务前端案例
> 持续开发中及时拉取代码文档还不够完善先凑合看目前只是demo代码还会进行大规模封装细化和改造
搭建的一套 **基于DDD领域驱动设计的微服务前端** 项目脚手架,适用于大型企业,开发大型复杂且拓展灵活的前端应用的架构方案。
代码编写建议使用 **OOP面向对象 + TypeScript + JSX** 进行开发,让项目更适合开发和维护,获得更好更极致的编码体验。
本案例中 **[主应用]** 采取的就是OOP风格当然如果你不熟悉上面的写法那么可以在
【其他模块】中使用Vue2Vue3都行但仍然需要遵守DDD的规范进行开发
## 架构图
![架构图](./doc/jgt.png)
## CI/CD 自动化集群部署
![cicd](./doc/newci.png)
## 开发日记
- [x] 基于DDD理念改造
- [x] 拆分领域模块为联邦模块,实现微前端
- [x] 基于 Vue3+OOP+JSX 改造项目代码
- [x] 基于 Nacos 开发 nacos-federation 插件,实现各模块的服务注册&发现,统一管理远程地址
- [x] 修改 nacos-federation 插件实现其成为vite的插件进一步简化代码
- [x] 修改 nacos-federation 插件,实现 接口请求基地址从 配置中心获取,并注入到环境变量中
- [x] 配置 Traefik实现微前端网关限流与熔断重试IP 白名单,压缩
- [x] 封装自动生成 Traefik 代理配置的 nodejs 插件代码
- [x] 修改base增加资源来源地址修复资源错误加载的问题
- [x] 将vite.config.ts中的base 改到插件 nacos-federation中实现简化代码
- [x] 增加控制台日志,方便访问各种服务
- [x] pnpm 统一管理集中项目依赖,运行&构建等
- [x] 领域模块实现 docker 自动化构建部署上线
- [ ] Deno集成GraphQL
- [ ] ....
- [ ] 爬快手api实现一个完整项目测试脚手架不足
## 技术栈:
- [DDD领域驱动设计](https://zh.wikipedia.org/zh-cn/%E9%A0%98%E5%9F%9F%E9%A9%85%E5%8B%95%E8%A8%AD%E8%A8%88)
- [@originjs/vite-plugin-federation](https://www.npmjs.com/package/@originjs/vite-plugin-federation)
- [Deno](https://deno.com/)
- [TypeScript](https://www.typescriptlang.org/)
- [GraphQL](https://graphql.org/)
- [docker](https://www.docker.com/)
- [drone](https://drone.cool/)
- [nacos](https://nacos.io/?spm=5238cd80.47ee59c.0.0.189fcd36fF0ca9)
- [traefik](https://traefik.io/)
- [nginx](https://nginx.org/)
- [Vue3](https://cn.vuejs.org/)
- [Jsx](https://legacy.reactjs.org/docs/introducing-jsx.html)
- [Vite](https://cn.vite.dev/)
- [axios](https://axios-http.com/)
- 等等等....
## 文件夹结构
**根目录:**
```txt
.
├── back-end # 【后端】基于Deno写的后端 测试接口,仅供测试
├── doc # 一些markdown笔记
├── docker # 微服务系统下的一些工具
│ ├── nacos # 动态服务发现配置管理平台
│ └── traefik # 微服务网关
├── front-end # 前端 微服务 项目
│ ├── app-product # 独立的【商品】领域模块
│ ├── app-shared # 独立的 共享资源 模块
│ ├── nacos-federation # 开发的Nacos服务注册与发现的插件简化优雅代码
│ ├── .... # 实际项目还会有更多其他的领域模块
│ └── main-app # 主应用(入口应用)
├── package.json # pnpm的顶级配置文件可以控制模块运行相同命令
├── pnpm-workspace.yaml # 管理多个包的依赖关系
└── README.md # 帮助文档
```
**DDD前端分层目录**
```txt
src/
├── domains/ # 【核心】领域层 - 所有业务领域模块
│ └── product/ # 【app-product模块】订单领域模块
│ ├── domain/ # 领域模型(充血模型)
│ │ ├── entities/ # 实体Product, ProductLineItem
│ │ ├── value-objects/ # 值对象Money, Address
│ │ ├── types/ # 领域内通用类型
│ │ ├── enums/ # 领域枚举
│ │ └── events/ # 领域事件(如果需要)
│ ├── application/ # 应用服务层 - 协调领域对象完成用例
│ │ └── services/ # 应用服务ProductApplicationService
│ ├── infrastructure/ # 基础设施层 - 领域层的具体实现
│ │ └── api/ # 数据获取实现HttpProductRepository
│ ├── ports/ # 端口(接口/抽象类)- 定义契约
│ │ └── repositories/ # 仓储接口ProductRepository
│ └── use-cases/ # (可选)或将用例放在这里
├── app/ # 【交付层】应用组装和配置路由、状态管理、主布局、UI库设置、错误处理、依赖注入容器
│ ├── components/ # 通用UI组件与业务无关如ButtonModal
│ ├── layouts/ # 布局组件
│ ├── di/ # 依赖注入配置
│ ├── router/ # Vue Router 配置
│ ├── stores/ # Pinia Store用于UI状态管理非核心业务状态
│ └── main.ts # 应用入口,依赖注入的组装之地
│ └── App.vue # 根组件
├── features/ # 【交付层】基于领域的功能模块:关注具体的业务功能实现,它是舞台上的“演员”和“节目”。
│ └── product/ # 订单功能模块app-product
│ ├── components/ # 订单领域专用的UI组件
│ ├── views/ # 订单相关的页面级Vue组件
│ ├── router/ # 订单相关的页面级Vue组件
│ ├── composables/ # 订单相关的Vue组合式函数
│ └── index.ts # 订单功能模块的出口
├── shared/ # 【app-shared模块】共享资源
│ ├── infra(infrastructure) # 基础设施层
│ │ ├── http/
│ ├── lib/ # 第三方库的封装/工具函数
│ ├── utils/ # 纯工具函数
│ └── types/ # 全局通用的TypeScript类型定义
│ └── constants/ # 全局常量(如错误码、正则)
│ └── exceptions/ # 通用异常如NotFoundError
└── public/ # 静态资源目录
└── index.html # 主HTML文件
```
## 代码风格
```tsx
// 首页 页面
import { Component, Ref, Setup, Vue } from 'vue-facing-decorator'
import Header from '../components/Header'
import { RouteLocationNormalizedLoaded, Router, useRoute, useRouter } from "vue-router";
interface ListItemType {
id: number
title: string
}
@Component()
export default class Home extends Vue {
counter: number = 1;
@Ref
readonly refH1!: HTMLDivElement
@Setup((props, ctx) => useRouter())
router!: Router
@Setup((props, ctx) => useRoute())
route!: RouteLocationNormalizedLoaded
newList: ListItemType[] = [
{ id: 1, title: '新闻1' },
{ id: 2, title: '新闻2' },
{ id: 3, title: '新闻3' },
]
addCount() {
// console.log("ref dom: ", this.refH1)
// this.router.push({ name: 'about' })
// this.route.query
this.counter++
}
testHtml() {
return <p>测试html jsx 函数</p>
}
render() {
return (
<div class="home">
<h1 ref="refH1">首页</h1>
<p onClick={ this.addCount }>counter 响应式变量(点我):{ this.counter }</p>
<Header
list={ this.newList }
text={ "测试" }>
{ {
default: () => <div class="default">父到子 default 插槽</div>,
haveName: () => <div class="haveName">父到子 具名 插槽</div>,
item: (val: ListItemType) => <li key={ val.id }>{ val.title }</li>
} }
</Header>
{ this.testHtml }
</div>
)
}
}
```
```tsx
// 头部组件
import { Component, Prop, TSX, Vue } from 'vue-facing-decorator'
interface Props {
text?: string
list?: ListItemType[]
}
interface ListItemType {
id: number
title: string
}
@Component()
export default class Header extends TSX<Props>()(Vue) implements Props {
@Prop({ default: '默认数值' })
text!: string;
@Prop()
list!: ListItemType[];
created() {
console.log("created: ", this)
}
render() {
return (
<div class="header">
头部组件
<p>{ this.text }</p>
{ this.$slots.default?.() }
{ this.$slots.haveName?.() }
<ul>
{
this.list.map(
item =>
this.$slots.item?.(item)
)
}
</ul>
</div>
)
}
}
```
## 部署
需要后端或运维参与,请注意咨询阅读文档,大致步骤如下:
**全局准备工作:**
- 1: 准备 >=8台Linux服务器并提前安装配置好Docker确保网络可用建议安装 [1panel](https://1panel.cn/)
- 2: 在1台Linux服务器上部署公司自己的 Docker Registry 镜像存储库
- 3: 准本 N台运行 前端各模块 的Linux服务器并提前组成N个Docker Swarm 集群,以供前端各模块部署使用
- 4: 准本 >=3台运行 Nacos服务中心 的Linux服务器并提前组成Docker Swarm 集群,提前运行好,确保服务可用
- [Nacos 部署文档](./docker/nacos-cluster/README.md)
- 5: 准本 一台 运行 traefik 网关的Linux服务器提前运行好确保服务可用
- [Traefik 部署文档](./docker/traefik/README.md)
**前端工作:**
详细请看 各前端模块 存储库内的 帮助文档!!!
- [商品模块 app-product](https://gitee.com/bmycode/app-product)