Help us understand the problem. What is going on with this article?

SwiftWebUIでWebアプリをつくろう!

はじめに

WWDC2019で発表され、大いに注目を集めるSwiftUIですが、そのSwiftUIでWebアプリを作れることをご存知でしょうか?

SwiftWebUIを使えばできます!
SwiftWebUIは、そのままですが、SwiftUIをWebでも使えるようにしようというプロジェクトです。

Screen Shot 2019-12-09 at 6.45.00.png

今回は簡単にTODOアプリを作っていきます。

Task App Demo.gif

参考リンク

Hello World

Xcodeを開き、New Project, macOS, Command Line Toolを選択します。
Screen Shot 2019-12-09 at 5.46.11.png

適当に名前を入力し、作成できたらSwift Package ManagerでSwiftWebUIを入れていきます。

[iOSアプリ開発にSwift Package Managerを使おう - Qiita]のリンクがわかりやすいです。

きちんと導入できれば、main.swift で下記をコピペしてBuild&Runして、http://localhost:1337にアクセスすれば、テキストの内容(Hello World)が表示されているでしょう

main.swift
import SwiftWebUI

SwiftWebUI.serve(Text("Hello World"))

続いて簡単なTODOアプリを作っていきましょう

TODOアプリ

モデルを定義します。

Task.swift
struct Task: Identifiable {
  var text: String
  var createdAt: Date
  var isFinished: Bool

  var id: String { text }
  var createdAtString: String {
    let f = DateFormatter()
    f.timeStyle = .short
    f.dateStyle = .short
    f.locale = Locale(identifier: "ja_JP")
    return f.string(from: createdAt)
  }
}

タスク一つ一つのUIを作成します。
Viewが一つのtaskを持っていて、Doneボタンを押せばisFinishedtrueになってタスクが完了し、文字色やViewのEnabledが制御されています。

TaskRow.swift
struct TaskRow: View {

  @State var task: Task

  var body: some View {
    HStack {
      Button("Done") {
        self.task.isFinished = true
      }

      VStack(alignment: .leading) {
        Text(task.name)
          .font(.headline)
          .color(task.isFinished ? .secondary : .primary)
        Text(task.createdAtString)
          .color(.secondary)
          .font(.subheadline)
      }
    }
    .padding()
    .disabled(task.isFinished)
  }
}

上記のUIは↓のようになります。

Screen Shot 2019-12-09 at 6.10.03.png

モデルとUIができればモックが作れるので、main.swiftを書き換えていきましょう。

import Foundation
import SwiftWebUI

struct MainView: View {

  @State private var tasks: [Task] = [
    Task(name: "Sample Task", createdAt: Date(), isFinished: false),
    Task(name: "Sample Task", createdAt: Date(), isFinished: false),
    Task(name: "Sample Task", createdAt: Date(), isFinished: false)
  ]

  var body: some View {
    Form {
      Section(header: Text("Task App").font(.title)) {
        List(tasks.identified(by: \.id)) { TaskRow(task: $0) }
      }
    }
  }
}

SwiftWebUI.serve(MainView())

この状態でBuild&Runすればタスクが画面の真ん中に表示されているかと思います。

Screen Shot 2019-12-09 at 6.13.09.png

あとはタスクを追加できるようにすれば完了です。

TaskInputViewを作成し、textをTextFieldで変更していき、追加ボタンを押したらactionを呼ぶようにします。

TaskInputView.swift
import SwiftWebUI

struct TaskInputView: View {

  @State private var text: String = ""

  let action: (String) -> Void

  var body: some View {
    HStack {
      TextField($text)
      Spacer()
      Button("追加", action: {
        self.action(self.text)
        self.text = ""
      })
        .disabled(text.isEmpty)
    }
  }
}

一方で、main.swiftではTaskInputViewのactionでString型受け取るので、tasksの配列に追加していくようにしておきます。

main.swift
  var body: some View {
    Form {
      Section(header: Text("Task App").font(.title)) {
        TaskInputView(action: { text in
          let task = Task(text: text, createdAt: Date(), isFinished: false)
          self.tasks.append(task)
        })
        Spacer(minLength: 12)
        Text("Task List")
          .font(.title)
          .bold()
        List(tasks.identified(by: \.id)) { TaskRow(task: $0) }
      }
    }
  }

下記のようなアプリが出来上がります。

Task App Demo.gif

既知のバグとして

  • TextField内のtextの変更を受け取れていない
  • Task Listを空配列で定義するとタスクを追加できない

が残っておりいろいろ雑ですが、現状のSwiftWebUIの仕様など、詳しくみれていないので時間があれば調査したいと思います。

完成形のプロジェクトをGitHubに上げておきます。
GitHub - mtfum/SwiftWebUISample

懸念点

  • NavigationViewが利用できない
  • Buttonの色が変更されない
  • タスクの空配列に追加してもListに反映されない
    • TypeError: Cannot read property 'parentNode' of Nullのエラーが表示される

など、実際に触ってみるとバグも多く、利用していくにはまだまだ先になりそうです。
また、ブラウザ上でSwiftを動かすためにはSwift Wasmの対応も待たなければなりません。

最後に

SwiftWebUIはプロダクション用ではなくSwiftUIを学ぶのに適していると注意書きされています。

Disclaimer: This is a toy project! Do not use for production. Use it to learn more about SwiftUI and its inner workings.

しかし、SwiftでWebアプリがつくれる日が近づいている証でもあり、まだまだ先は長そうですが今からとても楽しみです。

SwiftUIを触ってみるには良い環境かもしれないので、興味のある人は触ってみてください。
ということでSwiftWebUIの紹介を示させてもらえればと思います。
最後までお読みいただきありがとうございました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした