[初心者向け] Vue3にTypeScriptとQuasarを導入してみた。

先日、知人とモブプログラミングをしました。
テーマは「Vue3にTypeScriptとQuasarを導入する」でした。

通常のプロジェクトにおいて、リーダー以外のメンバーはリーダーが作ったソースの流れに乗っかると思うので、初期構築はそんなにやる機会はないと思います。
なので、初期構築作業を共有しながらやるのは学びが多そうということで始めたことです。

というわけで、Vue3のプロジェクトを新規作成し、TypeScriptとQuasarを導入してみました。
本記事は当日の記録を踏まえて整理した手順になります。

Vue.jsはViteを使う方がより良いということはわかってはいたのですが、
便利なものを最初から使うと理解が深まらないかなと思い今回はあえて使用していません。

# 環境

Aamzon Linux 2
これをRemoteSSHで操作して開発しています。

# 作業記録兼手順

## Node・npm・Yarnのインストール

```bash
  sudo yum clean all
  sudo rm -rf /var/cache/yum
  sudo yum update

  # Node.jsとnpmのインストール
  curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash -
  sudo yum install -y nodejs

  # Yarnのインストール
  curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
  sudo yum install -y yarn
```

## Vue CLIをインストール

```bash
sudo yarn global add @vue/cli
```

ちなみに、`sudo`なしで`yarn add`すると`vue`コマンドがnot foundになりました。
以下、コマンド実行後に始めるウィザードの質問の説明です。

### プロジェクトの作成

```bash
vue create sample-vue-project
Vue CLI v5.0.8
? Please pick a preset: 
  Default ([Vue 3] babel, eslint) 
  Default ([Vue 2] babel, eslint) 
❯ Manually select features 
```

`Default ([Vue 3] babel, eslint) `、`Default ([Vue 2] babel, eslint) `
だと、TypesScriptがONにならないのを確認したので`Manualy`の方を選びました。

### インストール要素の選択

```bash
 Vue CLI v5.0.8
 ? Please pick a preset: Manually select features
 ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
 ❯◉ Babel
  ◉ TypeScript
  ◯ Progressive Web App (PWA) Support
  ◉ Router
  ◯ Vuex
  ◯ CSS Pre-processors
  ◉ Linter / Formatter
  ◯ Unit Testing
  ◯ E2E Testing
```

最低限の要素を選択します。
PWAは、後で入れるQuasarと競合しそうなので除外しました。

各要素の概要はこちら。

- Babel
JavaScriptのコンパイラで、最新のECMAScript(ES6、ES7など)のコードをブラウザが解釈できるように変換します。
これにより、古いブラウザでも最新のJavaScript機能を安全に使用することが可能となります。
- TypeScript: 
静的型付けとクラスベースのオブジェクト指向を提供するJavaScriptのスーパーセットです。
- Progressive Web App (PWA) Support: 
ウェブサイトをネイティブアプリのように動作させる技術です。
- Router: 
URLの経路を管理し、SPA(Single Page Application)にてページ遷移を可能にする機能です。
- Vuex: 
Vue.jsの状態管理ライブラリで、複数のコンポーネント間でデータを一元管理します。
- CSS Pre-processors: 
CSSの拡張機能で、変数やネスト、ミックスインなどを使用可能にします（例: Sass, Lessなど）。
- Linter / Formatter: 
コードのスタイルや構文エラーをチェックし、一貫性を保つためのツールです。
- Unit Testing: 
個々のコードの単位（関数、メソッド、クラスなど）をテストする手法です。
- E2E Testing: 
システム全体が連携して正しく動作するかをテストする手法（End-to-End Testing）です。

### Vueのバージョンを選択

```bash
? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
❯ 3.x 
  2.x 
```

### クラスベースの構文を使用するかどうか

```bash
? Use class-style component syntax? (y/N) 
```

Vue.jsでは、コンポーネントを作成する際にオプションAPIとクラスベースの構文の2つの異なるスタイルを選ぶことができます。
クラスベースの構文はTypeScriptとの親和性が高く、大規模なプロジェクトでの管理が容易になるようです。
今回はお試しなのでNoで行きました。

というか、Vue 3以降では、Composition APIが導入され、より機能的なコードの組み立てが可能となっているため、クラスベースの構文はあんまり・・・という感じらしいですね。

https://vuejs.org/guide/extras/composition-api-faq.html#what-is-composition-api


### TypeScriptとBabelを一緒に使うかどうか

```bash
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) 
```

