---
title: "使用Dart开发你的serverless 后端"
description: "serverless时代，用什么开发你的后端？Go? NodeJs ? 其实随着Flutter的流行，我们还有个选项 -- Dart。有什么优势让我们选用这个相对小众的语言？还是它的核心优势，JIT + AOT"
url: "https://hicc.pro/p/blog/dart-serverless-server"
author: "tyler wang"
published: "2021-06-20T17:06:20.000Z"
updated: "2021-07-17T16:20:28.000Z"
category: "blog"
lang: "zh-CN"
site: "Hipo日志"
---

# 使用Dart开发你的serverless 后端

## Why ? 10M的Dart server镜像🤓

这是篇快文。😄

serverless时代，用什么开发你的后端？Go? NodeJs ? 其实随着Flutter的流行，我们还有个选项 -- Dart。

有什么优势让我们选用这个相对小众的语言？

还是它的**核心优势，JIT + AOT**

![10M的镜像尺寸](https://image.hicc.pro/pro/20210621011729FhaT4W8hkv5q66xVSGcDeaOdI1mduNoZuAgO6t8S_0nmQ5qw6.png)

- JIT: 极佳的开发体验，特别是前端工程师，像Nodejs一样，甚至有类似express的server框架，而且Dart是强类型语言，最近也做到了[null safe](https://dart.dev/null-safety) 更写起来跟省心，潜在bug少。
- AOT：极小的构建镜像，**10M**的尺寸加上执行更快的编译后机器码，保证最高效率的使用云资源。（最小的node镜像也有50M了）

### 快速开始

#### 创建项目

```bash
dart create -t server-simple hipo
```

#### 入口代码
```dart
import 'dart:io';

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_static/shelf_static.dart' as shelf_static;
import 'package:dotenv/dotenv.dart' show load, clean, isEveryDefined, env;

import 'src/common/db.dart';
import 'src/routers/user.router.dart';

Future main() async {
  load();

  final port = int.parse(Platform.environment['PORT'] ?? '8080');
  final isDev = env['DART_ENV'] == 'production';
  final conf = {
    'isDev': isDev,
    'database': {
      'host': env['DB_HOST'] ?? '127.0.0.1',
    }
  };

  final cascade = Cascade().add(_staticHandler).add(userRouter);

  // init db
  final db = getDb(conf);

  final pipeline = Pipeline()
      .addMiddleware(logRequests())
      .addMiddleware((innerHandler) => (req) async {
            final _req = req.change(context: {'db': db});
            return innerHandler(_req);
          })
      .addHandler(cascade.handler);

  final server = await shelf_io.serve(
      pipeline,
      InternetAddress.anyIPv4, // Allows external connections
      port);

  print('Serving at http://${server.address.host}:${server.port}');
}

final _staticHandler =
    shelf_static.createStaticHandler('public', defaultDocument: 'index.html');
```

shelf 系列是Google 提供类似前端express中间件形式的开发库，用起来很好上手

#### 路由代码

```dart
import 'package:hipo/mysql_utils.dart';
import 'package:shelf_router/shelf_router.dart' as shelf_router;
import 'package:shelf/shelf.dart';
import 'dart:async';

final userRouter = shelf_router.Router()
  ..get('/api/helloworld', _helloWorldHandler);

Future<Response> _helloWorldHandler(Request request) async {
  var data = await (request.context['db'] as MysqlUtils).getAll(table: 'user');
  print('$data');
  return Response.ok({'len': data.length}.toString());
}

```

#### mysql 数据库

可以使用[mysql1](https://pub.dev/packages/mysql1)，[mysql_utils](https://pub.dev/packages/mysql_utils) 这两个库。

```dart
import 'package:hipo/mysql_utils.dart';
import 'package:mysql1/mysql1.dart';

final getDb = (Map<String, dynamic> conf) => MysqlUtils(
    settings: ConnectionSettings(
      host: conf['database']['host'],
      port: conf['database']['port'],
      user: conf['database']['user'],
      password: conf['database']['password'],
      db: conf['database']['db'],
      useCompression: false,
      useSSL: false,
      // maxPacketSize: 1024 * 1024,
      // characterSet: CharacterSet.UTF8,
      // timeout: const Duration(seconds: 10),
    ),
    // prefix: 'prefix_',
    pool: false,
    errorLog: (error) {
      print('db error |$error\n├───────────────────────────');
    },
    sqlLog: (sql) {
      print('db sql |$sql\n├───────────────────────────');
    },
    connectInit: (db1) async {
      print('whenComplete');
    });

```

注意：

- 貌似不支持mysql 8.0+的版本
- mysql_utils需要变通下使用，作者写明了依赖flutter，实际上server也能用。

#### Dockerfile

```dockerfile
# Official Dart image: https://hub.docker.com/_/dart
# Specify the Dart SDK base image version using dart:<version> (ex: dart:2.12)
FROM dart:stable AS build

# Resolve app dependencies.
WORKDIR /app
COPY pubspec.* ./
RUN dart pub get

# Copy app source code and AOT compile it.
COPY . .
# Ensure packages are still up-to-date if anything has changed
RUN dart pub get --offline
RUN dart compile exe bin/hipo.dart -o bin/hipo

# Build minimal serving image from AOT-compiled `/hipo` and required system
# libraries and configuration files stored in `/runtime/` from the build stage.
FROM scratch

ARG DART_ENV=production
ENV DART_ENV=${DART_ENV}

COPY --from=build /runtime/ /
COPY --from=build /app/bin/hipo /app/bin/

# Include files in the /public directory to enable static asset handling
COPY --from=build /app/public/ /public

# Start server.
EXPOSE 8080
CMD ["/app/bin/hipo"]
```

哇啦～～

![](https://image.hicc.pro/pro/20210621011100FogTEZ-rHY_vjy8BV-yGeEPPrBe3NWXhU6m2v1W4087jDXEnl.jpg)

---

原文 / Source: <https://hicc.pro/p/blog/dart-serverless-server>
