Vue.jsにvuetifyとbootstrap-vueを共存させる

# Vuetifyめんどくさい
https://vuetifyjs.com/ja/

Vue.jsのフレームワークはVuetifyがベストなのかもしれませんが、いかんせん細かい制御がめんどくさすぎる。レイアウトの扱いにくさ、レスポンシブの「なんでここでブレイクポイントが？？」デベロッパツールで見ても分かりにくすぎる。かゆいところに手が届かないのがもどかしい。

# Vuetifyの良いところ
とはいえcomponentは素晴らしいと思う。ログイン画面をサクッといい感じに作れちゃうところとか。Vue.jsと仲良しなところも。

# Bootstrap
https://getbootstrap.jp/

containerとかgridを最初にフレームワークとして導入したのはBootstrapではなかろうか。わたくしはwebデザイナーではないのでよくわからないけど、RailsにBootstrapを導入したときはなかなかどうして感動したものである。

# TailwindCSS
https://tailwindui.com/

VueでTailwindCSSはどうだろうと思ったが、日本語ドキュメントが充実していない。学習コストが高すぎる。

# で？
Vue.jsでさくっといい感じに作りたいだけだったら、Vuetifyはcomponentsとjs、Bootstrapのグリッドシステムのいいとこ取りでいいのでは？という結論に。

# 【本題】Vue.jsにVuetifyとBootstrap-vueを導入する
参考

https://qiita.com/devzooiiooz/items/018006bffab235498f58

## まずdockerでviteでvueの環境を構築
プロジェクト名は"vueframework"とします。
```sh:
mkdir vueframework
```
環境変数はdirenvを使用
```sh:
touch .envrc
```
必要な環境変数はここに書き込む
ここではprojectnameを定義しているだけ
```env:.envrc
# projectname
export PJNAME='vueframework'
```
環境変数を設定したらdirenv allow
```sh:
direnv allow
```
## 開発用vue3-vite環境の追加
vue3-viteの環境を構築
まずcompose.yamlを作成し、
次にvueのvite開発用ディレクトリdevを作成。
その配下にvueディレクトリを切りDockerfileを作成します。
```sh:
touch compose.yaml
mkdir dev
mkdir dev/vue && touch dev/Dockerfile
```
##### この時点でのtree -F
```sh:tree
./vueframework
├── compose.yaml
└── dev/
    ├── Dockerfile
    └── vue/
```
## vue3-vite用のDockerfileを編集
```Dockerfile:dev/Dockerfile
FROM node:lts-alpine
WORKDIR /
RUN apk update
```
## compose.yamlを編集
```yaml:compose.yaml
services:
  vue:
    build: ./dev/
    ports:
      - 5173:5173
    # Timezoneを日本に
    environment:
       TZ: Asia/Tokyo
    volumes:
      - type: bind
        source: ./dev/vue
        target: /vue
networks:
  # コンテナ間通信用のネットワークセグメント
  nw:
    name: ${PJNAME}_nw
```
## 一旦build
```sh:
docker compose build
```

### create-vueでプロジェクトの作成
```sh:
docker compose run --rm vue npm init vue@latest
```
対話式でvueプロジェクトを構築していきます。
```sh:
create-vue@3.14.0
Ok to proceed? (y) y

> npx
> create-vue


Vue.js - The Progressive JavaScript Framework

✔ Project name: … vue #ここはdev配下に作成したディレクトリvueと同じにする
✔ Add TypeScript? … No / Yes #=>No まだTypeScriptに手を出していない
✔ Add JSX Support? … No / Yes #=>No
✔ Add Vue Router for Single Page Application development? … No / Yes #=>Yes
✔ Add Pinia for state management? … No / Yes #=>Yes
✔ Add Vitest for Unit Testing? … No / Yes #=>No
✔ Add an End-to-End Testing Solution? › No #=>No
✔ Add ESLint for code quality? … No / Yes #=>Yes
✔ Add Prettier for code formatting? … No / Yes #=>Yes
✔ Add Vue DevTools 7 extension for debugging? (experimental) … No / Yes #=>No

Scaffolding project in /vue...

Done. Now run:

  cd vue
  npm install
  npm run format
  npm run dev
```
完了するとfrontend/vue配下にファイルが作成される。