この質問に"Yes"と回答すると、TypeScriptとBabelを一緒に使う設定が有効化され、旧バージョンのブラウザでもTypeScriptの新機能を安全に使用できるそうです。
Yesで行きました。

### Vue Routerのhistoryモードを有効にするか

```bash
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) 
```

Vue RouterはVue.jsアプリケーションでルーティングを管理するための公式のライブラリです。
Vue Routerでは、デフォルトではハッシュモードが使用され、URLに#が含まれます。
例：http://localhost:8080/#/about

一方、historyモードを有効にすると、#なしのきれいなURLを使用することができます。
例：http://localhost:8080/about

きれいな方がいいので"Yes"で行きました。

historyモードを使用するためには、サーバー側で適切な設定（全ての未知のURLをindex.htmlにリダイレクトするなど）が必要のようです。

### ES Lintと自動整形の設定

ES Lintだけにするか、ES Lint＋自動整形にするかを問われます。
自動整形するならどのツールを使うか問われてますね。
とりあえず自動整形ツールはなしにしました。

```bash
? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only 
  ESLint + Airbnb config 
  ESLint + Standard config 
  ESLint + Prettier 
```

Lintのタイミングを問われるので、Saveする時を指定。

```bash
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
❯◉ Lint on save
 ◯ Lint and fix on commit (requires Git)
```

### 設定ファイルの管理方法の選択

BabelやESLintの設定をそれぞれ独立したファイルにするか、`package.json`にごちゃ混ぜにするか問われます。
ごちゃ混ぜはわかりにくいと思うので、独立させる方を選びます。

```bash
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files 
  In package.json 
```

#### `In dedicated config files `を選んだ場合


```json:package.json
{
  "name": "sample-vue-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^3.2.13",
    "vue-router": "^4.0.3"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.4.0",
    "@typescript-eslint/parser": "^5.4.0",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-plugin-typescript": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "@vue/eslint-config-typescript": "^9.1.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "typescript": "~4.5.5"
  }
}
```

```js:.eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true
  },
  'extends': [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/typescript/recommended'
  ],
  parserOptions: {
    ecmaVersion: 2020
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
  }
}
```

#### `In package.json`を選んだ場合

`.eslintrc.js`ができず、`eslintConfig`が増えています。
babel.config.jsがなくなると思いましたが、存在していました。

```json:package.json
{
  "name": "sample-vue-project2",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.8.3",
    "vue": "^3.2.13",
    "vue-router": "^4.0.3"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.4.0",
    "@typescript-eslint/parser": "^5.4.0",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-plugin-typescript": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "@vue/eslint-config-typescript": "^9.1.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "typescript": "~4.5.5"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "eslint:recommended",
      "@vue/typescript/recommended"
    ],
    "parserOptions": {
      "ecmaVersion": 2020
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}
```

### 設定したオプションをプリセットとして保存するかどうか

```bash
? Save this as a preset for future projects? (y/N) 
```

特にいらないのでNoで行きました。

### パッケージマネージャーの選択

`Yarn`にしました。
新しい方がいいかなと。

```bash
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn 
  Use NPM 
```

## ローカルホストで起動してテスト

作成したVueプロジェクトをローカルホストで起動して、とりあえず画面を見ます。
今回はEC2で作成したので外部からアクセス可能にします。

vue.config.jsを修正。

```json:vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true
})
```

↓↓↓

```json:vue.config.js
const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    host: '0.0.0.0',
    port: 8080, // ポート番号は任意に変更可能
    allowedHosts: [EC2のパブリックIP],
  }
})
```

セキュリティグループはこちら。

![セキュリティグループの画面（抜粋）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/45c28c49-ec44-d81f-a8c1-790103cb3e98.png)


22番はRemoteSSH用です。

