Quasar Frameworkでアプリ（SPA/SSR/PWA/デスクトップ/モバイル対応）を作る

[^1]: https://ja.wikipedia.org/wiki/%E3%82%AF%E3%82%A8%E3%83%BC%E3%82%B5%E3%83%BC
[^2]: https://quasar.dev/vue-components/dialog
[^3]: https://forest.watch.impress.co.jp/docs/serial/yajiuma/1129686.html
[^4]: https://www.rdlabo.jp/article/973

## Quasar Frameworkとは？
[Quasar Framework](https://quasar.dev/)（以下、**Quasar**とします）という、フレームワークの存在を[Vuetify](https://vuetifyjs.com/en/)のドキュメントから最近知りました。VuetifyはVue.jsベースのUIフレームワークで比較対象としてQuasarを挙げているので、同じような感じかな？と思っていました。
ただ公式の「[Why Quasar?](https://quasar.dev/introduction-to-quasar)」を確認してみて、各種UIコンポーネントが使える点は同じですが、より様々な特徴も合わせ持ったフレームワークだなと感じました。以下は簡単な抜粋です。

### 読み方
`/ˈkweɪ.zɑɹ/`と発音すると書かれていますがこれだけだとよく分からないので、調べてみると天文学の用語のようで[^1]、だからトップページも宇宙っぽいデザインになっているんだなーと納得しました。カタカナ表記の「**クエーサー**」という感じで読むのがよさそうです。

### 対応プラットフォーム
- SPA
- SSR
- PWA
- デスクトップアプリ（Electron製のアプリ）
- モバイルアプリ（Cordova or Capacitorによるネイティブアプリ）

これらへのデプロイを「**一つのコードベース**」で対応できるようです。
### Quasar CLI
Quasarには「Quasar CLI」という独自のCLIがあり、これを使うとより開発効率を上げることができるようです。

## マルチプラットフォームアプリを作ることにした
今回Quasarの記事を書くにあたってどんなことを書こうか迷ったのですが「マルチプラットフォーム対応をQuasarの一番の売りにしているのかな？」という印象を持ちました。なので「本当にそんなに楽にマルチプラットフォームのアプリ作れるの？」という検証記事にしました。

## 作ったアプリ
今回実際に作ったアプリの動作画面です。上のツールバーや左のメニューはデフォルトのままです。
「MODAL」ボタンを押す → モーダルからテキストを入力 → 入力した内容が「MODAL」の下に表示される、という単純なアプリです。

![Dec-26-2019-03-06-07-compressor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/180a0d58-153f-4e0c-340a-949122e72203.gif)

ソースコードは以下のリポジトリです。
https://github.com/kuromoka/quaser-modal

## Quasarの環境構築
### 導入方法
ここからは実際に上と同じアプリを作っていきます。
まずQuasarの導入方法として「[Getting Started](https://quasar.dev/start/pick-quasar-flavour)」のページに、次の方法をサポートしていること・それぞれ何ができて何ができないかの比較表が記載されています。

- Quasar UMD（CDNのファイルを呼ぶ形式）
- Quasar CLI
- Vue CLI 3 Plugin

今回は新規アプリということもあり、一番Quaserのパワーを発揮できる「**Quasar CLI**」を使っていくことにします。

### CLIのインストール
npmとyarnの両方のインストールをサポートしています。今回はnpmでインストールします。

```bash 
$ npm install -g @quasar/cli
```

### プロジェクトの作成
CLIをインストールすると`quasar create`コマンドが使えるようになるので実行します。いろいろ聞かれるので答えていくと、quasarプロジェクトの初期化処理が始まりプロジェクトが作成されます。

```bash  
$ mkdir quaser-modal
$ cd quaser-modal
$ quasar create .

  ___                             
 / _ \ _   _  __ _ ___  __ _ _ __ 
| | | | | | |/ _` / __|/ _` | '__|
| |_| | |_| | (_| \__ \ (_| | |   
 \__\_\\__,_|\__,_|___/\__,_|_|   
 


? Generate project in current directory? Yes
? Project name (internal usage for dev) quaser-modal
? Project product name (must start with letter if building mobile apps) Quasar App
? Project description A Quasar Framework app
? Author kuromoka <example@gmail.com>
? Pick your favorite CSS preprocessor: (can be changed later) SCSS
? Pick a Quasar components & directives import strategy: (can be changed later) Auto import
? Check the features needed for your project: ESLint
? Pick an ESLint preset: Standard
? Cordova/Capacitor id (disregard if not building mobile apps) org.cordova.quasar.app
? Should we run `npm install` for you after the project has been created? (recommended) NPM

  Quasar CLI · Generated "quaser-modal".
```

### 開発環境の起動
プロジェクト作成後に次のコマンドで起動できるようになります。一度起動しておけばホットリロードが有効になっているので、ファイル編集後のリロードは不要です。

```bash 
$ quasar dev
```
デフォルトだとhttp://localhost:8080/ で起動します。以下のような画面が表示されたらOKです！
<img width="1665" alt="開発環境" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/8d53d683-a6cf-e989-bcc0-1edd1d7540df.png">

## 実装
上のツールバーや左のメニューはそのままにするので、Quasarのロゴだけ置いてある`src/pages/Index.vue`のファイルを編集します。
モーダルの部分はDialogコンポーネント[^2]を使って、最終的には次のような内容になりました。

```src/pages/Index.vue 
<template>
  <q-page class="flex flex-center column">
    <q-btn label="Modal" color="primary" @click="modal = true" />

    <q-dialog v-model="modal">
      <q-card>
        <q-card-section>
          <div class="text-h6">Modal</div>
        </q-card-section>

        <q-card-section>
          <q-input v-model="text" label="Text" />
        </q-card-section>

        <q-card-actions align="right">
          <q-btn flat label="OK" color="primary" v-close-popup />
        </q-card-actions>
      </q-card>
    </q-dialog>
    <p>{{ text }}</p>
  </q-page>
</template>

<script>
export default {
  name: 'PageIndex',
  data () {
    return {
      modal: false,
      text: ''
    }
  }
}
</script>
```

## マルチプラットフォーム対応する
ここからが本題です。最初にも書いた次の環境向けに、作ったアプリをビルドしてみて動くかを検証します。

- SPA
- SSR
- PWA
- デスクトップアプリ（Electron製のアプリ）
- モバイルアプリ（Cordova or Capacitorによるネイティブアプリ）

各種環境（モード）で開発環境を起動したりビルドを行うためのコマンドがQuasar CLIには用意されているので、これを使っていきます。

### SPA
#### 開発環境の起動  
実は先ほどの何もオプションを付けない状態での`quasar dev`が、SPAモードでの起動になっています。

```bash 
$ quasar dev
```
#### ビルド
次のコマンドを実行します。ビルドが成功すれば`dist/spa`フォルダ以下に、結果のファイルが生成されます。

```bash 
$ quasar build
```

#### デプロイ
今回はドキュメントにも紹介されている「[Now](https://zeit.co/home)」というサービスでデプロイしてみます。GitHubアカウントでの登録が可能です。
登録後に次のコマンドでNowのCLIをインストールします。

```bash 
$ npm i -g now
```
NowのCLIを使ってログインします。登録メールアドレスを入力するように言われるので、メールアドレスを入力→送られてきた確認メールの「VERIFY」ボタンを押せばログイン完了です。

```bash 
$ now login
```
あとは`dist/spa`に移動し、`now`コマンドを実行すればデプロイできます！

```bash 
$ cd dist/spa/
$ now
```
https://spa-5qqyatcug.now.sh/ にSPAでデプロイしたアプリを置いています。

### SSR
#### 開発環境の起動  
次のコマンドを実行するとプロジェクトルートに`src-ssr`フォルダが生成されて、SSRモードで起動します。

```bash 
$ quasar dev -m ssr
```
#### ビルド
次のコマンドを実行します。ビルドが成功すれば`dist/ssr`フォルダ以下に、結果のファイルが生成されます。

```bash 
$ quasar build -m ssr
```

#### デプロイ
SPAと同じく「[Now](https://zeit.co/home)」にデプロイします。登録やCLIでのログインは済の状態とします。

同じように`dist/ssr`に移動して、`now`コマンドを実行します。

```bash 
$ cd dist/ssr/
$ now
```
が、以下のようなエラーが出てデプロイできませんでした。

```
> Error! Your `package.json` file is missing a `build` property inside the `scripts` property.
More details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script
```

どうもNowのサービスバージョンがv2になった影響で、デプロイできないっぽい感じのようです・・・
「[Deploying SSR](https://quasar.dev/quasar-cli/developing-ssr/deploying)」には、`dist/ssr/now.json`を作成したり`now -V 1`コマンドにしたりして、v1の方法でデプロイする方法が書かれていますが、これを実行するとv2を使ってくれと言われてしまいデプロイができません。

```
> Error! You tried to create a Now 1.0 deployment. Please use Now 2.0 instead: https://zeit.co/upgrade
```

[フォーラム](https://forum.quasar-framework.org/topic/3121/ssr-deployment-with-now/7)にも同じような問題が挙がっていて、私のように新たに登録したユーザにはv1は開放してないようです。
SSRでv2にもデプロイできるように今後のQuasarのアップデートに期待したいですが、もし解決方法知っている方いたら教えてください🙏

仕方ないので「[Heroku](https://jp.heroku.com/)」にデプロイすることにしました。`dist/ssr/`以下のファイルを一度プロジェクト外の別フォルダにコピーして、Gitリポジトリを作ってherokuにpushする方法でデプロイしました。

```bash 
$ git init .
$ git add .
$ git commit -m 'heroku'
$ heroku create
$ git push heroku master
```
https://arcane-oasis-66859.herokuapp.com/ にSSRでデプロイしたアプリを置いています。

### PWA
#### 開発環境の起動  
次のコマンドを実行するとプロジェクトルートに`src-pwa`フォルダが生成されて、PWAモードで起動します。

```bash 
$ quasar dev -m pwa
```
#### ビルド
次のコマンドを実行します。ビルドが成功すれば`dist/pwa`フォルダ以下に、結果のファイルが生成されます。

```bash 
$ quasar build -m pwa
```

#### デプロイ
今回こそ「[Now](https://zeit.co/home)」でデプロイできるか試してみます。登録やCLIでのログインは済の状態とします。

`dist/pwa`に移動して、`now`コマンドを実行します。今度は成功しました！

```bash 
$ cd dist/pwa/
$ now
```
https://pwa-liysjm31d.now.sh/ にPWAでデプロイしたアプリを置いています。
PCのChromeもPWAに対応[^3]したのでChromeでアクセスしてみます。するとアドレスバーの横にPWA対応していることを表す「+」のアイコンが表示されるので、インストールします。
<img width="323" alt="スクリーンショット 2019-12-25 23.24.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/1f88c2af-01b0-4d93-6afc-ce70f56710b9.png">

デスクトップに追加されたアイコンや`chrome://apps/`からインストールされたアプリを開くことができます。起動した画面は以下の画像です。アドレスバーがなくネイティブアプリっぽく動いてることが確認できます！
![スクリーンショット 2019-12-25 23.27.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/f410eaa8-29a1-83d2-79ff-099e25d289e1.png)

### デスクトップアプリ
#### 開発環境の起動  
次のコマンドを実行するとプロジェクトルートに`src-electron`フォルダが生成されて、electronのアプリが起動します。

```bash 
$ quasar dev -m electron
```
#### ビルド
次のコマンドで、ビルドとアプリとして動かせるようにするためのパッケージングまで自動でやってくれます。

```bash 
$ quasar build -m electron
```

ただし私の環境の場合、[このissue](https://github.com/quasarframework/quasar/issues/5259)と同じエラーが出てビルドに失敗したので、一度`node_modules`フォルダを削除し`npm install`をやり直してから再度実行したら成功しました。

#### アプリの起動
生成したアプリは`dist/electron`フォルダ以下に生成されます。特に何も設定を変えずMacでビルドをしたので、`dist/electron/Quasar App-darwin-x64`というフォルダができていて、中にアプリ本体の`Quasar App`がありました。起動した画面は以下の画像です。
![スクリーンショット 2019-12-26 1.31.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/7cdbb4fe-c4fb-a335-101e-50e04a98455b.png)

### モバイルアプリ
#### CordovaとCapacitor
モバイルアプリをQuasarで作る方法として、「Cordova」と「Capacitor」での方法があるようです。私自身はモバイルアプリの知識がまったくなくどっちがどうとかはまったく分からないのですがどうやら「Capacitor」のほうが後継らしいので[^4]、今回はこちらの方法で進めてみようと思います。

#### 環境構築
Android StudioやXcodeのインストールが必要です。こちらはドキュメントの「[Capacitor App Preparation](https://quasar.dev/quasar-cli/developing-capacitor-apps/preparation)」に詳しい方法が書かれているので、そちらをご参照ください。

#### QuasarにCapacitorを追加
次のコマンドを実行するとプロジェクトルートに`src-capacitor`フォルダが生成されます。

```bash 
$ quasar mode add capacitor
```

#### アプリの起動（Android）
次のコマンドで、自動でAndroid Studioが開きます。

```bash 
$ quasar dev -m capacitor -T android
```

CapacitorによってコンパイルされたファイルがAndroid Studioに同期されます（表現が合っているか微妙）。その後Android Studioの「▶」からアプリの実行ができます。エミュレーターの生成に少し手間取りましたが、何とかAndroidで起動することができました！

![スクリーンショット 2019-12-26 2.02.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/592a27b6-88a2-af8e-c247-61649a11ccb5.png)

#### ビルド（iOS）
iOSの場合はまず「CocoaPods」というツールのインストールが必要なようです。次のコマンドでインストールします。

```bash 
$ sudo gem install cocoapods
```
インストールをしないで後述のビルドのコマンドを実行すると、次のようなエラーが出ます。

```
[error] cocoapods is not installed. For information: https://guides.cocoapods.org/using/getting-started.html#installation
```

あとはAndroidと同じです。次のコマンドで、自動でXcodeが開きます。

```
$ quasar dev -m capacitor -T ios
```

XCodeも「▶」からアプリの実行ができます。iOSでも起動を確認しました！
![スクリーンショット 2019-12-26 2.21.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232357/2b8182f3-357c-3d2d-b496-6770d779d2d1.png)

## まとめ
今回Quasarで、「SPA/SSR/PWA/デスクトップアプリ/モバイルアプリ」のマルチプラットフォームアプリを一通り作ってみて、「**一つのコードベース**」で各種にデプロイできるというのは結構本当だなと思いました！
もちろん今回はアプリも非常に単純なもので、細かい設定はなにもいじっていないというのもあると思います。ただメインのロジックコードで自分で手で修正したのは[実装](#実装)の部分だけで、あとは各種コマンドが自動的に必要なファイルを作ってくれたファイルです。非常に楽でした！
Quasarはまだ日本では情報が少なくあまり知られてない印象があるのですが、今回の検証で個人的には最新の情報を追っていきたいと思うフレームワークの一つになりました！また今後Vue.jsでマルチプラットアプリを作るときの選択肢として普及していくように、啓蒙活動もできたら頑張っていきたいと思います！