Serverpod 适合全栈 Dart 开发吗?

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Serverpod 是一款适用于全栈Dart开发的框架,尤其适合熟悉Dart的开发者。它提供了Docker部署、代码自动生成、数据库连接等功能,简化了前后端开发流程。通过Serverpod,可以创建单体服务架构,但处理复杂业务时可能需要借助其他语言的丰富生态。框架包括对postgres和redis的支持,以及可视化工具Insights。开发步骤涉及安装、创建项目、启动服务和配置文件。Serverpod还允许动态生成接口和数据库代码,简化CURD操作。虽然适合简单到中等复杂度的应用,对于更复杂需求,可能需要结合其他语言或服务。

Serverpod 适合全栈 Dart 开发吗?

视频

https://youtu.be/RiicBU8fE-o

https://www.bilibili.com/video/BV1nM4m1k7DE/

前言

原文 https://ducafecat.com/blog/full-stack-development-with-dart-and-serverpod

Serverpod 是一个符合现代化需求的大前端框架,支持 Docker 部署、代码自动生成、数据库连接等功能。对于只会 Dart 语言的开发者来说,Serverpod 是否能胜任全栈开发?本文为您详细评估 Serverpod 的优势和局限性。

Serverpod, Dart 全栈开发, Dart 开发框架, 大前端框架, 全栈开发解决方案

Serverpod

https://serverpod.dev/

主要功能有:

  • Docker 生态部署
  • 代码自动生成 model、dao、controller、client sdk
  • 连接 postgres、redis
  • 可配置 yaml , 开发、生产隔离
  • 可视化日志UI工具 insights
  • 缓存、日志、验证、上传文件、健康检查、调度任务、流消息、RPC

如果你只是用来做以上业务,没有问题,但是再复杂些就要靠生态了,如图片加工、视频压缩、经纬度转换、P2P等等,你估计要用 java、go 这种生态丰富的语言来搭建了,然后用 Serverpod 来访问,当然你也可以用 saas 云服务解决。

如果你正在构建一个精简的单体服务架构,你可以从 Serverpod 的设计中寻找灵感。

参考

https://github.com/serverpod/serverpod

https://docs.serverpod.dev/

https://docs.serverpod.dev/insights

https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod

前提条件

步骤

1 全局安装 serverpod 命令行工具

安装

$ dart pub global activate serverpod_cli

自检

$ serverpod
❯ serverpod 

Manage your serverpod app development

Usage: serverpod <command> [arguments]

Global options:
-h, --help              Print this usage information.
-q, --quiet             Suppress all serverpod cli output. Is overridden by  -v, --verbose.
-v, --verbose           Prints additional information useful for development. Overrides --q, --quiet.
-a, --[no-]analytics    Toggles if analytics data is sent to Serverpod.
                        (defaults to on)

Available commands:
  create                    Creates a new Serverpod project, specify project name (must be lowercase with no special characters).
  create-migration          Creates a migration from the last migration to the current state of the database.
  create-repair-migration   Repairs the database by comparing the target state to what is in the live database instead of comparing to
                            the latest migration.
  generate                  Generate code from yaml files for server and clients.
  language-server           Launches a serverpod language server communicating with JSON-RPC-2 intended to be used with a client
                            integrated in an IDE.
  version                   Prints the active version of the Serverpod CLI.

Run "serverpod help <command>" for more information about a command.

2 创建项目

create 命令

$ serverpod create mypod

mypod 是项目名称

目录

代码 名称
mypod_client 客户端链接库
mypod_flutter flutter 项目
mypod_server serverpod 服务端

3 启动项目

Docker 方式启动 postgres、redis

$ cd mypod/mypod_server
$ docker compose up --build --detach

启动 Serverpod 服务

$ dart bin/main.dart --apply-migrations

启动 Flutter 程序

$ cd mypod/mypod_flutter
$ flutter run -d chrome

4 配置文件

开发、生产、测试 配置

mypod_server/config/development.yaml

mypod_server/config/production.yaml

mypod_server/config/staging.yaml

# This is the configuration file for your local development environment. By
# default, it runs a single server on port 8080. To set up your server, you will
# need to add the name of the database you are connecting to and the user name.
# The password for the database is stored in the config/passwords.yaml.
#
# When running your server locally, the server ports are the same as the public
# facing ports.

