2.1 前端技术栈选择
2.1.1 框架对比分析
主流前端框架比较
框架 | 优势 | 劣势 | 适用场景 |
---|---|---|---|
Vue.js | 学习曲线平缓、双向绑定、组件化 | 生态相对较小 | 中小型项目、快速开发 |
React | 生态丰富、性能优秀、社区活跃 | 学习成本高、配置复杂 | 大型项目、高性能要求 |
Angular | 完整框架、TypeScript原生支持 | 体积大、学习成本高 | 企业级应用 |
推荐技术栈:Vue 3 + TypeScript
选择理由: 1. 开发效率高:Vue的模板语法和响应式系统便于快速开发 2. 组件化友好:天然支持组件化开发模式 3. TypeScript支持:提供更好的类型安全和开发体验 4. 生态完善:Vue Router、Pinia、Vite等工具链成熟
2.1.2 核心依赖选择
package.json 配置
{
"name": "lowcode-platform-frontend",
"version": "1.0.0",
"description": "Low-code platform frontend application",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"test": "vitest",
"test:ui": "vitest --ui",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"vue": "^3.3.4",
"vue-router": "^4.2.4",
"pinia": "^2.1.6",
"@vueuse/core": "^10.3.0",
"element-plus": "^2.3.8",
"@element-plus/icons-vue": "^2.1.0",
"axios": "^1.4.0",
"lodash-es": "^4.17.21",
"dayjs": "^1.11.9",
"monaco-editor": "^0.41.0",
"sortablejs": "^1.15.0",
"fabric": "^5.3.0",
"konva": "^9.2.0",
"vue-konva": "^3.0.2"
},
"devDependencies": {
"@types/node": "^20.4.5",
"@types/lodash-es": "^4.17.8",
"@types/sortablejs": "^1.15.1",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.4.1",
"@vue/tsconfig": "^0.4.0",
"eslint": "^8.45.0",
"eslint-plugin-vue": "^9.15.1",
"jsdom": "^22.1.0",
"prettier": "^3.0.0",
"typescript": "~5.1.6",
"vite": "^4.4.6",
"vitest": "^0.33.0",
"vue-tsc": "^1.8.6"
}
}
核心依赖说明
// 依赖说明和使用场景
interface DependencyInfo {
name: string;
purpose: string;
usage: string;
alternatives?: string[];
}
const coreDependencies: DependencyInfo[] = [
{
name: 'vue',
purpose: '核心框架',
usage: '组件开发、响应式数据、模板渲染'
},
{
name: 'vue-router',
purpose: '路由管理',
usage: '页面导航、路由守卫、动态路由'
},
{
name: 'pinia',
purpose: '状态管理',
usage: '全局状态、组件通信、数据持久化',
alternatives: ['vuex']
},
{
name: 'element-plus',
purpose: 'UI组件库',
usage: '基础组件、表单组件、布局组件',
alternatives: ['ant-design-vue', 'naive-ui']
},
{
name: 'monaco-editor',
purpose: '代码编辑器',
usage: '代码编辑、语法高亮、智能提示',
alternatives: ['codemirror']
},
{
name: 'fabric',
purpose: '画布操作',
usage: '拖拽操作、图形绘制、交互处理',
alternatives: ['konva', 'paper.js']
},
{
name: 'sortablejs',
purpose: '拖拽排序',
usage: '组件排序、列表重排、树形拖拽'
}
];
2.1.3 项目结构设计
lowcode-platform-frontend/
├── public/ # 静态资源
│ ├── favicon.ico
│ └── index.html
├── src/
│ ├── assets/ # 资源文件
│ │ ├── images/
│ │ ├── icons/
│ │ └── styles/
│ ├── components/ # 通用组件
│ │ ├── common/ # 基础组件
│ │ ├── designer/ # 设计器组件
│ │ └── runtime/ # 运行时组件
│ ├── views/ # 页面组件
│ │ ├── designer/ # 设计器页面
│ │ ├── preview/ # 预览页面
│ │ └── admin/ # 管理页面
│ ├── stores/ # 状态管理
│ │ ├── designer.ts # 设计器状态
│ │ ├── components.ts # 组件状态
│ │ └── user.ts # 用户状态
│ ├── utils/ # 工具函数
│ │ ├── api.ts # API封装
│ │ ├── canvas.ts # 画布工具
│ │ └── validator.ts # 验证工具
│ ├── types/ # 类型定义
│ │ ├── component.ts # 组件类型
│ │ ├── designer.ts # 设计器类型
│ │ └── api.ts # API类型
│ ├── plugins/ # 插件系统
│ │ ├── component-loader.ts # 组件加载器
│ │ └── theme-manager.ts # 主题管理器
│ ├── router/ # 路由配置
│ │ └── index.ts
│ ├── App.vue # 根组件
│ └── main.ts # 入口文件
├── tests/ # 测试文件
│ ├── unit/ # 单元测试
│ └── e2e/ # 端到端测试
├── docs/ # 文档
├── vite.config.ts # Vite配置
├── tsconfig.json # TypeScript配置
├── eslint.config.js # ESLint配置
└── package.json # 项目配置
2.2 后端架构设计
2.2.1 技术栈选择
Node.js + Express + TypeScript
选择理由: 1. 开发效率:JavaScript全栈开发,减少语言切换成本 2. 生态丰富:npm生态系统提供丰富的第三方库 3. 性能优秀:事件驱动、非阻塞I/O模型 4. 类型安全:TypeScript提供静态类型检查
核心依赖配置
{
"name": "lowcode-platform-backend",
"version": "1.0.0",
"description": "Low-code platform backend service",
"scripts": {
"dev": "nodemon --exec ts-node src/app.ts",
"build": "tsc",
"start": "node dist/app.js",
"test": "jest",
"test:watch": "jest --watch",
"lint": "eslint src/**/*.ts --fix",
"migrate": "typeorm migration:run",
"seed": "ts-node src/database/seeds/index.ts"
},
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5",
"helmet": "^7.0.0",
"compression": "^1.7.4",
"express-rate-limit": "^6.8.1",
"typeorm": "^0.3.17",
"mysql2": "^3.6.0",
"redis": "^4.6.7",
"jsonwebtoken": "^9.0.1",
"bcryptjs": "^2.4.3",
"joi": "^17.9.2",
"multer": "^1.4.5-lts.1",
"sharp": "^0.32.4",
"nodemailer": "^6.9.4",
"winston": "^3.10.0",
"socket.io": "^4.7.2",
"bull": "^4.11.3",
"ioredis": "^5.3.2"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/cors": "^2.8.13",
"@types/compression": "^1.7.2",
"@types/jsonwebtoken": "^9.0.2",
"@types/bcryptjs": "^2.4.2",
"@types/multer": "^1.4.7",
"@types/nodemailer": "^6.4.9",
"@types/node": "^20.4.5",
"@types/jest": "^29.5.3",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint": "^8.45.0",
"jest": "^29.6.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"nodemon": "^3.0.1",
"typescript": "^5.1.6"
}
}
2.2.2 微服务架构设计
// 服务架构定义
interface ServiceArchitecture {
services: ServiceDefinition[];
gateway: GatewayConfig;
database: DatabaseConfig;
cache: CacheConfig;
messageQueue: MessageQueueConfig;
}
interface ServiceDefinition {
name: string;
port: number;
responsibilities: string[];
dependencies: string[];
database?: string;
}
const architecture: ServiceArchitecture = {
services: [
{
name: 'api-gateway',
port: 3000,
responsibilities: [
'请求路由',
'身份认证',
'限流控制',
'API文档'
],
dependencies: ['auth-service', 'designer-service']
},
{
name: 'auth-service',
port: 3001,
responsibilities: [
'用户认证',
'权限管理',
'JWT令牌',
'用户管理'
],
dependencies: [],
database: 'auth_db'
},
{
name: 'designer-service',
port: 3002,
responsibilities: [
'页面设计',
'组件管理',
'模板管理',
'版本控制'
],
dependencies: ['component-service'],
database: 'designer_db'
},
{
name: 'component-service',
port: 3003,
responsibilities: [
'组件注册',
'组件库管理',
'组件版本',
'组件市场'
],
dependencies: [],
database: 'component_db'
},
{
name: 'runtime-service',
port: 3004,
responsibilities: [
'应用运行',
'数据绑定',
'事件处理',
'性能监控'
],
dependencies: ['data-service'],
database: 'runtime_db'
},
{
name: 'data-service',
port: 3005,
responsibilities: [
'数据源管理',
'API代理',
'数据转换',
'缓存管理'
],
dependencies: [],
database: 'data_db'
},
{
name: 'workflow-service',
port: 3006,
responsibilities: [
'工作流引擎',
'流程设计',
'任务调度',
'审批流程'
],
dependencies: ['notification-service'],
database: 'workflow_db'
},
{
name: 'notification-service',
port: 3007,
responsibilities: [
'消息推送',
'邮件发送',
'短信通知',
'系统通知'
],
dependencies: []
}
],
gateway: {
port: 3000,
routes: [
{ path: '/api/auth/*', service: 'auth-service' },
{ path: '/api/designer/*', service: 'designer-service' },
{ path: '/api/components/*', service: 'component-service' },
{ path: '/api/runtime/*', service: 'runtime-service' },
{ path: '/api/data/*', service: 'data-service' },
{ path: '/api/workflow/*', service: 'workflow-service' }
]
},
database: {
type: 'mysql',
host: 'localhost',
port: 3306,
databases: [
'auth_db',
'designer_db',
'component_db',
'runtime_db',
'data_db',
'workflow_db'
]
},
cache: {
type: 'redis',
host: 'localhost',
port: 6379,
clusters: [
{ name: 'session', db: 0 },
{ name: 'cache', db: 1 },
{ name: 'queue', db: 2 }
]
},
messageQueue: {
type: 'redis',
host: 'localhost',
port: 6379,
queues: [
'email-queue',
'notification-queue',
'export-queue',
'import-queue'
]
}
};
2.2.3 项目结构设计
lowcode-platform-backend/
├── services/ # 微服务目录
│ ├── api-gateway/ # API网关
│ │ ├── src/
│ │ │ ├── middleware/ # 中间件
│ │ │ ├── routes/ # 路由配置
│ │ │ ├── utils/ # 工具函数
│ │ │ └── app.ts # 应用入口
│ │ ├── Dockerfile
│ │ └── package.json
│ ├── auth-service/ # 认证服务
│ │ ├── src/
│ │ │ ├── controllers/ # 控制器
│ │ │ ├── services/ # 业务逻辑
│ │ │ ├── models/ # 数据模型
│ │ │ ├── middleware/ # 中间件
│ │ │ ├── routes/ # 路由
│ │ │ └── app.ts
│ │ ├── Dockerfile
│ │ └── package.json
│ ├── designer-service/ # 设计器服务
│ ├── component-service/ # 组件服务
│ ├── runtime-service/ # 运行时服务
│ ├── data-service/ # 数据服务
│ ├── workflow-service/ # 工作流服务
│ └── notification-service/ # 通知服务
├── shared/ # 共享代码
│ ├── types/ # 类型定义
│ ├── utils/ # 工具函数
│ ├── middleware/ # 通用中间件
│ └── database/ # 数据库配置
├── scripts/ # 脚本文件
│ ├── build.sh # 构建脚本
│ ├── deploy.sh # 部署脚本
│ └── migrate.sh # 迁移脚本
├── docker/ # Docker配置
│ ├── docker-compose.yml # 开发环境
│ ├── docker-compose.prod.yml # 生产环境
│ └── nginx.conf # Nginx配置
├── docs/ # 文档
│ ├── api/ # API文档
│ └── deployment/ # 部署文档
└── package.json # 根配置
2.3 数据库选型
2.3.1 关系型数据库:MySQL
数据库设计
-- 用户管理相关表
CREATE DATABASE auth_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE auth_db;
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
avatar_url VARCHAR(500),
status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
role_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_login_at TIMESTAMP NULL,
INDEX idx_username (username),
INDEX idx_email (email),
INDEX idx_status (status)
);
-- 角色表
CREATE TABLE roles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
description TEXT,
permissions JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 设计器相关表
CREATE DATABASE designer_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE designer_db;
-- 项目表
CREATE TABLE projects (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
owner_id BIGINT NOT NULL,
config JSON,
status ENUM('draft', 'published', 'archived') DEFAULT 'draft',
version VARCHAR(20) DEFAULT '1.0.0',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_owner (owner_id),
INDEX idx_status (status),
INDEX idx_name (name)
);
-- 页面表
CREATE TABLE pages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
project_id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
path VARCHAR(200) NOT NULL,
config JSON NOT NULL,
meta JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
UNIQUE KEY uk_project_path (project_id, path),
INDEX idx_project (project_id)
);
-- 组件库相关表
CREATE DATABASE component_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE component_db;
-- 组件表
CREATE TABLE components (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL,
version VARCHAR(20) NOT NULL,
config JSON NOT NULL,
schema JSON NOT NULL,
preview_url VARCHAR(500),
author_id BIGINT,
status ENUM('draft', 'published', 'deprecated') DEFAULT 'draft',
download_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_name_version (name, version),
INDEX idx_category (category),
INDEX idx_status (status),
INDEX idx_author (author_id)
);
-- 组件依赖表
CREATE TABLE component_dependencies (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
component_id BIGINT NOT NULL,
dependency_name VARCHAR(100) NOT NULL,
dependency_version VARCHAR(20) NOT NULL,
type ENUM('runtime', 'build') DEFAULT 'runtime',
FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE,
INDEX idx_component (component_id)
);
TypeORM 实体定义
// src/entities/User.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Role } from './Role';
@Entity('users')
export class User {
@PrimaryGeneratedColumn('increment')
id: number;
@Column({ unique: true, length: 50 })
username: string;
@Column({ unique: true, length: 100 })
email: string;
@Column({ name: 'password_hash', length: 255 })
passwordHash: string;
@Column({ name: 'full_name', length: 100, nullable: true })
fullName?: string;
@Column({ name: 'avatar_url', length: 500, nullable: true })
avatarUrl?: string;
@Column({
type: 'enum',
enum: ['active', 'inactive', 'suspended'],
default: 'active'
})
status: 'active' | 'inactive' | 'suspended';
@Column({ name: 'role_id', nullable: true })
roleId?: number;
@ManyToOne(() => Role)
@JoinColumn({ name: 'role_id' })
role?: Role;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
@Column({ name: 'last_login_at', nullable: true })
lastLoginAt?: Date;
}
// src/entities/Project.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { Page } from './Page';
@Entity('projects')
export class Project {
@PrimaryGeneratedColumn('increment')
id: number;
@Column({ length: 100 })
name: string;
@Column({ type: 'text', nullable: true })
description?: string;
@Column({ name: 'owner_id' })
ownerId: number;
@Column({ type: 'json', nullable: true })
config?: any;
@Column({
type: 'enum',
enum: ['draft', 'published', 'archived'],
default: 'draft'
})
status: 'draft' | 'published' | 'archived';
@Column({ length: 20, default: '1.0.0' })
version: string;
@OneToMany(() => Page, page => page.project)
pages: Page[];
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
// src/entities/Component.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { ComponentDependency } from './ComponentDependency';
@Entity('components')
export class Component {
@PrimaryGeneratedColumn('increment')
id: number;
@Column({ length: 100 })
name: string;
@Column({ length: 50 })
category: string;
@Column({ length: 20 })
version: string;
@Column({ type: 'json' })
config: any;
@Column({ type: 'json' })
schema: any;
@Column({ name: 'preview_url', length: 500, nullable: true })
previewUrl?: string;
@Column({ name: 'author_id', nullable: true })
authorId?: number;
@Column({
type: 'enum',
enum: ['draft', 'published', 'deprecated'],
default: 'draft'
})
status: 'draft' | 'published' | 'deprecated';
@Column({ name: 'download_count', default: 0 })
downloadCount: number;
@OneToMany(() => ComponentDependency, dependency => dependency.component)
dependencies: ComponentDependency[];
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
2.3.2 缓存数据库:Redis
Redis 配置和使用
// src/config/redis.ts
import Redis from 'ioredis';
interface RedisConfig {
host: string;
port: number;
password?: string;
db: number;
keyPrefix?: string;
}
class RedisManager {
private clients: Map<string, Redis> = new Map();
constructor() {
this.initializeClients();
}
private initializeClients() {
const configs: Record<string, RedisConfig> = {
session: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
db: 0,
keyPrefix: 'session:'
},
cache: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
db: 1,
keyPrefix: 'cache:'
},
queue: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
db: 2,
keyPrefix: 'queue:'
}
};
Object.entries(configs).forEach(([name, config]) => {
const client = new Redis(config);
this.clients.set(name, client);
});
}
getClient(name: string): Redis {
const client = this.clients.get(name);
if (!client) {
throw new Error(`Redis client '${name}' not found`);
}
return client;
}
async disconnect() {
await Promise.all(
Array.from(this.clients.values()).map(client => client.disconnect())
);
}
}
export const redisManager = new RedisManager();
// 缓存服务
export class CacheService {
private redis: Redis;
constructor() {
this.redis = redisManager.getClient('cache');
}
async get<T>(key: string): Promise<T | null> {
const value = await this.redis.get(key);
return value ? JSON.parse(value) : null;
}
async set(key: string, value: any, ttl?: number): Promise<void> {
const serialized = JSON.stringify(value);
if (ttl) {
await this.redis.setex(key, ttl, serialized);
} else {
await this.redis.set(key, serialized);
}
}
async del(key: string): Promise<void> {
await this.redis.del(key);
}
async exists(key: string): Promise<boolean> {
const result = await this.redis.exists(key);
return result === 1;
}
async keys(pattern: string): Promise<string[]> {
return await this.redis.keys(pattern);
}
// 组件缓存
async cacheComponent(componentId: string, component: any, ttl = 3600): Promise<void> {
await this.set(`component:${componentId}`, component, ttl);
}
async getCachedComponent(componentId: string): Promise<any> {
return await this.get(`component:${componentId}`);
}
// 页面配置缓存
async cachePageConfig(pageId: string, config: any, ttl = 1800): Promise<void> {
await this.set(`page:${pageId}`, config, ttl);
}
async getCachedPageConfig(pageId: string): Promise<any> {
return await this.get(`page:${pageId}`);
}
// 用户会话缓存
async cacheUserSession(userId: string, session: any, ttl = 7200): Promise<void> {
await this.set(`user:session:${userId}`, session, ttl);
}
async getUserSession(userId: string): Promise<any> {
return await this.get(`user:session:${userId}`);
}
}
2.4 开发环境配置
2.4.1 Docker 开发环境
docker-compose.yml
version: '3.8'
services:
# MySQL 数据库
mysql:
image: mysql:8.0
container_name: lowcode-mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: lowcode_platform
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/init:/docker-entrypoint-initdb.d
command: --default-authentication-plugin=mysql_native_password
networks:
- lowcode-network
# Redis 缓存
redis:
image: redis:7-alpine
container_name: lowcode-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
networks:
- lowcode-network
# Nginx 反向代理
nginx:
image: nginx:alpine
container_name: lowcode-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/conf.d:/etc/nginx/conf.d
- ./docker/ssl:/etc/nginx/ssl
depends_on:
- api-gateway
networks:
- lowcode-network
# API 网关
api-gateway:
build:
context: ./services/api-gateway
dockerfile: Dockerfile.dev
container_name: lowcode-gateway
ports:
- "3000:3000"
environment:
NODE_ENV: development
MYSQL_HOST: mysql
REDIS_HOST: redis
volumes:
- ./services/api-gateway/src:/app/src
- /app/node_modules
depends_on:
- mysql
- redis
networks:
- lowcode-network
# 认证服务
auth-service:
build:
context: ./services/auth-service
dockerfile: Dockerfile.dev
container_name: lowcode-auth
ports:
- "3001:3001"
environment:
NODE_ENV: development
MYSQL_HOST: mysql
REDIS_HOST: redis
volumes:
- ./services/auth-service/src:/app/src
- /app/node_modules
depends_on:
- mysql
- redis
networks:
- lowcode-network
# 设计器服务
designer-service:
build:
context: ./services/designer-service
dockerfile: Dockerfile.dev
container_name: lowcode-designer
ports:
- "3002:3002"
environment:
NODE_ENV: development
MYSQL_HOST: mysql
REDIS_HOST: redis
volumes:
- ./services/designer-service/src:/app/src
- /app/node_modules
depends_on:
- mysql
- redis
networks:
- lowcode-network
# 前端开发服务器
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
container_name: lowcode-frontend
ports:
- "5173:5173"
environment:
NODE_ENV: development
VITE_API_BASE_URL: http://localhost:3000
volumes:
- ./frontend/src:/app/src
- ./frontend/public:/app/public
- /app/node_modules
networks:
- lowcode-network
volumes:
mysql_data:
redis_data:
networks:
lowcode-network:
driver: bridge
Dockerfile.dev 示例
# services/api-gateway/Dockerfile.dev
FROM node:18-alpine
WORKDIR /app
# 安装依赖
COPY package*.json ./
RUN npm ci
# 复制源码
COPY . .
# 暴露端口
EXPOSE 3000
# 开发模式启动
CMD ["npm", "run", "dev"]
2.4.2 环境变量配置
.env.development
# 应用配置
NODE_ENV=development
APP_NAME=LowCode Platform
APP_VERSION=1.0.0
APP_PORT=3000
# 数据库配置
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=root123
DB_DATABASE=lowcode_platform
DB_SYNCHRONIZE=true
DB_LOGGING=true
# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB_SESSION=0
REDIS_DB_CACHE=1
REDIS_DB_QUEUE=2
# JWT 配置
JWT_SECRET=your-super-secret-jwt-key-here
JWT_EXPIRES_IN=7d
JWT_REFRESH_EXPIRES_IN=30d
# 文件上传配置
UPLOAD_MAX_SIZE=10485760
UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/gif,image/webp
UPLOAD_DEST=./uploads
# 邮件配置
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_SECURE=false
MAIL_USER=your-email@gmail.com
MAIL_PASS=your-app-password
MAIL_FROM=noreply@lowcode-platform.com
# 日志配置
LOG_LEVEL=debug
LOG_FILE=./logs/app.log
LOG_MAX_SIZE=20m
LOG_MAX_FILES=14d
# 安全配置
CORS_ORIGIN=http://localhost:5173
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX=100
# 外部服务
AI_SERVICE_URL=http://localhost:8080
AI_SERVICE_API_KEY=your-ai-service-key
# 监控配置
MONITORING_ENABLED=true
METRICS_PORT=9090
HEALTH_CHECK_INTERVAL=30000
环境变量验证
// src/config/env.ts
import Joi from 'joi';
interface EnvConfig {
NODE_ENV: 'development' | 'production' | 'test';
APP_NAME: string;
APP_VERSION: string;
APP_PORT: number;
DB_TYPE: string;
DB_HOST: string;
DB_PORT: number;
DB_USERNAME: string;
DB_PASSWORD: string;
DB_DATABASE: string;
REDIS_HOST: string;
REDIS_PORT: number;
JWT_SECRET: string;
JWT_EXPIRES_IN: string;
UPLOAD_MAX_SIZE: number;
UPLOAD_DEST: string;
}
const envSchema = Joi.object({
NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
APP_NAME: Joi.string().required(),
APP_VERSION: Joi.string().required(),
APP_PORT: Joi.number().port().default(3000),
DB_TYPE: Joi.string().default('mysql'),
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().port().default(3306),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_DATABASE: Joi.string().required(),
REDIS_HOST: Joi.string().required(),
REDIS_PORT: Joi.number().port().default(6379),
JWT_SECRET: Joi.string().min(32).required(),
JWT_EXPIRES_IN: Joi.string().default('7d'),
UPLOAD_MAX_SIZE: Joi.number().default(10485760),
UPLOAD_DEST: Joi.string().default('./uploads')
}).unknown();
export function validateEnv(): EnvConfig {
const { error, value } = envSchema.validate(process.env);
if (error) {
throw new Error(`Environment validation error: ${error.message}`);
}
return value;
}
export const env = validateEnv();
2.4.3 开发工具配置
VS Code 配置
// .vscode/settings.json
{
"typescript.preferences.importModuleSpecifier": "relative",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.workingDirectories": [
"frontend",
"services/api-gateway",
"services/auth-service",
"services/designer-service"
],
"files.associations": {
"*.vue": "vue"
},
"emmet.includeLanguages": {
"vue": "html"
}
}
// .vscode/extensions.json
{
"recommendations": [
"vue.volar",
"vue.vscode-typescript-vue-plugin",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-next",
"bradlc.vscode-tailwindcss",
"ms-vscode-remote.remote-containers"
]
}
启动脚本
#!/bin/bash
# scripts/dev.sh
echo "🚀 启动低代码平台开发环境..."
# 检查 Docker 是否运行
if ! docker info > /dev/null 2>&1; then
echo "❌ Docker 未运行,请先启动 Docker"
exit 1
fi
# 检查端口是否被占用
check_port() {
if lsof -Pi :$1 -sTCP:LISTEN -t >/dev/null ; then
echo "⚠️ 端口 $1 已被占用"
return 1
fi
return 0
}
ports=(3000 3001 3002 3306 6379 5173)
for port in "${ports[@]}"; do
if ! check_port $port; then
echo "请释放端口 $port 后重试"
exit 1
fi
done
# 创建必要的目录
mkdir -p logs uploads
# 启动服务
echo "📦 启动 Docker 容器..."
docker-compose up -d mysql redis
echo "⏳ 等待数据库启动..."
sleep 10
# 运行数据库迁移
echo "🗄️ 运行数据库迁移..."
npm run migrate
# 启动后端服务
echo "🔧 启动后端服务..."
docker-compose up -d api-gateway auth-service designer-service
# 启动前端服务
echo "🎨 启动前端服务..."
cd frontend && npm run dev &
echo "✅ 开发环境启动完成!"
echo "📱 前端地址: http://localhost:5173"
echo "🔌 API地址: http://localhost:3000"
echo "📊 监控面板: http://localhost:3000/health"
# 等待用户输入退出
read -p "按 Enter 键停止所有服务..."
echo "🛑 停止服务..."
docker-compose down
killall node 2>/dev/null || true
echo "👋 开发环境已停止"
2.5 小结
本章详细介绍了低代码平台的技术栈选择和环境搭建,包括:
核心要点
- 前端技术栈:选择 Vue 3 + TypeScript + Vite 构建现代化前端应用
- 后端架构:采用 Node.js + Express + TypeScript 微服务架构
- 数据存储:MySQL 作为主数据库,Redis 作为缓存和会话存储
- 开发环境:使用 Docker 容器化部署,提供一致的开发体验
技术选型原则
- 开发效率:选择学习曲线平缓、开发效率高的技术
- 生态完善:优先选择生态系统成熟、社区活跃的技术
- 性能优秀:考虑技术的性能表现和扩展能力
- 类型安全:使用 TypeScript 提供更好的开发体验
架构设计
- 微服务架构:将功能拆分为独立的服务,便于开发和维护
- 容器化部署:使用 Docker 实现环境一致性和快速部署
- 数据分离:不同服务使用独立的数据库,避免数据耦合
- 缓存策略:合理使用 Redis 缓存提升系统性能
开发体验
- 热重载:前后端都支持热重载,提升开发效率
- 类型检查:TypeScript 提供编译时类型检查
- 代码规范:ESLint + Prettier 保证代码质量
- 调试工具:完善的调试和监控工具链
下一章我们将深入学习平台架构设计,了解如何设计一个可扩展、高性能的低代码平台架构。