### dev/Dockerfileを変更
WORKDIRを’/’から'/vue'へ変更
COPYコマンドを追加
```diff_docker:Dockerfile
FROM node:lts-alpine
+ #変更
- WORKDIR /
+ WORKDIR /vue
RUN apk update
+ # 起動コマンドを追加
+ CMD ["yarn", "dev", "--host"]
```

### 再度build
Dockerfileの変更を反映させるため、再度build
```sh:
docker compose build
```

### 確認
コンテナに入り、プロンプト(カレントディレクトリ：WORKDIR)が/vueだったらOK。
カレントが/vueにならないと次項のyarnが/vue配下にインストールされない。
確認後exitで抜ける
```sh:
docker compose run --rm vue sh
/vue #　exit
```

## yarnのインストール
```sh:
docker compose run --rm vue yarn install
```
※一回目失敗する場合があるのでerrorが出たらもう一度

インストール完了後vue配下にyarn.lockファイルとnode_modulesフォルダができる。
#### orbstackを使用している場合
vite.config.jsに以下を追加

```js:vite.config.js
export default defineConfig({
  server: {
    allowedHosts: true,
  },
  plugins: [
  ....
```
## コンテナ起動
ここでコンテナを起動させ、vueが表示されることを確認する。
```sh:
docker compose up -d
```
### Vue3の起動確認
http://locahost:5173/
で以下のvueの画面が確認できていればVite + Vue3の環境まではOK
![スクリーンショット 2024-11-04 17.06.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82975/d20576ff-9f30-044a-5969-0b519373f62e.png)

# Vuetifyの導入
https://vuetifyjs.com/ja/getting-started/installation/#section-65e25b5830d730ed30b830a730af30c830674f7f304658345408

↑ここの「既存プロジェクトで使う場合」を参照
#### docker compose upのまま
```sh:
docker compose exec vue yarn add vuetify
```
#### main.jsに次を追加する
```js:main.js
// Vuetify
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
...
const vuetify = createVuetify({
  components,
  directives,
})
...
app.use(vuetify)
...
```
## Vuetifyが適用されているか確認
vueの初期画面で確認してみます。
views/App.vueにv-btnを埋め込んでみます。(You did it!の下に)

```vue:App.vue
   <div class="wrapper">
      <HelloWorld msg="You did it!" />
<v-btn>
  Button
</v-btn>
...
```
あっという間にVuetify風の影付きボタンが表示されました。

![スクリーンショット 2025-01-31 0.25.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82975/3020b9f0-0602-56c0-5b19-9cd4e9a5138b.png)

# Bootstrap-vueの導入
Vuetifyがインストールされている状態でBootstrap-vueをインストールします

https://getbootstrap.com/docs/5.3/getting-started/vite/

+ Bootstrap本体とpopperjs
```sh:
docker compose exec vue yarn add bootstrap @popperjs/core
```
+ sass
```sh:
docker compose exec vue yarn add sass
```
+ scssファイルを作成
```sh:
docker compose exec vue touch src/assets/styles.scss
```
+ scssファイルを編集
```scss:./assets/styles.scss
// Import all of Bootstrap's CSS
@import "bootstrap/scss/bootstrap"
```
## main.jsにscssとbootstrapのJSをインポート

+ main.jsにscssとbootstrapのJSをインポートします。

```diff_javascript:main.js
import './assets/main.css'
+ import './assets/styles.scss'
+ // Import all of Bootstrap's JS
+ import * as bootstrap from 'bootstrap'
```
## vueの初期AboutViewにBootstrapのAccordionをコピペ
```vue:AboutView.vue
<template>
<div class="accordion" id="accordionExample">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
        Accordion Item #1
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <strong>This is the first item's accordion body.</strong> It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
      </div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
        Accordion Item #2
      </button>
    </h2>
    <div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <strong>This is the second item's accordion body.</strong> It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
      </div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
        Accordion Item #3
      </button>
    </h2>
    <div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        <strong>This is the third item's accordion body.</strong> It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
      </div>
    </div>
  </div>
</div>
</template>
```
BootstrapのAccordionが表示されました。

![スクリーンショット 2025-01-31 0.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82975/f930d6f1-5a5c-ec6a-5c9b-dbf72b65f92c.png)

### Bootstrapは全てが動くわけではない。
BootstrapのPopoverなど、Vuetifyと機能がかぶるものは動かないものもあるようです。
VuetifyのJSの機能を優先させ、BootstrapはCSSのみ使いたいというのであれば、main.jsでBootstrapのImportをコメントアウトするか、一部だけ有効にした方が良いです。