2025-09-20 02:26:42 +08:00
2025-09-17 01:52:10 +08:00
2025-09-17 21:59:50 +08:00
2025-09-20 02:26:42 +08:00
2025-09-19 02:22:04 +08:00
2025-09-20 02:26:42 +08:00

DDD领域驱动设计的微服务前端案例

持续开发中及时拉取代码文档还不够完善先凑合看目前只是demo代码还会进行大规模封装细化和改造

搭建的一套 基于DDD领域驱动设计的微服务前端 项目脚手架,适用于大型企业,开发大型复杂且拓展灵活的前端应用的架构方案。

代码编写建议使用 OOP面向对象 + TypeScript + JSX 进行开发,让项目更适合开发和维护,获得更好更极致的编码体验。

本案例中 [主应用] 采取的就是OOP风格当然如果你不熟悉上面的写法那么可以在 【其他模块】中使用Vue2Vue3都行但仍然需要遵守DDD的规范进行开发

技术栈:

文件夹结构

根目录:

.
├── back-end          # 【后端】基于Deno写的后端 测试接口,仅供测试
├── doc               # 一些markdown笔记
├── front-end         # 前端 微服务 项目
│   ├── app-product   # 独立的【商品】领域模块
│   ├── app-shared    # 独立的 共享资源 模块
│   ├── ....          # 实际项目还会有更多其他的领域模块
│   └── main-app      # 主应用(入口应用)
└── README.md         # 帮助文档

main-app 目录:

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/                 # 共享资源
│   ├── infra(infrastructure) # 基础设施层
│   │   ├── http/  
│   ├── lib/                # 第三方库的封装/工具函数
│   ├── utils/              # 纯工具函数
│   └── types/              # 全局通用的TypeScript类型定义
│   └── constants/          # 全局常量(如错误码、正则)
│   └── exceptions/         # 通用异常如NotFoundError
└── public/                 # 静态资源目录
└── index.html              # 主HTML文件

代码风格

// 首页 页面
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>
        )
    }
}
// 头部组件
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>
        )
    }
}

开发任务

  • 基于DDD理念改造
  • 基于 vite-plugin-federation 拆分领域模块为联邦模块,实现微前端
  • 基于Vue3+OOP+JSX改造项目代码
  • 基于Nacos开发Nodejs模块实现各模块的服务注册&发现,统一管理远程地址
  • pnpm 统一管理集中项目依赖,运行&构建等...
  • 领域模块实现 docker 自动化构建部署上线
  • Deno集成GraphQL
  • ....
  • 爬快手api实现一个完整项目测试脚手架不足

运行 & 打包

# 1 下载代码
git clone https://gitee.com/bmycode/dddmicro-frontend.git

# 2 运行后端
cd back-end  # 进入 后端 文件夹
deno install # 安装依赖
deno run dev # 运行后端

# 3 运行前端
cd front-end  # 进入 前端 文件夹
pnpm install  # 会同时为 所有模块 安装依赖
pnpm add -g concurrently  # 全局安装 并发命令执行 插件,局部安装也行,随你。
pnpm run all  # 构建 app-product 和 app-shared 并启动预览,并开发阶段启动 main-app 模块
# 注意:命令跑完后 ctrl + c 停止,重跑一次!!因为子模块内命令并发执行预览跑在构建之前,解决办法很简单,后面再搞。
pnpm run all 
# 打开 main-app 主模块访问地址即可:[http://localhost:1300/](http://localhost:1300/)

# 4 部署上线
pnpm run build:main # 构建并预览主应用预览打包后的主应用没问题ctrl + c 停止。
# 子模块在 第三步 已经打包好了,不需要重新打包了。

# 上传部署 各模块内的 dist/ 文件夹到服务器上,注意修改 vite.config.ts 内 plugins.federation.remotes.xxx 的地址!
# 后期会实现集中管理 地址配置,并根据环境变量动态加载!!

问 & 答

问: 为什么vue项目要抛弃SFC写法而尝试jsx/tsx方式来编码

答:https://juejin.cn/post/6911175470255964174

问:不会 vue3 jsx 语法,怎么办?

答:https://juejin.cn/post/7141674726434439176

Description
基于DDD领域驱动设计的微服务前端架构
Readme 4.1 MiB
Languages
TypeScript 75.7%
JavaScript 16.9%
CSS 6.4%
HTML 0.8%
Less 0.2%