http://EC2のパブリックIP:8080
でアクセス。
Vueが表示されることを確認できました。
![http://EC2のパブリックIP:8080の画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/5e3799ac-6158-8313-b589-0f7d21af7d2c.png)

### [補足]所有者の変更

最初の最初、ローカルのMacで`sudo vue create`したら、`yarn serve`したらパーミッションエラーになってアワアワしました。
これは所有者が`root`だったせいないので、`chown`で所有者の変更をしておくと解消しました。
同じような現象になったら所有者の変更を試すとよいと思います。

```bash
 sudo chown -R ec2-user sample-vue-project
```

# Quasarの適用

## Quasarとは
Quasarは、SPAたPWAを作れるJSフレームワークです。
エレクトロンアプリが作成できるのが特徴とのこと。

https://quasar.dev/

Quasarは独自のCSSを持っており、VuetifyやBootstrapとの共存は難しいようです。

## QuasarをVueに適用する。

https://quasar.dev/start/vue-cli-plugin

公式の手順に従います。

VueのプロジェクトフォルダでQuasarを追加するコマンドを実行。

```bash
cd sample-vue-project
vue add quasar
```

以下、Quasarのウィザードの質問項目の説明です。

### 既存ソースを置き換えるか？

任せた方がいいと思うのでYes。
これを後からやるのは勇気がいるでしょうね。

```bash
? Allow Quasar to replace App.vue, About.vue, Home.vue and (if available) router.js? (Y/n) 
```

### SassやSCSSを使用するかどうか

```bash
? Pick your favorite CSS preprocessor: (Use arrow keys)
❯ Sass with indented syntax 
  Sass with SCSS syntax 
  None (style variables won't be available) 
```

正直、SassやSCSSはよくわからないのですが、もうスタンダードでしょうからYes。

### アイコンセットの種類を選択

```bash
? Choose Quasar Icon Set (Use arrow keys)
❯ Material Icons (recommended) 
  Material Icons Outlined 
  Material Icons Round 
  Material Icons Sharp 
  Fontawesome 
  Ionicons 
  MDI
```

### 言語パックの選択

```bash
? Default Quasar language pack - one from https://github.com/quasarframework/quasar/tree/dev/ui/lang en-US
```

現状日本語の必要性を感じないのでデフォルトの英語のままで。

### 右から左への記述（RTL）をサポートするか？

```bash
? Use RTL support? (y/N) 
```

RTLはRight To Leftの略です。
不要なのでNo。

### フォントの選択

デフォルトのままで

```bash
? Select features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
❯◯ Roboto font
 ◯ Material Icons (recommended)
 ◯ Material Icons Outlined
 ◯ Material Icons Round
 ◯ Material Icons Sharp
 ◯ Fontawesome
 ◯ Ionicons
```

## Qasarのjsファイル読み込みエラーの解消。

Quasar追加後に`yarn serve`でエラー発生。

```bash
webpack compiled with 1 error
ERROR in src/main.ts:5:31
TS7016: Could not find a declaration file for module './quasar-user-options'. '/home/ec2-user/sample-vue-project/src/quasar-user-options.js' implicitly has an 'any' type.
    3 | import router from './router'
    4 | import { Quasar } from 'quasar'
  > 5 | import quasarUserOptions from './quasar-user-options'
      |                               ^^^^^^^^^^^^^^^^^^^^^^^
    6 |
    7 | createApp(App).use(Quasar, quasarUserOptions).use(router).mount('#app')
```

Vue.jsでTypeScriptを使用している場合、jsファイルをインポートするにはTypeScriptのコンフィグでJSのロードを許可しないといけない。
ts.confiog.jsonでallowJsをtrueにする。

```json
 {
   "compilerOptions": {
     "allowJs": true
   }
 }
```

`ts.config.json`を修正後、`yarn serve`。

```bash
ERROR in ./src/quasar-user-options.js 2:0-58
Module not found: Error: Can't resolve '@quasar/extras/material-icons/material-icons.css' in '/home/ec2-user/sample-vue-project/src'
 @ ./src/main.ts 5:0-54 6:27-44 6:58-75
```

またエラーが出るのでメッセージを頼りに`@quasar/extras`を追加。

```bash
yarn add @quasar/extras
```

`yarn serve`でアクセス可能かつ画面が変わっていることを確認。

![Quasarに変わった画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/16e1e0f7-2c7f-56cc-99cc-f8dfddb92999.png)

# 最後に

Quasarインストール後、`yarn serve`でエラーになった時15分ぐらい悩みました。
`quasar-user-options`でエラーがあること、`quasar-user-options.js`というファイルがいつ間にかできていたことから、`allowJs`にたどり着いた次第です。
ただし、`Quasar`をTypeScriptありのVueで使うには型定義ファイル (.d.ts)を作るなどの方法が正しそうです。
この辺りは改めて調べておこうと思います。

# [おまけ]　Quasarの適用方法についてChatGptパイセンに聞いてみた

Quasarの適用方法をChatGptにも聞いてみたんですが、全然うまくいきませんでした。
Vue本体のイントールはうまくいったんですが・・・。
やっぱり公式サイトをちゃんと見るべきでした。

一個ツールを覚えたらそれに頼りっきりになる癖はつけない方がいいですね。