# Configuration for the main API server.
apiServer:
  port: 8080
  publicHost: localhost
  publicPort: 8080
  publicScheme: http

# Configuration for the Insights server.
insightsServer:
  port: 8081
  publicHost: localhost
  publicPort: 8081
  publicScheme: http

# Configuration for the web server.
webServer:
  port: 8082
  publicHost: localhost
  publicPort: 8082
  publicScheme: http

# This is the database setup for your server.
database:
  host: localhost
  port: 8090
  name: mypod
  user: postgres

# This is the setup for Redis.
redis:
  enabled: false
  host: localhost
  port: 8091

密码配置

mypod_server/config/passwords.yaml

# Use this file to store passwords to services that your server you use. When
# the server starts, the passwords will be automatically loaded and can be
# accessed from the `session.passwords` field. If you don't have access to a
# session object, passwords can also be accessed from
# `Serverpod.instance.passwords`. You can provide different passwords for
# different run configurations. If you want the same password for any
# configuration used, place it under `shared`.
#
# Note that this file should not be under version control. Store it in a safe
# place.

# Save passwords used across all configurations here.
shared:
  mySharedPassword: 'my password'

# These are passwords used when running the server locally in development mode
development:
  database: 'jBXWslvjYpfszBbFKS661o1MrY1esjVC'
  redis: 'ijH4ON9CCHtK9Cojnqivvym1zxHkwjig'

  # The service secret is used to communicate between servers and to access the
  # service protocol.
  serviceSecret: 'uVoVJ-cqnwc9Bn8gQG-ZLtYfgXGnMUu3'

# Passwords used in your staging environment if you use one. The default setup
# use a password for Redis.
staging:
  database: '3_5RPi7yVOSwSEhr8ecNftp1K4H0_7nL'
  serviceSecret: 'JgM8DPORU5OwOyG23_gdjhYuRLD6mk1J'

# Passwords used in production mode.
production:
  database: 'ReE97mCuS0QaxlXEy4hNMQYtE_Q1lxP4'
  serviceSecret: '0XpMqP4aybryFxm4N8V5ZXHcPFTHUXpP'

生成配置

type: server

client_package_path: ../mypod_client

docker 服务配置

mypod_server/docker-compose.yaml

version: '3.7'

services:
  postgres:
    image: postgres:14.1
    ports:
      - '8090:5432'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: mypod
      POSTGRES_PASSWORD: "jBXWslvjYpfszBbFKS661o1MrY1esjVC"
    volumes:
      - mypod_data:/var/lib/postgresql/data
  redis:
    image: redis:6.2.6
    ports:
      - '8091:6379'
    command: redis-server --requirepass "ijH4ON9CCHtK9Cojnqivvym1zxHkwjig"
    environment:
      - REDIS_REPLICATION_MODE=master
volumes:
  mypod_data:

5 动态生成接口代码

添加 example.hello2 方法

mypod_server/lib/src/endpoints/example_endpoint.dart

class ExampleEndpoint extends Endpoint {
   
   
  // You create methods in your endpoint which are accessible from the client by
  // creating a public method with `Session` as its first parameter.
  // `bool`, `int`, `double`, `String`, `UuidValue`, `Duration`, `DateTime`, `ByteData`,
  // and other serializable classes, exceptions and enums from your from your `protocol` directory.
  // The methods should return a typed future; the same types as for the parameters are
  // supported. The `session` object provides access to the database, logging,
  // passwords, and information about the request being made to the server.
  Future<String> hello(Session session, String name) async {
   
   
    return 'Hello $name';
  }

  Future<String> hello2(Session session, String name) async {
   
   
    return 'Hello $name';
  }
}

执行生成命令

$ cd mypod/mypod_server
$ serverpod generate

查看 generated 目录的文件变化

mypod_server/lib/src/generated

客户端 lib 库

mypod_client/lib/src/protocol/client.dart

class EndpointExample extends _i1.EndpointRef {
   
   
  EndpointExample(_i1.EndpointCaller caller) : super(caller);

  
  String get name => 'example';

