- 投稿日:2020-09-09T23:30:15+09:00
FirebaseのCloud Firestoreと連携して掲示板を作る【nuxt.js】
FirebaseとNuxt.jsで掲示板を作りました。削除ボタンが機能しなかったり未完成の部分があります。
この記事は
- Firebaseを活用してみたい
- Nuxt.jsでアプリ作ってみたい
という人向けに書いてみました。
「こんな感じでやれば短時間でFirebaseと連携できます」的なものを記事にしました。作っていく際に参考にした記事と躓いた点も書いていきます。中途半端な出来ですが初心者向けに書いてみました!Firebaseとは何?
Firebaseはリアルタイムでデータ同期ができるモバイルプラットフォームです。Firebaseを使うとサーバを立てたり、管理や保守がいらなくなるのでフロントサイドの作成に集中できます。
NuxtJSとは何?
NuxtJSは、Vueファイルで記述できるフレームワークです。モジュール構造で拡張でき一部分から徐々に採用することが可能で、静的なページから複雑なwebアプリケーションまで、あらゆるものの作成に使用できます。
以下公式から抜粋
本質的に汎用性があり、さまざまなターゲット(サーバー、サーバーレス、または静的)をサポートし、サーバーサイドのレンダリングは切り替えることができます。
強力なモジュールエコシステムにより拡張可能で、REST や GraphQL エンドポイント、お気に入りの CMS や CSS フレームワークなどさまざまなものに簡単に接続できます。
NuxtJS は Vue.js プロジェクトのバックボーンであり、柔軟でありながら自信を持ってプロジェクトを構築するための構造を提供します。めちゃくちゃ簡易的な掲示板
できたもの
実際に利用できます!コメントしてみてください!
http://keiziban.tk/about/簡易的な掲示板を作ってみました!削除ボタンは飾りです。https://t.co/73cLQb3M8d#protoout #JavaScript #Firebase pic.twitter.com/Hu4AITFnL0
— Toshiki (@Hirasawa1987) September 9, 2020機能
名前、コメントの投稿がきる
作成手順
任意のフォルダーに移動して
VScode
のTerminalより
yarn
を使って以下のコマンドでNuxtプロジェクトを作成することができます。
yarn create nuxt-app cloudfireTest
を実行すると、UIフレームワークなどの機能が必要か聞かれるので選択していき、終了したら
yarn run dev
で起動させます。無事に終了したら以下のアドレスにアクセスして実行されているか見ます。
http://localhost:3000
続いて
yarn add firebaseでインストールて完了です。
今回にUIフレームワークはBootstrapVueを選択したので、こちらでどのようなスタイルになるのかを調べました。フォルダ構造
pages
pagesディレクトリに
.vue
ファイルを作成するとページのルーティングができます、index.vue
が/
になり、about.vue
が/about
でアクセスできますabout.vue<template> <div class="container"> <div class="jumbotron"> <div class="container"> <h1 class="display-3">掲示板</h1> </div> <div class="links"> <client-only placeholder="Loading..."> <Memo /> </client-only> </div> </div> </div> </template> <script> import Memo from '~/components/Memo.vue' export default { components: { Memo } } </script>以下の部分でComponents内に作る
Memo.vue
が呼び出されます。<client-only placeholder="Loading..."> <Memo /> </client-only>Components
何度も利用可能な
.vue
で構成されています。今回のFirebaseとの連携はこちらに書いていきます。まずはComponents
にMemo.vue
を追加。
Memo.vue<template> <div> <p> <b-form-input v-model="name" placeholder="名前"></b-form-input> <b-form-textarea input v-model="age" placeholder="コメント" id="button"></b-form-textarea> <b-button id="button" size="sm" variant="outline-success" v-on:click="post(); removetext()">投稿</b-button> </p> <ul v-for="(data, index) in allData" :key="data.id" class="menu-list" > <li> 名前:{{data.name}} <br> コメント:{{data.age}}<br> <b-button size="sm" variant="outline-danger" class="delete" @click="switchDelateAlarm(); getIndex(index)"> 削除 </b-button> </li> </ul> <div v-show="showDelateAlarm" id="overlay"> <div id="delateAlarm"> <p>コメントを削除します</p> <b-button size="sm" variant="outline-dark" v-on:click="closeModal"> 戻る </b-button> <b-button size="sm" variant="outline-danger" @click="switchDelateAlarm(); deleteItem(data.id)"> 削除 </b-button> </div> </div> </div> </template> <script> import firebase from "firebase/app"; import "firebase/firestore"; export default { components: {}, data(){ return{ db: {}, allData: [], name: '', age: '', showDelateAlarm: false, id: [], } }, methods: { init: () => { const config = { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "", measurementId: "" }; firebase.initializeApp(config); }, post: function(){ const testId = firebase.firestore().collection('memos').doc().id; //ユニークなIDを生成 const docRef = firebase.firestore().collection('memos').doc(testId); const setAda = docRef.set({ name: this.name, age: this.age, createdAt: new Date() }); this.get(); }, get: function(){ this.allData = []; firebase.firestore().collection('memos').get().then(snapshot => { snapshot.forEach(doc => { this.id = doc.id; console.log(this.id); const array = []; console.log(array); this.allData.push(doc.data()); }) }); }, getIndex: function() { console.log(firebase.firestore().collection('memos')); }, deleteItem: function(deleteId, getIndex) { const db = firebase.firestore(); db.collection("memos").doc(deleteId).delete().then(function() { console.log("Document successfully deleted!"); }).catch(function(error) { console.error("Error removing document: ", error); }); this.showDelateAlarm = false; this.get(); }, switchDelateAlarm: function() { this.showDelateAlarm = true }, closeModal: function(){ this.showDelateAlarm = false }, removetext: function() { this.name = ''; this.age = ''; }, }, mounted(){ this.init(); this.get(); }, } </script> <style> #delateAlarm{ z-index:2; width:50%; padding: 1em; background:#fff; } #overlay{ /* 要素を重ねた時の順番 */ z-index:1; /* 画面全体を覆う設定 */ position:fixed; top:0; left:0; width:100%; height:100%; background-color:rgba(0,0,0,0.5); /* 画面の中央に要素を表示させる設定 */ display: flex; align-items: center; justify-content: center; border-radius: 10%; } ul { display: block; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0px; margin-inline-end: 0px; padding: 0px; list-style: none; } #button { margin-top: 2px; } </style>Cloud Firestoreの設定
こちらの部分にファイヤーベースの設定→全般の下のほうにあるマイアプリ
からコピー&ペーストします。
Memo.vueconst config = { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", messagingSenderId: "", appId: "", measurementId: "" };今回はあらかじめCloud Firestoreのコレクションに
memos
作成しておきます。設定
以下は
post
の部分を抜粋しています。Memo.vuepost: function(){ const testId = firebase.firestore().collection('memos').doc().id; //ユニークなIDを生成 const docRef = firebase.firestore().collection('memos').doc(testId); const setAda = docRef.set({ name: this.name, age: this.age, createdAt: new Date() }); this.get(); },躓いた部分
削除ボタンの実装に躓きました。ボタンに紐づいたドキュメントidが取得できずボタンは配置されていますが、機能しません。
参考にした記事
- ざっくりFirestore + Vue.jsの使い方
- 【v2対応】Nuxt.jsとFirebaseを組み合わせて爆速でWebアプリケーションを構築する
- 【Nuxt.js】todoアプリを作成してみた①
- firestore, vue.jsでリアルタイム同期のチャットを実装してみる [チュートリアル形式]
- Vue.js おすすめライブラリ 21選(おまけ+1)
終わりに
読んでいただきありがとうございました、よくわからん部分もあったと思います。私自身わかっていない部分が多いですが、とにかく一言いってやりたいという方!是非こちらで絡んでやってください。
- 投稿日:2020-09-09T22:52:48+09:00
Docker上にvue.jsの開発環境する。docker-composeで簡単に作成する手順。
Docker上にvue.jsの開発環境する。docker-composeで簡単に作成する手順。
dockerを使ってvue.jsの開発環境を簡単に構築できるようにする。
本番に応用できるよう、DockerfileのENTRYPOINTでコンテナ内のスクリプトを実行する。
また、実行はdocker-composeを使用する。
実行順序は docker-composeファイル -> Dockerファイル -> スクリプトファイル となる。複数人のプロジェクトを想定して、作成したファイル群をgithubにアップして、cloneしvue.jsの開発環境を立ち上げるまで。
開発手順
- Dcokerのインストール
- Dockerfileの作成
- シェルスクリプトの作成
- docker-compose.ymlの作成
- .dockerignoreの作成
- aliasの作成
- aliasファイルの読み込み
- docker-composeの実行
- コンテナ内に入る
- vueの開発環境を作成する
- ファイルの移動と削除
- vue開発環境の確認
- githubに作成したファイル群をプッシュ
- 他のプロジェクトメンバーのローカルで実行する
Dcokerのインストール
Dockerの公式ページからOSに合ったDockerをインストール
https://docs.docker.com/get-docker/
設定が完了したら、正しくインストールされているかターミナルで確認。
$docker -v Docker version 19.03.12 $docker-compose -v docker-compose version 1.26.2dockerとdocker-composeのバージョンがそれぞれ表示されたらOK。
Dockerfileの作成
環境開発時のコマンドはdocker-composeで実行するが、独自のイメージを作成(build)する際に、Dockerfileを指定する。
Dockerfileはコンテナ内の処理となる。
プロジェクトフォルダを作成したい階層に移動。
ここでは、PJのルートディレクトリとしてvuecliを作成する。ターミナル#vuecliフォルダを作成し移動 $ mkdir vuecli && cd vuecli #Dockerfileを作成 $ touch Dockerfile #vimエディタでファイルを開く $ vi Dockerfile▼vimエディタの超基本コマンド
- 貼り付け:
p
- インサートモード:
i
- インサートモード終了:
esc
- 保存して終了:
:wq
▼Dockerファイルの内容
Dockerfileは拡張子不要。
Dockerfileには下記を記述。Dockerfile#nodeイメージをpullする FROM node:10.15.3-alpine #working directory WORKDIR /app #vuecliインストール RUN npm install -g @vue/cli #shファイルをコンテナにコピー COPY ./scripts/docker.start.sh /scripts/start.sh #shフォルダの権限追加(全員実行可) RUN chmod +x /scripts/* #初期実行 # ENTRYPOINT [ "/scripts/start.sh" ]Dockerfileはイメージを作成するための元となるファイル。
・
FROM イメージ名:タグ
継承のような機能。指定したイメージを取得し、以下に続く処理を実行する。
タグはバージョンを指定。記載しない場合は最新版(latest)が選択される。
イメージの取得は、まずdocker公式の共有イメージ置き場であるdockerhubで該当するものがあるか探す。ない場合はローカルのDocker内のイメージを探す。
(補足) node:10.15.3-alpineとは?
本当はvue-cliのイメージを取得したいが、現状dockerhubにはないため、nodeのイメージを取得する。バージョンは10.15.3、OSはlinux alpineを選択。
linux alpineは軽量のOS。dockerのイメージで見かけることが多い。注意点としてはbashファイルが存在せず、shファイルのみとなること。(後々の記述に影響)
・
WORKDIR パス
コンテナ内のワーキングディレクトリの指定。
デフォルトではルートディレクトリ(/)が指定されているが、WORKDIRで変更することができる。
・
RUN コマンド
コンテナ内で実行するコマンドを記述。
「npm install -g @vue/cli」で、vueを操作するコマンドラインインターフェース(cli)をインストールする。exec形式(配列でコマンドと引数を順に記述)での記述も可能。例えば上のコマンドだと、
RUN ["npm", "install", "-g", "@vue/cli"]
・
COPY ホスト内パス コンテナ内パス
ホスト内のファイルをコンテナの指定したパスにコピーする。
親フォルダが存在しない場合は自動で作成される。コンテナ内のシェルスクリプトでコマンドを実行する仕様とするため、予めホスト内でコマンドを記述したシェルスクリプトを作成しておき、それをコンテナ内にコピーする。(シェルファイルの作成は後ほど)
シェルスクリプトに実行権限を与え、ファイルパス指定で実行できるようにする。
「RUN chmod +x /scripts/*」で権限を付与。実行権限を与えない場合は、shコマンドでないと実行できない。「$sh シェルスクリプトパス」
・
ENTRYPOINT [ "コマンド", "引数",,]
ENTYPOINTはコンテナ初回起動時に実行するコマンド。
コンテナ内のスクリプトファイルのパスを指定することで、コンテナ初回起動時に指定したスクリプトを実行できる。
(補足)
ENTRYPOINT
とCMD
の違い
ENTRYPOINT
とCMD
はどちらもコンテナ初回実行時に実行するコマンド。どちらか一つは必ず必要で、記述がないとエラーになる。
ENTRYPOINTとCMDもexec形式(配列のような形)でコマンドを渡せる。その際、引数の扱いが異なる。
- ENTRYPOINT: 引数の変更はできない。追加の引数として処理する。
- CMD: 引数に変数を指定できる(状況に合わせて変更可能)
コマンドの記述でよく見る例
CMD [ "/bin/sh" ]
: shファイルを実行CMD [ "/bin/bash" ]
: bashファイルを実行CMD [ "npm", "run", "serve" ]
: 「$npm run serve」コマンドを実行(vue.jsのサーバー起動)
シェルスクリプトの作成
ローカルのPJルートディレクトリにscriptsフォルダを作成し、シェルスクリプト「docker.start.sh」を作成する。
ターミナル#scriptsフォルダとシェルファイルを作成 $mkdir scripts && touch ./scripts/docker.start.sh #vimエディタで開く $vi ./scripts/docker.start.sh▼シェルスクリプトの記述内容
docker.start.sh#!/bin/sh #node_modulesインストール echo "npm install" npm install #vue起動 echo "npm run serve. " npm run serve #メモを出力 echo "localhost:18080"※(補足)シェルスクリプトの利用について
指定のシェルスクリプトを使用せず、DockerfileのみでCMD ["npm","run","serve"]
でも実行できるが、実際の開発で、開発環境と本番環境でインストールするライブラリを変更するなど、条件分岐(if)などを使うことを想定。
docker-compose.ymlの作成
docker-composeは複数のコンテナでプロジェクトを立ち上げる時に使う。
例えば、①ruby on rails, ②PostgreSQL, ③Redis, ④Sideqikのコンテナをまとめて立ち上げることができる。
docker-composeで立ち上げたコンテナは自動で独自のネットワーク(コンテナ同士の関連づけ)が設定される。
docker-composeファイルの拡張子はyml(ヤムル)なので、ヤムルの仕様に沿って記述する。
まずはPJのルートディレクトリにファイルを作成する。
terminal#ファイル作成 $touch docker-compose.yml #vimエディタで開く $vi docker-compose.yml▼docker-compose.ymlの記述内容
docker-compose.yml#docker-composeのバージョンを指定 version: "3.7" volumes: #volumeはホストにコピー or 表示させないもの ##バイナリファイル(node_module)など、OS依存があるもの #node_moduleを入れるvolume vue-cli-node-volume: services: #コンテナ詳細 app: image: vuecli:1 build: context: . dockerfile: Dockerfile container_name: vuecli3 ports: - "18082:8080" volumes: #node_moduleを入れるボリューム - vue-cli-node-volume:/app/node_modules #コンテナ内の指定ディレクトリをホスト側と同期 - .:/app/ #-it stdin_open: true tty: true・
version:"メジャーNo.マイナーNo"
docker-composeのファイルフォーマットのバージョンを指定する。versionにより記述方法に違いがあるため注意。今回は3.7を指定。
マイナーNoを記述しない場合、0に置き換わる。
例: version:"3" = version:"3.0">ファイルフォーマットとdocker-composeのバージョンの対応表
https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-versioning/・
volumes:
トップレベルに「volumes:」を記述すると、指定したvolume名を各コンテナで共有できるようになる。
volumeを使用すると、指定したコンテナのディレクトリやファイルをホストのdockerのストレージに保存する。
▼volumeの使い方
volumeの使い方は大きく3つ。
(1)ホスト側のPJルートディレクトリと同期する
コンテナ内のワーキングディレクトリと、PJのルートディレクトリを同期することで、viewファイルやsrcなどがリアルタイムで同期できる。
- .:/app/
(ホスト側のパス:コンテナ側のパス)
上記例では、コンテナのワーキングディレクトリ/app/を、ホスト側のdocker-composeを実行するディレクトリに同期している。(2)ホスト側にコピーしたくないファイルやディレクトリの指定。
volume名を指定することで、.dockerignoreファイルと組み合わせ、ホスト側に同期させないようにすることができる。
例えば、バイナリファイルが該当する。
バイナリファイルはバイナリ(0,1)で書かれたPC用のテキストファイルでOS毎に内容が異なる(依存性がある)。コンテナ内にインストールしたnodeはLinux用なので、ホスト側のOSと一致しない場合に不具合を起こす。なので、nodeの入ったnode_modulesはホスト側のPJディレクトに同期させないようにする。(.dockerignoreファイルと合わせて使う)
(3) 同期除外しなくてもいいが、ホスト側にも特に必要ないファイルやディレクトリ
ログファイルなどログ分析用ファイルに同期している場合はホストのPJディレクトリに同期する必要はない。
volumeの記述方法
volumesの記述は
ホスト側:コンテナ側
。
実際の記述方法は大きく3つ。(1)コンテナ側のパスのみ
./logs
/var/lib/mysql
ホスト側のパスを記述しない場合、コンテナ内の指定したフォルダはホストのvolume内のどこかに保存される。
呼び出す必要もないファイルやディレクトリに使う。
(2) ボリューム名で指定
node_volume: ./node_modules
ホスト側をボリューム名で記述する方法。この場合、docker内に指定したボリューム名のディレクトリが作成され、その中に指定したフォルダやファイルが保存される。
ホスト側のPJディレクトリに保存したくない場合に使用。(.dockerignoreを合わせて使う)
(3) パスで指定
./cache:/tmp/cache
パスで指定することも可能。
上記例では、ホスト側を相対パス、コンテナ側を絶対パスで指定。・
sevices:
コンテナと使用するイメージを設定する。
今回はappコンテナのみ作成。・
image: イメージ名:タグ
コンテナ作成のために使用するimageを指定する。
タグはバージョン。記述しない場合はlatestとなる。buildがある場合は、buildに記載の内容からイメージを作成する。buildの指定がない場合は、dockerhub、ローカルの順にイメージを探す。
・
build
イメージを作成するためのDockerfileを指定する。
記述方法は2つ。(1)Dockerファイルのパスとファイル名で指定
build: context: Dockerファイルのパス dockerfile: ファイル名(補足)Dockerfileのファイル名について
Dockerfileのファイル名は「Dockerfile」に限定する必要はない。指定ディレクトリの拡張子のないファイルを構築用ファイルとみなす。
誰が見てもわかりやすいように「Dokerfile」を記述するのが一般的。
▼ファイル名の例
- Dockerfile
- Dev.Dockerfile
- Dockerfile-2(2)ファイルのパスで指定
構築用ファイル(拡張子のないファイル)がディレクトリに1つのみのとき、ディレクトリパスのみの指定もできる。build: Dockerファイルのパス・
container_name:
作成したコンテナの名前を指定する。
「docker ps -a」 でコンテナの一覧を出した時に表示される名前。・
ports: - ホスト側:コンテナ側'
ポートの指定。複数設定することも可能。
「- "18082:8080"」の場合、コンテナ側の通信ポート8080と、ホスト側の18082ポートをつなげる。
ホスト側のブラウザにlocalhost:18082と打ち込むと、コンテナ内で開発用サーバーを立ち上げた時に表示されるlocalhost:8080に接続する。
・
stdin_open: true
コンテナ起動時のオプション。標準入力(standard in)を許可する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。Dockerのコマンドでは「-i」
・
tty: true
コンテナ起動時のオプション。標準出力用の擬似ターミナルを起動する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。Dockerのコマンドでは「-t」
基本的に「-t」と「-i」はセット(-it)で使う。
.dockerignoreの作成
ホスト側に同期したくないファイルやディレクトリのパスを記述する。(.gitignoreと同じ機能)
terminal#ファイルの作成 touch .dockerignore #vimエディタで開く vi .dockerignore▼.dockerignoreの内容
.dockerignore#node_modulesは同期しない node_modulesコンテナ作成を実行すると、ローカル内にnode_modulesという空のフォルダが自動作成される。コンテナ内の同じフォルダの内容を同期しなくなる。
aliasの作成
ここまでで、ようやくイメージとコンテナを作成するために必要なファイルが揃った。
- docker-compose.yml
- Dockerfile
- docker.start.sh
- .dockerignore
この時点でdocker-composeを実行することもできるが、本番を見据えてdocker-composeコマンドのaliasを作成することで、より簡単に操作できるようにする。
作成の流れは、aliases.shファイルを作成しコマンドを記述。bash_profileでファイルを読み込み、bash_profileをリロード。
terminal#ファイルを作成 $ touch aliases.sh #vimエディタで開く $ vi aliases.sh▼aliases.shの内容
aliases.sh#イメージの作成とコンテナ起動 alias vue-pj="docker-compose up --build app" #コンテナ内のshファイルを起動 alias vue-exec="docker exec -it vuecli sh"・
alias ショートカットコマンド="本来のコマンド
イコールの前後にスペースがあるとエラーになる。・
docker-compose up --build app
「docker-compose up [サービス名]」:指定したサービスの内容を実行。イメージがない場合はビルドし、コンテナを起動する。イメージが既に存在する場合は上書きせず、それを使用する。
docker-compose.ymlの変更内容を反映したいため、「--build」オプションをつけることで、イメージが存在しても再度イメージを構築する。(docker-compose build && docker-compose up appと同じ)
▼サービス名の指定がない場合
サービス名を指定しない場合は、記述してある全てのコンテナを起動する。今回の環境では、appの指定がなくても同じ挙動となるが、実際は開発環境や本番環境で立ち上げるコンテナを切り替えることがあるためあえて指定。
▼「-d」オプション
-dオプションをつけると、バックグラウンドモードでの起動となり、bash(or sh)が起動しない状態となる。
コンテナ内の実行内容が見えなくなってしまうため、今回は付けない。・
docker exec -it コンテナ名 sh
指定したコンテナのシェルを立ち上げる。コンテナ内がbashの場合はshではなくbashを指定。今回はlinux alpineのためshを指定。
aliasファイルの読み込み
作成したaliasが使えるように、bashで読み込む。
terminal#bash_profileをvimエディタで開く $ vi ~/.bash_profile▼bash_profileの内容
bash_profile#作成したファイルを読み込み(フルパスで記述) source /Users/.../vuecli/aliases.shterminal#bash_profileのリロード $ source ~/.bash_profile #aliasの確認 $ alias alias vue-exec='docker exec -it vuecli sh' alias vue-pj='docker-compose up --build app'作成したaliasが表示されていればOK。
bash_profileとは?
bash_profileはシェルをbashで起動したときに読み込まれるファイル。
設定したaliasはシェルを閉じると消えるが、bash_profileに記述することで毎回自動でロードされる。
似たファイルで、より高頻度でロードする、.bashrcというのもある。
docker-composeの実行
いよいよdocker-composeを実行し、イメージとコンテナを作成する。
docker-compose.ymlのあるディレクトリで先ほど設定したコマンドを実行。
terminalvue-pjこれで、コンテナ内にnode.jsとvue-cliがインストールされる。
コンテナ内に入る
コンテナ内でvue-cliを使ってvue.jsの開発環境を作成するため、先ほど作成したaliasでコンテナないのシェルを起動する。
terminalvue-exec /app #
/app #
と表示されれば、docker内に作成したワーキングディレクトリでコマンドを打ち込める状態になっている。
vueの開発環境を作成する
コンテナ内シェル/app #vue create -d pj
vue create プロジェクト名
ここではプロジェクト名をPJとして実行。
オプションの「-d」はデフォルト設定(bavelとeslint)で作成。「-d」を記述せず、vue-cliの対話モードでオプションを選択してくこともできる。
ファイルの移動と削除
vue createを実行するとフォルダは指定したプロジェクト名のフォルダの中に作成される。
ホスト側のプロジェクトファイルのルートディレクトリとコンテナ内のワークディレクトリを同期させたいため、コンテナ内のプロジェクトフォルダの中身を一階層上に上げる。
.dockerignoreに記述しているnode_modulesは同期するディレクトリに移動できないため、一度削除し再インストールする。
まず、コンテナ内のvue-cliが立ち上がっているので、
ctrl + c
でいったん終了し、コンテナ内のシェルに戻る。コンテナ内シェル#pjフォルダを一階層上に移動(隠しファイル含む) ##gitignoreのnode_moduelsは移動できない mv -f ./pj/* ./pj/.* . <br> ##node_modulesファイルを削除し、再インストール rm -r pj && npm install ##yarn関連ファイルを削除。 rm *yarn* ##コンテナ内を確認 /app # ls Dockerfile node_modules scripts aliases.sh package-lock.json src babel.config.js package.json docker-compose.yml publicホスト側にコンテナ内のファイルが反映されていればOK
vue開発環境の確認
これで自分のPCでの開発環境の設定が完了したので、実際にWEBページが開けるか確認する。
npm run serve
でサーバーを再起動できるが、dockerの練習も兼ね一旦コンテナから出て確認してみる。#コンテナから抜ける /app # exit #起動中のコンテナを確認 $docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ebe0276cb7f0 vuecli:0 "/scripts/start.sh" 36 minutes ago Up 4 minutes 0.0.0.0:18080->8080/tcp vuecli#イメージを確認 $docker images REPOSITORY TAG IMAGE ID CREATED SIZE vuecli 0 c6a23f947246 32 hours ago 338MB #イメージの詳細 $docker image inspect vuecli:0docker-compose.ymlに記述したコンテナ名とイメージ名のコンテナとイメージがそれぞれ存在していることがわかる。
WEBページを確認するため、再びコンテナ内に入る。
#コンテナ内に入る $vue-exec #サーバーを起動 /app # npm run serve App running at: - Local: http://localhost:8080/ It seems you are running Vue CLI inside a container. Access the dev server via http://localhost:<your container's external mapped port>/上記が表示されればサーバーの起動完了。
WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18080
WEBページが表示されれば成功。
githubに作成したファイル群をプッシュ
このままでは自分しか使えないため、複数人で開発を進められるようgithubのリモートレポジトリに作成したファイル群をプッシュする。
githubのレポジトリを指定してアップする。
git init git commit -m "first commit" git branch -M master git remote add origin https://github.com/(レポジトリのフルパス) git push -u origin master
他のプロジェクトメンバーのローカルで実行する
前提条件として、dockerとdocker-composeが入っていること。
#リモートレポジトリをclone ##クローンした際のフォルダ名をvuecli(任意)としている。 $git clone https://github.com/(レポジトリのフルパス) vuecli #フォルダ移動 $cd vueclialiasファイルの読み込み
作成したaliasが使えるように、bashで読み込む。
terminal#bash_profileをvimエディタで開く $vi ~/.bash_profile▼bash_profileに以下を記述
bash_profile#作成したファイルを読み込み(フルパスで記述) source /Users/.../vuecli/aliases.shterminal#bash_profileのリロード $source ~/.bash_profile #aliasの確認 $ alias alias vue-exec='docker exec -it vuecli sh' alias vue-pj='docker-compose up --build app' #イメージとコンテナ作成 $vue-pj 省略 App running at: - Local: http://localhost:8080/ It seems you are running Vue CLI inside a container. Access the dev server via http://localhost:<your container's external mapped port>/上記が表示されればサーバーの起動完了。
WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18080
WEBページが表示されれば成功。
以上。
- 投稿日:2020-09-09T21:33:07+09:00
Vuetifyのv-data-tableで奇数行の背景色を変える
やりたいこと
Vuetifyに用意されているテーブルコンポーネント[v-data-table]がデフォルトのままだといまいち見づらかったので、
よくある奇数行だけ色が変わっている一覧にしたいおなじみのCSSを設定してみる
普通にCSSで奇数行の色変わるように指定
App.vue<style scoped> .v-data-table td { background: #f0f8ff; } .v-data-table tr:nth-child(odd) td { background: #fff; } </style>変わらない。。。
あぁ、scopedがついてるから子コンポーネントには反映されんのか。。。App.vue<style> .v-data-table td { background: #f0f8ff; } .v-data-table tr:nth-child(odd) td { background: #fff; } </style>
変わった!
・・・けど、マウスオーバーしてる行の背景色が変わらなくなった。。。tableのstyle上書きしてしまったから?
しょうがないから自分で設定してやる。App.vue<style> .v-data-table td { background: #f0f8ff; } .v-data-table tr:nth-child(odd) td { background: #fff; } .v-data-table tr:hover td { background-color: #eee; } </style>完成!
- 投稿日:2020-09-09T21:19:32+09:00
Vue.jsでおみくじアプリを作ってみた
はじめに
Vue.jsを学習中の初心者の私が理解を深めるためにおみくじアプリを作ったのでアウトプットの為に記事を書いておきます。
同じVue.js初心者の助けになれば嬉しいです。やろうと思うこと
おみくじは大吉、中吉...と○吉の文字を配列に入力しておきます。
ブラウザ上のボタンをクリックしたら配列数以下のランダムな数を取得し、それを使って同じ数の配列を取得してアラートを出します。コード
omikuzi.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>Vue.js</title> </head> <body> <div id="app"> <button @click="result">結果を見る</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="js/omikuzi.js"></script> </body> </html>omikuzi.jsnew Vue({ el: '#app', data: { list: [ '大吉', '中吉', '小吉', '末吉' ], }, methods: { result: function() { const num = Math.floor(Math.random() * this.list.length) alert(this.list[num]) } } });ではhtmlからコードの説明をしていきます。
まず<div id="app">
はVue.jsの影響を及ぼす範囲のルートになります。
omikuzi.jsでel: '#app'
と記載しているのでそれ以外の場所には影響を与えません。
Vue.jsをシンプルに理解しよう その2
詳しくは上記記事をお読みください。次に
<button @click="result">結果を見る</button>
ですが、
これはボタンをクリックした時にresultメソッドを呼び出すという意味になります。最後に
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
と
<script src="js/omikuzi.js"></script>
ですが、これはVue.js本体とresultメソッドを書いているomikuzi.jsを読み込むという意味になり、この読み込みが無い場合はVue.jsの機能である@clickやomikuzi.jsに書いてあるresultメソッドを呼び出せなくなるため正常に動作しません。次にjavascriptファイルの説明をしていきます。
まずnew Vue
ですがこれはVueインスタンスを作成しています。
Vue.jsはnew Vue
で作成されたルートVueインスタンスの中にメソッドなどをツリー状にして保存しているのでnew Vue
が無い限りVue.jsは動かないと思います。(Vue.js初心者の言うことだからもしかしたら違うかも?)
詳しくはVue.jsの公式ガイドをお読みください。次に
data:
の中にあるlist:
に配列で大吉などの○吉を入力しています。
これでlist[0]と書くことで大吉を呼び出すことができます。次にメソッドの説明をしていきます。
methods:
の中でresult: function()
と書くことでresultメソッドを作成しています。
resultメソッドに記載しているconst num = Math.floor(Math.random() * this.list.length)
はnumという箱にランダムな数字を生成して入れるという意味です。
もっとわかりやすく書くとMath.floor
は【小数点以下を切り捨てる】、Math.random()
は【0以上1未満の数字をランダムで生成する】、this.list.length
はlistの配列のデータの数を意味しています。なので0以上1未満の数をランダムで生成してlistのデータの数だけ掛け算して、計算結果の小数点を切り捨ててnumに保存するという意味になります。
最後に
alert(this.list[num])
ですがalertは文字通りアラートを出します。
alertの()内にどのデータをアラートで表示するかを記載できるのでthis.list[num]
でlistにある先ほど生成したランダムな数値を使って配列のデータを表示します。最後に
一応私なりに頑張って書きましたが、かなり冗長になってしまいました。
ここが分かりづらいやこうするのがおすすめなどのご意見ありましたらコメントにお願いします。
- 投稿日:2020-09-09T20:22:36+09:00
Webpack関連
Vue.jsで開発でWebpack関連でつまずくことが多かったので得た情報をまとめていく
Webpack4、CopyWebpackPluginのwebpack.config.js
Webpackはバージョンアップごとに設定ファフィルの記述方式が変わるらしい
↓見出し環境下での基本的な設定方法↓webpack.config.jsconst CopyPlugin = require("copy-webpack-plugin"); module.exports = { plugins: [ new CopyPlugin({ patterns: [ { from: "**/*.html", to: "./sample", context: ".src/sample", }, ], }), ], };正直よくわかってない
参照ページ
https://tadtadya.com/webpack4-error-of-version-up-of-copywebpackplugin/
ValidationError: Invalid options object.
Vue.jsで
npm run dev
実行時に発生したエラーValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema. - options[0] misses the property 'patterns'. Should be: [non-empty string | object { from, to?, context?, globOptions?, filter?, toType?, force?, flatten?, transform?, cacheTransform?, t ransformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
トップディレクトリ/build/webpack.dev.conf.js
内のnew CopyWebpackPlugin
部分を以下のように書き換えwebpack.dev.conf.jsnew CopyWebpackPlugin({ patterns: [ { from: 'source', to: 'dest' }, { from: 'other', to: 'public' }, ], }),参照ページ
- 投稿日:2020-09-09T20:07:01+09:00
アイデアの相互評価ができるidea streamerを作りたかったああああ
アイデアの評価むつかしい問題
最近世の中でアート思考だとかデザイン思考だとかがもてはやされるようになった気がします。
でも誰か知り合いが出したアイデアって、忖度なしで評価するの結構難しいと思うんですよね。
例えば上司のアイデアだったら「いいですね!」と言ってしまいそうですし、斬新なアイデアであっても、「こいつ生意気やんけ」といって評価を下げてしまう人もいるかもしれません。今回は「ひたすらアイデアを投稿しまくって」「それを知らない誰かに評価してもらえる」idea streamerというプラットフォームを作ってみました。
途中バグがあったり画面遷移がうまくいかなかったりで、超未完成ですが一旦振り返りの意味で投稿してみたいと思います。
「アイデアの相互評価」という意味で面白い仕組みだと思うので、何か刺激になればなと思います。アプリはこちらから入って、途中で画面遷移が切れるのでアイデア評価からはこちらからお願いします!
動作デモ
アイデアのブレスト
3分間の間にひたすらアイデアを投稿しまくっていきます。
Keywordに自分の好きな単語を入れておくと、「×〇〇」の部分がランダムで変わっていきます(技術不足で途中バグってます)。
普段交じり合わない組み合わせからアイデアを発想して投稿しまくる、という感じですね。アイデアを投稿しまくって知らん人に評価してもらうIdeaStreamerというプラットフォームを作りたかった
— canonno (@canonno_blog) September 9, 2020
途中バグってますが一回区切りでQiita書きます#protoout #アイデア思考 #idea #VueJS pic.twitter.com/QDcnUBVOtvアイデアの評価
アイデア出しが終わったら次は知らない人が投稿したアイデアの評価を行います (画面遷移の実装ができてません)。
DBにあるアイデアを見て面白い・斬新だな、などの観点で0~10の間で評価します。
現状自分のアイデアも見れるようになっていますが、そうすると自己評価になって意味がないので、他の人のアイデアだけ取り出す処理が必要そうですね。アイデア出しが終わったら次はアイデア評価になります。
— canonno (@canonno_blog) September 9, 2020
画面遷移の実装ができてないので手動で遷移しています。
他の人が出したアイデアに0~10の評価をつけて返します。
Postボタンを押したらアイデアが変わる実装もできてないので手動で変えていますboroboro#protoout #VueJS #アイデア思考 pic.twitter.com/r1gb8tYn1sアイデアのスコアの確認
こちらは全く実装できてません。
自分のアイデアがどう評価されたのかを確認できるようにしたいですね。自分が出したアイデアへの評価結果を確認したい。
— canonno (@canonno_blog) September 9, 2020
技術不足すぎて実装できませんでしたがそんな想定ですクヤシィィィイ#protoout #VueJS #アイデア思考 pic.twitter.com/IhPeEBbv5Qできたこととできなかったこと
実装できた
・アイデア出しする仕組み
・アイデア評価する画面
・全体の雰囲気実装できなかった
・アイデア評価の仕組み
・自分のアイデアのスコア確認
・全部0点にしちゃうなど悪ふざけ対策
・画像がデフォルト悔しい。。。
実装こまごま
yarnでいろいろ
今回は初めてNuxt.jsを使って実装してみました。
結構癖があるけれど使いこなせたら楽しそう。
備忘録的に記録しておきます。$ yarn create nuxt-app myNuxtTest Project name: myNuxtTest Programming language: JavaScript Package manager: Yarn UI framework: Bootstrap Nuxt.js modules: Axios, Progressive Web App (PWA), Content Linking tools: (Press <space> to select, <a> to toggle all, <i> to invert election) Testing framework: None Rendering mode: Universal (SSR / SSG) Deployment target: Static (Static/JAMStack hosting) Development tools: None $ cd myNuxtTestpagesの中に画面を作ったり、componentsにコンポを作り終わったら、
$ yarn devを実行後localhost:3000へアクセスし、画面を確認します。上手く動作していれば、
$ yarn generateでhtmlを生成し、distフォルダをデプロイ、という流れです。
generateしてフォルダ構造がどう変化するかをちゃんと把握していなかったため、画面遷移がうまくできなかったです。。。悔しい。Netlifyにデプロイしたのち、freenomで取得したドメインでURLを生成しました。
freenomは今回初めて使いましたがこんなにお手軽にドメインが借りれるのは驚きですね。タイマーがゼロになったら次へ
カウントダウンタイマーはこちらのサイトを参考にさせていただきました。
カウントがゼロになったら自動で画面遷移するようにしたかったものの、うまく実装ができず。。。
ひとまずはv-showで表示非表示を制御して、ユーザにクリックしてもらう作戦に変更しました。<template> <div> <div v-show="show"> <div id="timer"> <div class="timer"> <div class="time"> {{ formatTime }} </div> </div> </div> <h3> <input v-model="key" placeholder="KeyWord" class="key"> × {{reactant}} = <input v-model="idea" placeholder="Input Your Idea" class="idea"> </h3> <br> <h3> <button v-on:click='random' class="button--green">Pass</button> <button v-on:click='post' class="button--green">Post</button> </h3> </div> <div v-show="shownext"> <a href="ScoreIdea" target="_blank" rel="noopener noreferrer" class="button--green" > Next Step </a> </div> </div> </template>script部分はカウントダウンする部分の処理と、データをDBへPostする処理を実装しました。
vueのライフサイクルをまだ理解しておらず、createdやmountedが使いこなせていないです。。。
いやあこのあたりもちゃんと理解したい。<script> import firebase from "firebase/app"; import "firebase/firestore"; export default { components: {}, data(){ return{ db: {}, reactant: 'Click Pass', allData: ["文化","コロナ","夢","飲む","食べ物","おいしい","恋愛","決める","地面"], show:true, shownext:false, min: 2, sec: 59, timerOn: false, timerObj: null, } }, methods: { //初期化 init: () => { const config = { //firebaseの情報 }; // Initialize Firebase firebase.initializeApp(config); }, //カウントダウン処理 count: function() { if (this.sec <= 0 && this.min >= 1) { this.min --; this.sec = 59; } else if(this.sec <= 0 && this.min <= 0) { this.complete(); } else { this.sec --; } }, //カウントがゼロになった処理 complete: function() { clearInterval(this.timerObj) this.show = false; this.shownext = true; }, //ボタンを押したらランダムに表示 random: function(){ const rnd = Math.floor(Math.random() * this.allData.length); this.reactant = this.allData[rnd] }, //データ追加の処理 post: function(){ const testId = firebase.firestore().collection('test').doc().id; //ユニークなIDを生成 const docRef = firebase.firestore().collection('test').doc(testId); const setAda = docRef.set({ key: this.key, reactant:this.reactant, idea:this.idea }); this.random(); this.idea = ""; //window.location.href = "JoinTable"; }, //データ取得の処理 get: function(){ //this.allData = []; firebase.firestore().collection('test').get().then(snapshot => { snapshot.forEach(doc => { console.log(doc); this.allData.push(doc.data()); }) }); this.random(); } }, //インスタンスが生成したときの処理 created(){ let self = this; this.timerObj = setInterval(function() {self.count()}, 1000) this.timerOn = true; //timerがOFFであることを状態として保持 }, //常に動く処理 computed: { formatTime: function() { let timeStrings = [ this.min.toString(), this.sec.toString() ].map(function(str) { if (str.length < 2) { return "0" + str } else { return str } }) return timeStrings[0] + ":" + timeStrings[1] } }, //マウントされたときの処理 mounted(){ this.init(); this.get(); }, } </script>あとはデザイン部分ですね。
これはほとんどデフォルトのものを利用しています。<style> input{ text-align: center; } input.key{ width:160px; height:50px; } input.idea{ width:260px; height:50px; } #timer { display: flex; align-items: center; justify-content: center; } .time { font-size: 100px; } </style>さいごに
フレームワークの便利さを感じれるほどまだ慣れておらず、この辺りは経験積んでいくしかないですね。
この辺は精進していかなきゃなあと思います。
アイデア自体は悪くないと思うのに悔しい。。。最後までご覧になっていただきありがとうございました!
LGTMしていただけると励みになりますので、是非是非よろしくお願いします!
- 投稿日:2020-09-09T18:25:49+09:00
Electron(+Vue)でnode-oracledbを利用する
はじめに
Windows環境でのVue+Electronアプリ開発においてOracleデータベースへのアクセスに一苦労あったので実現方法を備忘録として残す。
環境
- Windows 10
- npm 6.14.8
- Vue CLI 4.5.4
プロジェクト作成
Vueプロジェクト作成
Vue CLIを利用してVueプロジェクトを作成。Vue 3.x+Typescriptを選択。その他オプションは下記の通り。
>vue create electron-oracle Vue CLI v4.5.4 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, TS, Linter ? Choose a version of Vue.js that you want to start the project with 3.x (Preview) ? Use class-style component syntax? No ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? No ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? (y/N) NoElectron化
VueプラグインからElectron化する。途中でバージョンを聞かれるので
^9.0.0
を選択する。vue add electron-builder動作確認
ここまでで自動生成されたコードの動作確認をする。
Electronアプリケーション上にVueのいつものページが表示されていればOK。npm run electron:servenode-oracledbインストール
ポイント
Electronで利用する場合はElectron独自のパラメータを利用してoracledb
ビルドする必要があるが、npm経由でインストールした場合はそれがされておらず、またリビルドの対象にもならないため使えないらしい。(参考)そのため、ソースからインストールする必要がある。
事前準備
ビルドに必要なライブラリを事前にインストールしておく。
windows-build-tools
Windowsの場合はコンパイラセットとして
windows-build-tools
をインストールする。コンパイラインストール時に管理者権限が必要なので「管理者として実行」したコマンドプロンプトで実行すること。npm install --g --production windows-build-tools(Visual C++ build toolsがうまく入らなかったのでVisual Studio Build Toolsから手動インストールした。)
node-gyp
node-gyp
コマンドが必要になるのでグローバルインストールしておく。npm install -g node-gypインストール後はコマンドとして実行できることが確認できる。
>node-gyp --version v7.1.0インストール
GitHubのソースアーカイブを指定してインストールする。URLはリリースノートを参照して必要なバージョンに適宜変更すること。
npm install --save https://github.com/oracle/node-oracledb/releases/download/v5.0.0/oracledb-src-5.0.0.tgzデータベースアクセス実装
基本的な実装方法は公式のサンプルを参照のこと。
ポイント
node-oracledb
はNode.jsのライブラリなので、ElectronではMainプロセスで実行する必要がある。
すなわち画面操作からキックする場合はIPC通信によりRenderプロセスからMainプロセスに処理をリクエストする必要がある。
(※RenderプロセスでipcRenderer
を利用するのに一工夫が必要。今回はローカルで完結するアプリケーションであったため簡単にnodeIntegration: true
とした。)参考
- 投稿日:2020-09-09T14:42:17+09:00
vue.js css background-image を指定
vue.js で background-image を指定したい。
hoge.vue<div v-if="bg" :style="{ 'background-image': 'url(' + bg + ')' }" style="padding-top: 16%;background: no-repeat center center;background-size: cover;"></div> //略 data () { return { bg:'',これで bg の値が変わるたびに 背景も変化する。
- 投稿日:2020-09-09T14:13:06+09:00
セクション13 vue router
routerの初期設定
npm install vue-router
srcファイルにrouter.jsを作る
main.jsでrouterのインポート登録
router-viewの記述
active-class
exactボタンでurlの移動
this.$router.push('users');動的にurlを操る
コロンをつける
path:'/users/:id'idにアクセスする
{{$route.params.id}}props:true
props:["id"]
で、idだけで表示できるようになるchildrenでrouter-viewをネストすることができる
v-bindで動的にurlを変える
<router-link :to="'/users/'+(Number(id)+1)+'/profiles'">名前月つきルートを使う
```
次{path:"profiles",component:UsersProfiles,name:"users-id-profile"},
```名前をつけると、同じページでいろんなrouter-viewが使える
routes:[ { path:'/',components:{ default:Home, header:HeaderHome }名前つきrouter-viewを使うときはpropsをオブジェクトにする
props:{ default:true, header:false }
- 投稿日:2020-09-09T13:06:36+09:00
npm関連の話
Vue.jsでの開発を行う上で遭遇したエラー等について得た情報のまとめ
目次
- npm ERR! Cannot read property 'match' of undefined
- パッケージのバージョン管理
- バージョンの確認
- npm-check-updatesが便利
- npm audit
- Error: Cannot find module 'webpack-cli/bin/config-yargs'
- compilation.mainTemplate.applyPluginsWaterfall is not a function
npm ERR! Cannot read property 'match' of undefined
npm install
を行った際に遭遇
package-lock.json
とのズレがあると起こるらしいのでpackage-lock.json
を消してやると解決参照ページ
https://qiita.com/mojirico/items/8db742fa5f22e3e719c4
https://www.nekoni.net/Blog/Article/npm-err-cannot-read-property-match-of-undefinedパッケージのバージョン管理
バージョンの確認
通常
terminalnpm list --depth=0 # インストール済みの全てのパッケージ npm outdated # 古くなったパッケージ # 各列の意味 # Current => 現在インストールされているバージョン # Wanted => package.jsonのsemverを満たす最新のバージョン # Latest => 最新バージョンnpm-check-updatesが便利
terminalnpm install -g npm-check-updates # インストール ncu # 現在のバージョンと最新バージョン ncu -u # package.jsonの更新 ncu -a # マイナーバージョン以下アップデートについても更新参照ページ
https://dackdive.hateblo.jp/entry/2016/10/10/095800
npm audit
npm install
時などに脆弱性を警告されたパッケージについての処理
1.npm audit
で脆弱性のあるパッケージを一覧表示
2.npm i [パッケージ名] -D
で修正済みパッケージをインストール
3.npm ls [パッケージ名]
でパッケージの依存関係を確認
4. 上記実行時にdeduped
を表記されているパッケージを削除(FinderでもOK)
5.npm dedupe
で依存関係を整理package.jsonの更新を自動化すればもっと楽らしい
参照ページ
https://qiita.com/hibikikudo/items/0af352acac85fce28ec2
Error: Cannot find module 'webpack-cli/bin/config-yargs'
sass-loader
等を使い始めてからnpm run dev
で吐かれたエラー
webpack
、webpack-cli
、webpack-dev-server
のバージョンの組み合わせの問題らしい
全て最新版をインストールterminalnpm isntall --save-dev webpack@latest # webpack npm install webpack-cli -D # webpack-cli npm isntall --save-dev webpack-dev-server@latest # webpack-dev-server npm install vue-loader@latest # vue-loader参照ページ
https://qiita.com/Shoryu_N/items/9ae2417489c9faaa271c
compilation.mainTemplate.applyPluginsWaterfall is not a function
パッケージの脆弱性を解決すると消えた
参照ページ
https://qiita.com/mitsuya_bauhaus/items/c31b146fb9649469f8d1
npmERR! code ELIFECYCLE
npm run dev
実行時に発生
特定のエラーを指すものではないようなので、続くエラー文を読んで対応するのがいいと思う
一応、node_modules
フォルダを再インストールで解決はするっぽいrm -rf node_modules rm package-lock.json npm install参照ページ
- 投稿日:2020-09-09T11:54:32+09:00
vue-property-decoratorを用いてVueXにTypeScript導入
まずは今回用いる
- VueX
- TypeScript
について簡単に説明します。
VueX
状態管理します。
Global変数のことを指していると自分は理解しています。どのcomponent
からもこのvuexで管理されている
- 値
- メソッド
にアクセスできるようになります。
TypeScript
スーパーJSと自分は理解しています。
javascriptにできることは全てtypescriptで対応できます。
typescriptは画面で用いられる際はjavascriptにコンパイル(変換)
されて利用できるようになります。vue-property-decoratorとは??
自分が新規の案件でvueを用いて開発しようとしたときに用いることになったツールになります。
ツールという表現が正しいかは置いておきます。現在VueXにも型安全を取り込もうとTs
を導入した場合VueX内では簡単に用いさせてくれませんでした。
シンプルいVueとTsはあ仕様が悪いです。Vue.3.0を待ちましょう。。。。
なので
vue-property-decorator
をこの度は用いました。
少しVueの書き方とは異なるclassを用いた書き方のためてこずってしまいましたが慣れてきたので今回紹介させていただきます。
導入
Vue Cli使ってください。
https://qiita.com/nunulk/items/7e20d6741637c3416dcd
この記事を参考に
tsとVueXを用いる部分を参考にしてみてください。
npm install -S vue-class-component npm install -S vue-property-decoratorでdownloadです。
src/store/planディレクトリを作り
planでぃレクトリ配下にplan.ts
types.tsをそれぞれ作ります。
plan | |--plan.ts |--types.tsイメージはこんな形です。
plan.ts
plan.tsの中身は本来VueXで定義している中身を記述します。
plan.tsimport { Module, VuexModule, Mutation, Action, getModule, } from 'vuex-module-decorators'; import store from '../store'; import { Plan, PlanDetail, setPlan } from './types'; @Module({ dynamic: true, store, name: 'PlanModule', namespaced: true }) class PlanModule extends VuexModule { public plan: Plan[] = []; //planのgetterメソッド public get getPlans(): object { return this.plan; } @Mutation public setPlan(payload: setPlan) { console.log(payload); this.plan[payload.planId] = payload.payLoad; } @Action public addPlan(payload: object): void { let planCount = Object.keys(this.plan).length; console.log(planCount + 1, payload); this.setPlan({ planId: planCount + 1, payLoad: payload }); } } export default getModule(PlanModule);@Module({ dynamic: true, store, name: 'PlanModule', namespaced: true })おまじないみたいなものなので覚えましょう。詳細は調べてみてください。
state
VueX内では
stateで定義されていたVueX内のパラメータはplan.tspublic plan: Plan[] = [];に変わっています。
このPlan型はまた記述しますが型を持ったinterfaceになります。なのでこのplan変数の中にグローバルで用いたい値が入ってきます。
getter
getterメソッドもまたVuexとは異なり
plan.ts//planのgetterメソッド public get getPlans(): object { return this.plan; }このような形でgetを頭につけてメソッド名を定義してあげます。
でts導入しているので型を宣言してあげます。慣れてきたでしょうか?
Mutation
plan.ts@Mutation public deletePlan(planId: number) { this.plan.splice(planId, 1); } //stateのplanを変更する処理のみを行うメソッドになります。 //変更する値は基本的にactionから渡してもらいます。@Mutationを記述するだけで簡単にmutationの中身をかけます。
vuexのMutationの説明になりますが
- 基本的にstateを変更するメソッドのみ
- 複雑ななロジックは書かない
- stateを唯一変更することができるメソッドをかける
そういったメソッドを持っています。
なのでもし状態を管理するstateを変更したい場合は
必ずこのmutationを経由する必要があります。Action
plan.ts@Action public addPlan(payload: object): void { let planCount = Object.keys(this.plan).length; this.setPlan({ planId: planCount + 1, payLoad: payload }); } //Actionの記述になります。こちらもMutation同様に@Actionを記述するだけとなります。
- componentから受け取った処理を記述する。
- 非同期処理を行う + state変更は行はない
が特徴のメソッドになります。
state変更は行えますが、行わないというルールがありますので従います。
Actionで変更できるようにしてしまうと、どこが原因でエラーが起きているかなどが追いづらくなります。
stateの変更は決して行わないことに注意です。外部で読み込み可能に
export default getModule(PlanModule);この記述を最後に入れておかないと他のComponentで
読み込むことができなくなりますので注意です。では先ほど作成したModuleを外部から用いていきましょう!
Componentから用いる
PlanListComponent.vue//PlanListComponent.vueというPlanをlistにしたComponentになります。 <template> <div> <v-content v-for="(plan, index) in plans" :key="index"> <v-hover v-slot:default="{ hover }"> <v-card :elevation="hover ? 14 : 2" class="mx-auto pa-3" max-width="344" outlined > <v-card-title> {{ plan.planTitle }} </v-card-title> <v-card-text> {{ plan.issueContent }} </v-card-text> <v-container fluid fill-height> <v-row class="d-flex align-center justify-space-around"> <v-btn>編集</v-btn> <v-btn @click="planDelete(index)">削除</v-btn> </v-row> </v-container> </v-card> </v-hover> </v-content> </div> </template> <script lang="ts"> import { Vue, Component } from 'vue-property-decorator'; import PlanModule from '../../store/plan/plan'; @Component export default class PlanListModule extends Vue { public plans: object = {}; created() { this.plans = this.getPlans; } protected get getPlans() { return PlanModule.getPlans; } planDelete(planId: number) { PlanModule.deletePlan(planId); this.plans = this.getPlans; } } </script>上記のようなファイルを作ってみました。
肝になってくるのは
import PlanModule from '../../store/plan/plan';で先ほど作成した
export default getModule(PlanModule);Moduleをimportしてくる箇所です。
importさえしてしまえばprotected get getPlans() { return PlanModule.getPlans; } planDelete(planId: number) { PlanModule.deletePlan(planId); this.plans = this.getPlans; }Module名.Moduleで定義したメソッド名で
そのModuleのメソッドが使えてしまいます!
これでVueX内も役割ごとに大きく分割できます。
- 投稿日:2020-09-09T10:39:42+09:00
MDBootstrap Vueことはじめ
プロジェクトのクローン
# ユーザーディレクトリ直下にワークスペースを作成 cd && mkdir GitHub && cd GitHub # git cloneする git clone https://github.com/mdbootstrap/Vue-Tutorial-Agenda-App.gitインストールと起動
# 作業ディレクトリに移動 cd ~/GitHub/Vue-Tutorial-Agenda-App/getting-started/start-here # npmがインストールされているかチェック npm -v # 依存関係のインストール npm install # サーバーの立ち上げ npm startアクセスしてみる
Vueプロジェクトの構造について
構造
. ├── License.pdf ├── README.md ├── build ├── config ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── assets │ └── main.js └── static主要な要素
要素 役割 node_modules Vueをビルドするために必要なライブラリー src アプリケーションのソースコード assets 画像やアイコンなどの静的アセットが配置される App.vue ルートコンポーネント(他の全てのコンポーネントがネストされる) main.js App.vueコンポーネントをレンダリングし、DOMにマウントする index.html アプリのメインファイル
- コンポーネントとは、構成要素のこと
App.vueのシングルファイルコンポーネント
- Template
- Scripts
- Styles
=> 詳しくは次の投稿で解説
参考
- 投稿日:2020-09-09T08:00:59+09:00
ゴリゴリのSIerのSEが初めての個人開発で公開まで頑張ってみた過程
ゴリゴリのSIerのSEが個人開発でWebサービスを作ってみた
の続き、みたいな。前回「Webサービスを作ってみた」話を書きました。
書いたやつを見て思ったんですが、ほとんどWebサービスの紹介でSIerの要素があんまり入ってない。
前回の意図としては、Webサービスそのものをアピールするというより「SIerはBPに投げるだけでプログラミングなんてしないよ」なんていう声をたまに聞くので、SIerの経験しかないSEがプログラミングやってWebサービスっぽいものを作るとこんな感じになりますよ、というひとつの実験結果をお見せしたかったのです。それが成功か失敗かは置いといて。
ただ、「こんなの作りました」しか書いてない気がするので、大まかにどんな過程で開発を進めていったかを書きますので、何かの参考になれば…と思います。
ほんと大まかです。
モダンではありません。
読み物的な感じです。
「ポエム」タグです。1.動機づけ
今回は「作りたいもの」が自分の開発のきっかけになりました。
なぞるように一から体系的に学ぶのもいいですが、「作りたいもの」に必要な機能、その機能に必要な技術は何か?って考えながら進めていくと結構時間を忘れてどんどん形になっていきました。
とはいえ「作りたいもの」はそんな簡単に出てこない気もするので、いろんな人に「何か欲しいもの」をひたすら聞くのも良いと思ってます。
それを「作りたいもの」にすればもうあとは手が勝手に動くと思います。2.開発環境
そう思い立って、では何から始めるか…
本番環境をイメージしました。
私はモダンな経験はしていません。
「まぁ最初の個人開発だしサーバーは1台でいいか~、で、Web/APサーバーに Apache Tomcat、DBはMySQLでもいいけど今回は触ったことのないMariaDBの方で!」
みたいな。
あとは言語。
言語は前に書いた通り、未経験のVueと経験のあるJavaでバランスよく学んでいこうという思いでフロントはVue、バックエンドはJava(Spring Boot)にしました。
そしてエディタ。
私はC#とJavaの経験があり、業務で使った経験があるのはVisual StudioとEclipseです。
Visual Studioのライセンスは持ってません。
Eclipseは経験上、重くて起動時にたまにコケてたのが気になります。
よく目にするVS Codeが軽くてJavaにも使いやすそうなのでVS Codeにしました。
ソースのバージョン管理は特にしていません。
コンテナ的なものもありません。3.Javaで開発スタート
まず、ログイン画面から作り始めました。
最初にログイン画面って…あんまりおもしろくないですね。
Spring Bootの機能を利用して実装しました。次にSIerの基本、マスタメンテナンス画面。
SIerが開発を学ぶためにまず最初に作らされるのがマスメン画面というイメージ。
経験があるのでとりえず実装完了。
このときはまだ見た目に何の装飾もしていません。
ヨメに「こんなのできたんだけど」とログイン画面とマスメン画面を見せてみました。
反応は「こんなのに何時間かけてんの?」みたいな反応でした。
機能がどうのこうのというより、見た目のしょぼさのインパクトが強かったみたいです。
これは私のモチベーションが下がったぁぁ
…ということでこの時点になってVueを導入しました、私は、Vue未経験者です。(素のJavaScriptはそれなりに扱ってます)
何かライブラリになってて、ファイルをどこかに置いて参照する感じ?って思ってました。
学習用ならそんな感じでもいいかもしれませんが、Node.js、Vue CLIをインストールし、Vue CLIからプロジェクトを作成すると想像と違うものが出てきました。
単体で動かす感じ…
な私のVueレベル。
※あとで公式を見たら「初心者が vue-cliで始めることは推奨しません」って書いてある…
とりあえず見た目を何とかしたいので業務で扱ったことのあるBootstrapでも入れればいいのかなと思いましたが、調べるとElementというコンポーネントライブララリがVueとセットになってる記事をよくみかけたので、Elementを採用。
Vueの説明の最初らへんで「リアクティブ」って言葉をよく見かけましたが、その言葉に最初はピンときませんでした。
今は「動的に変わる」ってことだと思ってます。4.開発の流れ
業務では仕様書を書いてレビューしてもらって直してまたレビュー…の繰り返しですが、今回はそんな細かくやってません。
SIerとして「要件定義→外部設計→内部設計→実装→テスト色々→リリース」まで一通り経験してるので、頭の中では色々やってたかもしれません。
今回の流れとしては、機能ごとに
・画面イメージのメモ
・画面遷移図のメモ
・DBのテーブル設計のメモ
を作ったくらいです。
しかもそれらは今現在手元にありません。
紛失です。
業務の引継ぎ時は「仕様書はありません。ソース見てください」って伝える必要があります。
画面イメージや画面遷移が変わってもだいたい機能内で閉じてたので影響は少なかったのですが、テーブルの項目が変わると他の機能への影響が大きかったり色々面倒臭かったので、そっちはもう少しちゃんと考えてたほうがよかったな…と今は思ってます。5.いきなりAPI
さて、Node.jsとTomcatという二つの実行環境ができました。
今さらですがここらへんでバックエンドをREST API化するイメージが固まりました。
開発時はJavaのプロジェクトにVueのプロジェクトを突っ込んで、Node.jsとTomcat両方立ち上げてました。
本番環境ではビルドしたVueのファイルがwarファイルに含まれるようにして、全部Tomcatに乗せました。
※APIのURLの先頭を/api/… にしないとVue側とURLがかぶってしまう問題が発生したのは後のこと…6.Vue + Java(Spring Boot)で開発スタート
ログイン画面とマスメン画面をVue + Spring Boot(REST API)で作り直し。
ここら辺は探すと色々やり方が出てくるのでそこまで詰まることはなかったです。バリデーションには最初Elementを使ってましたが、サーバーサイドのエラーを扱おうとしたとき上手く使えなかったので、VeeValidateに切り替えました。
VeeValidateでなんとかやってます。実装の流れはだいたいルーティーン化していました。
画面作成(Vue)→テーブル作成(DB)→リポジトリクラス作成(Java)→サービスクラス作成(Java)→コントローラークラス作成(Java)→REST APIアクセス部分作成(Vue)→画面調整(Vue)
これを機能ごとに繰り返す感じです。ちなみに私のSIerとしての経験的に、ちょっとデザイナーと仕事をしたことがあるくらいで私にはデザインの知見がほとんどありません。なのでデザインに関しては何とも言えない仕上がりになっています。
7.その他各機能の作成
各機能の作成は経験と世にあふれてるサービスを参考にしました。
排他制御は細かくやりました…
あと、世にあふれてるサービスを参考にしなくても、チャットなんかは実装方法を教えてくれてるサイトがたくさんありました。
ただシンプルなチャットが多いので、メンバーがオンラインかとか削除機能とかアイコンの表示とかは自力で考えました。チャットのメッセージを削除する機能をあとから実装しようとしたら、テーブルの構造上消せないということが判明しました。
その時点でチャットに関するテーブルの構造を結構見直したので、影響範囲が大きかったです。
メッセージの削除はあとでいいかな~と思ってましたが、テーブルの構造はある程度そこも考慮に入れるべきだったな~と思ったりもしました。ちょくちょくヨメに見せてましたが、けっこう辛辣なことを言ってくれました。
特にデザインと操作性ですね。
そこまで言う?くらい。
まあユーザーにとって大事なのはそこなんですよね。
ヨメの身も蓋もない指摘でダメージを受けつつ良くなった部分もあるので感謝です。8.迫りくるネガティブ
開発中、ときどきあいつはやってきます。
「こんなサービス誰が使うのか…?」という蠢き。
それは大きな影となり、視界を闇で包みます。
レビュー「クソサービスですね」
レビュー「使えない」
レビュー「バグ多すぎ」
頭の中をマイナスの評価が駆け巡ります。
そして手を止めて、すべてを捨て去りたくなります。
そうやって途中で止めて放置状態になった作りかけのアプリは至る所で眠っているでしょう。こういうときは本来ユーザー目線でやりがいを取り戻すべきなのかもしれませんが、私はプログラミングの楽しさに逃げました。
で、気持ちが落ち着いてきたらまたユーザー目線に戻ります。
それの繰り返しでなんとかモチベーションを保っていました。9.ちょっと苦労したユーザー間で同期するタスク管理
チャットみたいにWebSocketでユーザー同士の画面を同期させる機能をタスク管理にもつけてみようかな~と思い、Vue.Draggable + WebSocket で実現しようと思ったのですが、一つ微妙に、いやかなり気になる現象が発生しました。
Vue.Draggable の奇妙な動きを対症療法でなんとかする
動きが微妙なのです。
結局丸2日くらい悩んで対症療法で何とかしました。10.公開準備
サーバーはAWS EC2 を利用しました。
最初は無料枠のインスタンスを利用していましたが、メモリが少なすぎてパフォーマンスに影響が出たので、有料でも少しスペックのいいものにしました。
勉強代、勉強代…
ここにDBとWeb/APサーバーをセットアップして、ビルドしたモジュールを乗せるだけ。一通り機能を作り終えたら、公開に必要なドメイン取得、HTTPS化にとりかかりました。
何か大変なんだろうな~と思っていましたが、AWSでドメイン取得、HTTPS化はあっさり完結しました。
.comドメインは年1,000円くらいかかるみたいですが…
無料より手軽さを優先しました。準備が整ったら、あとは告知するのみ。
今回は自分がアカウントを持ってるSNSで告知しました。
このボタンを押せば告知…って思うとなかなかの指プルプル状態でした。11.公開後
さほど変わりはありません。
辛辣なコメントをいただき沈むこともありますが…
利用してもらうのはなかなか難しいと思ってます。
今後、どうすべきかあまり決まっていません。
公開してからが一番大事な気がしますが。12.最後に
開発するぞ!と決めてから公開するまで大まかにこんな感じです。
技術的な要素はほとんどありませんが、ポエムということで。
やってて思ったのは、「あ~これ絶対に解決しなさそう!」って思っても長くても一週間以内にはなんとかなるということです。
意外に解決します。
ベタですがお風呂とかトイレの中で思いついたり。やってて「こんなサービス誰か使うのか…?」という疑問は常に付きまといます。
実際誰も使わない気もします。
でもやっぱり一回公開まで経験することは大事だと思います。
ダメならまた作ればいいだけですし。
私は心臓が剛毛なメンタル強者ではないですが、へこみつつも何とか前に進む気はあります。
なのでこれまで一度も公開用のアプリを作ったことの無い方も、一度作ってみてはどうでしょうか。
- 投稿日:2020-09-09T05:35:10+09:00
vue.js コンポーネントの書き方
Vue cliを使わないcdn版でのコンポーネントの書き方です。
いくつか書き方があり迷うので自分メモ的に投稿致します。
大きくわけてグローバル登録とローカル登録があります。コンポーネントの書き方(グローバル登録)
コンポーネント名はHTMLタグになるもの
テンプレート名は直接HTMLタグを書くか、HTML内に記述したx-templateの対応するidを設定//コンポーネント1 Vue.component('コンポーネント名A', { template: 'HTMLタグを記述、もしくはテンプレートのid', data: function() { return { number: 12 } } }) //コンポーネント2 Vue.component('コンポーネント名B', { template: 'HTMLタグを記述、もしくはテンプレートのid', data: function() { return { msg: 'hello!' } } }) //HTML内で表示したいブロック new Vue({ el: '#app' }) new Vue({ el: '#app2' })グローバルなので#app、#app2どちらのブロックでもすべてのコンポーネント名がHTMLタグとして使用できます。
<div id="app"> <コンポーネント名A></コンポーネント名A> </div> <div id="app2"> <コンポーネント名A></コンポーネント名A> <コンポーネント名B></コンポーネント名B> </div>コンポーネントの書き方(ローカル登録) 推奨
定義したコンポーネントの定数名を、new Vue内で使いたいel:に使いたいタグ名で登録する
//コンポーネントを定義 const 定数名 = { template: 'HTMLタグを記述、もしくはテンプレートのid', data: function() { return { msg: 'キーワードを入力してください', } } } new Vue({ el: 'HTML内の使いたいブロックをCSSセレクタで記述', components: { //上のelでマウントしたHTML内のブロックに //下の 'HTMLタグ名':定数名 を使います宣言 'search-component': Search } })[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option. - did you register the component correctly? For recursive components, make sure to provide the "name" option.
というエラーを吐かれたときはコンポート名が間違っていないか確認してください。
まとめ
基本的にローカル登録を推奨
多くの場合、グローバル登録は理想的ではありません。例えば Webpack のようなビルドシステムを利用しているときに、グローバルに登録した全てのコンポーネントは、たとえ使用しなくなっても、依然として最終ビルドに含まれてしまうことでしょう。これは、ユーザがダウンロードしなくてはならない JavaScript のファイルサイズを不要に増加させてしまいます。
このような場合に、コンポーネントを素の JavaScript オブジェクトとして定義することができます。ローカル登録手順まとめ
- constでコンポーネントを定義
- templateを作成(HTML内にx-templateかコンポーネントのtemplate:に直接記述)
※vue cli で使える.vueファイルだとファイル毎にコンポーネントをまとめて書くやり方が使える- template:でテンプレートを定義(直接記述でない場合x-templateのidを指定する)
- data、methodsなどオプションを定義
※dataはコンポーネント側に記述する(new Vueの方にdataを記述した場合反映されない感じ?)- new Vue で使いたいブロックをel:に、使いたいコンポーネントをcomponents:に
- el:複数登録不可、components:は複数登録可能
- components:に登録したコンポーネントだけがそのel:内で使える
- 投稿日:2020-09-09T03:01:35+09:00
Vue.js で TypeScriptを使う
vue-cli
vue-cli は vue.js のプロジェクトを準備するとき等に利用するツールです。
vue-cli でプロジェクトを作りましょう。vue-cli を利用するには node.js をインストールして npm を利用して vue-cli をインストールします。
npm install -g @vue/cliインストールが終わったら早速 vue-cli のプロジェクトテンプレートを利用してプロジェクトを作りましょう。
プロジェクトは vue create コマンドで作成します。
コマンドは vue create <project-name> で指定します。vue create vue-ts-practice起動するとプリセット選択に移ります。
Typescript を利用するために Manually select features を選択します。Vue CLI v4.5.4 ? Please pick a preset: (Use arrow keys) > Default ([Vue 2] babel, eslint) Default (Vue 3 Preview) ([Vue 3] babel, eslint) Manually select featuresとりあえず、全部チェックしておきます。
Vue CLI v4.5.4 ? 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) >(*) Choose Vue version (*) Babel (*) TypeScript (*) Progressive Web App (PWA) Support (*) Router (*) Vuex (*) CSS Pre-processors (*) Linter / Formatter (*) Unit Testing (*) E2E TestingVue.jsのversionを聞かれるので3.x (Preview)を選択します。
Vue CLI v4.5.4 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Lint er, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 2.x > 3.x (Preview)以降設定について聞かれるので お好みで設定したら、プロジェクト作成が始まるので完了するまで待ちます。
完了すると以下のような画面になると思います。
� Successfully created project vue-ts-practice. � Get started with the following commands: $ cd vue-ts-practice $ npm run serve記述されているように
cd <プロジェクト名> npm run serveと実行すると構築されたプロジェクトが起動されます。
DONE Compiled successfully in 23867ms App running at: - Local: http://localhost:8080/ - Network: http://172.16.0.66:8080/ Note that the development build is not optimized. To create a production build, run npm run build. No issues found.表示されているアドレス(http://localhost:8080) にブラウザで接続してみると Vue.js のウェルカムページに遷移します。
このプロジェクトを利用して Typescript で Vue.js を書いていきます。