0
0

More than 1 year has passed since last update.

DartでExpressを使う(型定義なし)

Last updated at Posted at 2022-10-24

概要

DartでNode.js用のJavaScriptトランスパイルができたので、Expressを使ったサーバーをあえて型定義なしで作成してみる。

なぜならDart用の型定義なんて全く用意されていないし、わざわざ作るのは面倒なので、型定義しないで作ってみてどうしても複雑で必要になってから型定義を作るか考える方針でやるのがいいんじゃないかと。

コード

とりあえず型定義なしで最低限サーバーとして動くレベルは作れた。

main.dart
import 'dart:js';
import 'package:js/js.dart';
import 'package:js/js_util.dart';
import 'package:node_interop/node.dart';

void main() {
  var express = require('express');
  var app = express();
  const port = 8080;

  callMethod(app, 'listen', [
    port,
    allowInterop(() {
      print("サーバーが起動しました。(ポート番号:${port})");
    })
  ]);

  callMethod(app, 'get', [
    '/',
    allowInterop((req, res, next) {
      res.send('Hello World!');
      print("リクエストがありました。");
    })
  ]);
}

詰まったところ

app.getのような関数呼び出しはうまくいかない

規則性がよくわからないのですが、上記のコードの関数をapp.getのような形で呼び出そうと下記のようにすると、

app.listen(...);
app.get(...);

トランスパイルされる関数の呼び出しコードがlistenとgetで異なり、getの呼び出しに失敗します。

J.listen$2$x(app, 8080, A.allowInterop(new A.main_closure()));
app.$get$2("/", A.allowInterop(new A.main_closure0()));

なんでこうなるのか、どういう基準で違いが出ているのかさっぱりわかりません・・・。

package:js/js_utilのcallMethodを使うとうまくいくようです。

callMethod(app, 'listen', [port, allowInterop(...)]);
callMethod(app, 'get', ['/', allowInterop(...)]);
app.listen(8080, A.allowInterop(new A.main_closure()));
app.get("/", A.allowInterop(new A.main_closure0()));

引数として渡す(コールバック)関数の引数の数が異なるとエラーになる

get関数のコールバックとして渡す関数やラムダ式(ミドルウェア関数って言うらしい)の引数が(req, res)や(request, response)となっているサンプルをよく見かけますが、
JavaScriptの場合はこれでも大丈夫なんですが、Dartの場合はこれではうまくいきません。

どうやらdart2jsが出力するコードの中に引数の数が一致しているかどうかを確認するコードが含まれていて、異なっているとエラーにするようです。

if (t1) {
  if (namedArguments != null && namedArguments.__js_helper$_length !== 0)
    return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
  if (argumentCount === requiredParameterCount)
    return jsFunction.apply($function, $arguments);
  return A.Primitives_functionNoSuchMethod($function, $arguments, namedArguments);
}

コールバックとして渡す関数の引数は実際のところは(req, res, next)なので、Dartの場合はそれに合わせる必要があります。

コールバック関数を引数に渡すにはallowInteropで囲む必要がある

なんでこんな仕様になっているんでしょうかね?

参考

今後の予定

テンプレートエンジンを呼び出すことができればそれなりのwebサーバーは作れそうな気がする。ロジックレスじゃないと意味がない(Dartで書けない)のでロジックレスでそれなりに機能があるHandlebars辺りがいいのかな?と考え中。

流石に都度callMethodを呼ぶのは面倒なので.d.tsを変換するような本格的なものではなく簡易な型定義ファイルを生成する方法を模索中。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0