  _i2.Future<String> hello(String name) => caller.callServerEndpoint<String>(
        'example',
        'hello',
        {
   
   'name': name},
      );

  _i2.Future<String> hello2(String name) => caller.callServerEndpoint<String>(
        'example',
        'hello2',
        {
   
   'name': name},
      );
}

多了 hello2 的定义

Flutter 项目中调用

mypod_flutter/lib/main.dart

  void _callHello2() async {
   
   
    try {
   
   
      final result = await client.example.hello2(_textEditingController.text);
      setState(() {
   
   
        _errorMessage = null;
        _resultMessage = result;
      });
    } catch (e) {
   
   
      setState(() {
   
   
        _errorMessage = '$e';
      });
    }
  }
...

  Padding(
              padding: const EdgeInsets.only(bottom: 16.0),
              child: ElevatedButton(
                onPressed: _callHello2,
                child: const Text('Send to Server'),
              ),
            ),

6 动态生成数据库代码

编写 model 定义

mypod_server/lib/src/models/note.yaml

class: Note
table: note
fields:
  text: String

生成代码

serverpod generate

编写 CURD 接口定义

mypod_server/lib/src/endpoints/notes_endpoint.dart

import 'package:serverpod/server.dart';

import '../generated/protocol.dart';

class NotesEndpoint extends Endpoint {
   
   
  Future<List<Note>> getAllNotes(Session session) async {
   
   
    // By ordering by the id column, we always get the notes in the same order
    // and not in the order they were updated.
    return await Note.db.find(
      session,
      orderBy: (t) => t.id,
    );
  }

  Future<void> createNote(Session session, Note note) async {
   
   
    await Note.db.insertRow(session, note);
  }

  Future<void> deleteNote(Session session, Note note) async {
   
   
    await Note.db.deleteRow(session, note);
  }
}

生成迁移内容

$ serverpod create-migration

服务器启动应用迁移

$ cd mypod/mypod_server
$ dart bin/main.dart --apply-migrations

重启服务

迁移完成后需要重新启动服务器

dart bin/main.dart --apply-migrations

Flutter 编写代码

mypod_flutter/lib/main.dart

  void _callNoteCreate() async {
   
   
    try {
   
   
      await client.notes.createNote(Note(text: "this is example."));
      setState(() {
   
   
        _errorMessage = null;
        _resultMessage = "create send~";
      });
    } catch (e) {
   
   
      setState(() {
   
   
        _errorMessage = '$e';
      });
    }
  }
Padding(
              padding: const EdgeInsets.only(bottom: 16.0),
              child: ElevatedButton(
                onPressed: _callNoteCreate,
                child: const Text('Note Create Send To Server'),
              ),
            ),

Flutter 项目访问测试

$ cd mypod/mypod_flutter
$ flutter run -d chrome

7 部署项目

Docker 部署

mypod_server/Dockerfile

FROM dart:3.2.5 AS build

WORKDIR /app
COPY . .

RUN dart pub get
RUN dart compile exe bin/main.dart -o bin/server

FROM alpine:latest

ENV runmode=production
ENV serverid=default
ENV logging=normal
ENV role=monolith

COPY --from=build /runtime/ /
COPY --from=build /app/bin/server server
COPY --from=build /app/config/ config/
COPY --from=build /app/web/ web/

EXPOSE 8080
EXPOSE 8081
EXPOSE 8082

ENTRYPOINT ./server --mode=$runmode --server-id=$serverid --logging=$logging --role=$role

构建 docker 包

$ cd mypod/mypod_server
$ docker build -t mypod_server:v1.0 .

原生部署

mypod_server/deploy

  • aws
  • gcp

代码

官方有些不错的例子

https://docs.serverpod.dev/tutorials/code-example

小结

Serverpod 是一个功能强大的 Dart 全栈开发框架,为只掌握 Dart 语言的开发者提供了一个全面的解决方案。它支持 Docker 部署、代码自动生成、数据库连接等关键功能,满足了现代化应用开发的需求。但是对于更加复杂的业务场景,开发者可能还需要使用其他语言的生态工具。总的来说,Serverpod 是一个值得 Dart 开发者认真考虑的全栈开发框架,能够大幅提高开发效率和部署效果。

感谢阅读本文

如果有什么建议,请在评论中让我知道。我很乐意改进。


flutter 学习路径


© 猫哥
ducafecat.com

end

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
7月前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
7月前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
【4月更文挑战第30天】Dart是Google为Flutter框架打造的高效编程语言,具有易学性、接口、混入、抽象类等特性。本文概述了Dart的基础语法,包括静态类型(如int、String)、控制流程(条件、循环)、函数、面向对象(类与对象)和异常处理。此外,还介绍了库导入与模块使用,帮助开发者快速入门Flutter开发。通过学习Dart,开发者能创建高性能的应用。
74 0
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
|
7月前
|
Dart 前端开发 Android开发
【Flutter前端技术开发专栏】Flutter中的平台特定代码实现
【4月更文挑战第30天】Flutter旨在实现跨平台移动应用开发,但有时需针对iOS或Android编写特定代码。平台通道是关键机制,允许Dart代码与原生代码交互。通过`MethodChannel`等实现跨平台通信,然后在iOS和Android上响应调用。条件编译则在编译时决定特定平台代码。本文展示了如何在Flutter中处理平台特定功能,包括示例代码和总结。
159 0
【Flutter前端技术开发专栏】Flutter中的平台特定代码实现
|
7月前
|
开发框架 前端开发 Android开发
【Flutter 前端技术开发专栏】Flutter 与原生模块通信机制
【4月更文挑战第30天】本文探讨了Flutter作为跨平台开发框架与原生Android和iOS交互的必要性,主要通过方法调用和事件传递实现。文中详细介绍了Flutter与Android/iOS的通信方式,数据传输(包括基本和复杂类型),性能优化,错误处理以及实际应用案例。理解并掌握这一通信机制对开发高质量移动应用至关重要,未来有望随着技术发展得到进一步优化。
78 0
【Flutter 前端技术开发专栏】Flutter 与原生模块通信机制
|
7月前
|
传感器 前端开发 Android开发
【Flutter 前端技术开发专栏】Flutter 中的插件开发与集成
【4月更文挑战第30天】本文探讨了Flutter插件开发的关键技术和实践,包括插件作为连接Flutter与原生功能桥梁的角色,开发流程(定义接口、实现原生代码、打包发布),以及集成方法(添加依赖、初始化)。文中提到了多媒体、传感器和文件系统等常见插件类型,并以相机插件为例说明开发步骤。此外,还强调了版本兼容性、性能优化和错误处理的注意事项,推荐了开发工具和资源。随着Flutter的发展,插件开发将更加重要,未来有望形成更丰富的生态系统。
87 0
【Flutter 前端技术开发专栏】Flutter 中的插件开发与集成
|
Dart 前端开发 Java
《深入浅出Dart》Flutter简介
Flutter简介 Flutter是由Google开发和维护的开源框架,自2017年以来,已经迅速获得了开发者社区的广泛认可。其主要目的是开发出高性能、高保真的移动应用程序,用于iOS和Android两个主要平台。 Google创建Flutter的初衷是解决跨平台开发中的一些普遍问题,包括性能瓶颈,不同平台的UI不一致等。Google希望Flutter能够创建美观、流畅且用户体验接近原生应用的应用程序。目前,Flutter已经逐步扩展到其他平台,如Web、桌面应用和嵌入式系统。
107 0
|
7月前
|
Rust 前端开发 JavaScript
Rust在前端与全栈开发中的实践探索
随着Rust语言的日渐成熟,其应用场景已经从后端扩展到前端和全栈开发领域。本文将深入探讨Rust语言在前端与全栈开发中的实际应用案例,分析Rust语言在这些领域的优势和面临的挑战,并展望Rust未来的发展趋势。
|
7月前
|
监控 安全 前端开发
Python全栈安全:构建安全的全栈应用
Python全栈安全:构建安全的全栈应用
92 0
|
Cloud Native 算法 测试技术
你写过的最蠢的代码是?——全栈开发篇
你写过的最蠢的代码是?——全栈开发篇
60 0
Flutter 入门指南之 Dart 语言基础介绍
Dart是一种由Google开发的通用编程语言,用于构建跨平台的移动、Web和桌面应用程序。以下是Flutter入门指南中的Dart语言基础知识:
101 0