- 投稿日:2020-12-27T23:15:49+09:00
ページネーション【Vue.js/Vuetify】
概要 ・ ポートフォリオでページネーション機能を実装したので、コメントつきのソースコードを紹介 ・ 使用した技術はRealtimeDatabase(Firebase)とVuetify(Vue.js) ※ v-pagenation のページは https://vuetifyjs.com/ja/components/paginations/ ・ api経由でデータを取得し、ページネーション付きで表示する ・ 開発環境はVue-Cli template <v-layout> <v-flex> <v-pagination v-model="currentPage" :length="getPageCount"> </v-pagination> </v-flex> </v-layout> <v-layout v-for="list in getLists" :key="list.message"> //以下省略 </v-layout> :length は画面に表示できる最大限のページ数のこと。 script data(){ return { input: '', parPage:3, //1ページごとに表示されるリスト数 currentPage:1 //画面を開いた時に最初にあなたがいるページの場所 } }, computed(){ lists(){// 表示するリストのデータ return this.$store.state.lists }, getLists(){// 表示するリストを1ページ3つにする let current = this.currentPage * this.parPage //全ページlistの合計数 let start = current - this.parPage //1ページ目のlistの数 return this.lists.slice(start, current) //リストの何番目〜何番目を今のページに表示するか }, getPageCount(){ //引数として与えた数以上の最小の整数を返す //ページ数になって、上の:lengthに当てはめる return Math.ceil(this.lists.length / this.parPage) } }, watch:{ search(){//1ページ目以外のページにいる状態で検索欄に文字入力すると、1ページ目に戻って検索 this.currentPage = 1 } }
- 投稿日:2020-12-27T23:14:45+09:00
リアルタイム検索【Vue.js/Vuetify/Vuex】
概要 ・ ポートフォリオでリアルタイム検索機能を実装したので、コメントつきのソースコードを紹介 ・ 使用した技術はVue.js,Vuetify,Vuex ※ v-text-field のページは以下URL内にあり。 https://vuetifyjs.com/en/components/text-fields/#api ・ api経由でデータを取得し、ページネーション付きで表示する ・ 開発環境はVue-Cli template <v-layout> <v-flex> //入力フォーム <v-text-field label="検索する" v-model="search"> </v-text-field> </v-flex> </v-layout> <v-layout v-for="list in getLists" :key="list.index"> //以下にcomputedの「getLists」がループされて表示される </v-layout> computed内では、stateから取得したリストをgetListsで自分が入力した内容とマッチするリストになるようにフィルタリング。 フィルタリングしたリストをv-forループで表示させる。 script data(){ return : { //上記入力フォームの初期値 search: " } }, computed(){ //stateの配列listsの中のオブジェクトから、キーtitleがv-modelで入力したsearchと一致するものだけ表示 getLists(){ const lists = this.$store.state.lists return lists.filter((list) => { return list.title.match(this.search) }) } } store(state) lists: [ { id: "akdddgela22nad", title: "FreeTalk in NewYork", date: "2017-09-29", location: "New York"} { id: "akdbbraa5ffggg", title: "FreeTalk in Paris", date: "2017-10-20", location: "Paris" } //以下省略... ], 下記のように" || "を使用すれば、リストの中のあらゆるワードや数字を拾って検索も可能になる。 script return list.title.match(this.search) || list.date.match(this.search) || list.location.match(this.search)
- 投稿日:2020-12-27T23:13:40+09:00
SPA作成の雛形【Vue.js/Vuetify】
概要 ・ Vue.js/VuetifyでSPAを作成時にこの雛形から要素を付け足していくことにすればスムーズにSPAが作成できるかと思い投稿 ・ 使用した技術はVuetify ・ 開発環境はVue-Cli App.vue <template> <v-app> //左に出てくるナビゲーションドローワー <v-navigation-drawer app v-model="drawer" temporary> <v-list-item> <v-list-item-content> <v-avatar> <img src="photoURL"> </v-avatar> </v-list-item-content> <v-list-item-content> <v-list-item-title>ユーザネーム</v-list-item-title> </v-list-item-content> </v-list-item> <v-divider></v-divider> <v-list-item v-for="item in menuItems" :key="item.title" :to="item.link"> <v-list-item-icon> <v-icon>{{ item.icon }}</v-icon> </v-list-item-icon> {{ item.title }} </v-list-item> </v-navigation-drawer> //画面の上に表示するナビゲーションバー <v-app-bar app> <v-app-bar-nav-icon @click.stop="drawer = !drawer"> </v-app-bar-nav-icon> <v-toolbar-title> <router-link to="/" tag="span" style="cursor: pointer">アプリケーション</router-link> </v-toolbar-title> <v-spacer></v-spacer> <v-toolbar-items class="hidden-xs-only"> <v-btn text v-for="item in menuItems" :key="item.title" :to="item.link"> <v-icon medium left>{{ item.icon }}</v-icon> {{ item.title }} </v-btn> </v-toolbar-items> </v-app-bar> //routerの画面の表示場所 <v-main> <router-view/> </v-main> </v-app> </template> <script> export default { name: 'app', data: () => ({ drawer : false }), computed: { menuItems(){ let menuItems = [ {icon: "mdi-login", title:"ログイン", link:"/login"}, {icon: "mdi-account-multiple", title:"アイテムを見る", link:"/items"}, {icon: "mdi-google-maps", title:"アイテムを投稿", link:"/item/new"} //以下省略... ] return menuItems } }; </script> ■Vuetifyコンポーネントは下記を使用。バージョンによって変化するので注意が必要。 ・ナビゲーションドローワー: v-navigation-drawer 参考:https://vuetifyjs.com/ja/components/navigation-drawers/ ・ナビデーションバー: v-app-bar 参考:https://vuetifyjs.com/ja/components/app-bars/ ■menuItemsとして配列にアイテムを保存してv-forループで表示。 ■class="hidden-xs-only" : 画面がXSサイズ(スマホサイズ)で見るときにだけバーのメニューが消える。 参考:https://vuetifyjs.com/ja/styles/display/#visibility ■v-mainの中に遷移していく画面であるrouter-viewを入れる。router-viewのところに、router/index.jsの画面が遷移していく。 router/index.js import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../components/Home.vue' import CreateFreeTalk from '../components/Item/CreateItemc.vue' //以下省略... Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/item/new', name: 'CreateItem', component: CreateItem }, //以下省略... ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
- 投稿日:2020-12-27T23:12:31+09:00
MailAddressとPasswordによるユーザー新規登録/認証【Vue.js/Vuetify/Vuex/Firebase】
概要 ・ ポートフォリオでメールとパスワードでユーザー新規登録/認証機能を実装したので、コメントつきのソースコードを紹介 ・ 使用した技術はRealtimeDatabase(Firebase)・Vuetify・Vue.js・Vuex ・ 開発環境はVue-Cli signup.vue <template> <div> <h1>新規登録</h1> <v-divider></v-divider> //下記の「type="submit"」のクリックにより、下記に入力したemailとpasswordを引数としてonSignupメソッドが発動 <form @submit.prevent="onSignup"> <v-layout> <v-flex> <v-text-field name="email" label="Mail" id="email" v-model="email" type="email" required> </v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> <v-text-field name="password" label="Password" id="password" v-model="password" type="password" required> </v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> //クリックすると<form></form>間に入力した情報が提出(submit)される <v-btn type="submit"> </v-btn> </v-flex> </v-layout> </form> </div> </template> <script> export default { data(){ return{ //入力したメールアドレス email: "", //入力したパスワード password: "" } }, computed: { //あなたのユーザー情報を取得 user(){ return this.$store.getters.user } }, watch: { //あなたのユーザー新規登録処理が成功したらホーム画面へ遷移する user(value){ if(value !== null && value !== undefined){ this.$route.push("/") } } }, methods: { //v-modelで入力したemailとpasswordを引数にしてactionsの"signUserUp"へデータを渡す onSignup(){ this.$store.dispatch("signUserUp", {email: this.email, password: this.password}) } } } </script> store state: { //あなたのユーザー情報のstate。ログインするとユーザー情報のオブジェクトがnullに入る user: null }, mutations: { //stateのuserをactionsのユーザーオブジェクトにする。またはnullに戻す setLoginUser(state, payload){ state.user = payload } }, actions: { signUserUp({commit}, payload){ //dispatchで引数にしたemailとpasswordを使って、firebaseのAuthenticationsにユーザーアカウントが作成される。 firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password) .then( user => { //登録済みユーザーオブジェクト const newUser = { id: user.uid } //mutationsへ登録済みユーザーオブジェクトを渡す commit("setLoginUser", newUser) }) .catch( error => { console.log(error) }) } }, getters: { //stateのユーザーオブジェクトをgettersで取得 user(state){ return state.user } } ユーザー新規登録の大まかな処理フロー ① v-modelのアドレスとパスワードを入力し、引数としてonSignupメソッドが動き、actionsのsignUserUpが動く。 ② actionsでのcreateUserWithEmailAndPasswordにてFirebaseのAuthenticationsにアドレスとパスワードを新規登録。登録成功したら、そのユーザーオブジェクトをmutationsへ渡す。 ※ Promise(.then/.catch)を付けないと、ユーザーのアドレスとパスワードがAuthenticationsに登録される前にuser情報がnullのままmuationsへ処理が進んでエラーになるので、Promiseは忘れないように。 Promiseについては、下記の記事がわかりやすく、参考にさせていただきました。 https://qiita.com/saka212/items/9b6cfe06b464580c2ee6 ③ mutationsによって、stateでnullになっているuserにmutationsのユーザーオブジェクトを上書きする。 ④ signup.vue にてgettersでstateのユーザーオブジェクトを引っ張ってきて、watchにて「gettersのuserにユーザーオブジェクトが入ってきてユーザー新規登録が完了したら、ホーム画面に戻る」 ように監視する。 ⑤ 新規ユーザー登録完了した後 、ホーム画面に戻ることで完了 では次に新規登録したユーザー情報のメールアドレスとパスワードでログインするフローについて。 signin.vue <template> <div> <h1>ログイン画面</h1> //下記の「type="submit"」のクリックにより、下記に入力したemailとpasswordを引数としてonSigninメソッドが発動 <form @submit.prevent="onSignin"> <v-layout> <v-flex xs12> <v-text-field name="email" label="Mail" id="email" v-model="email" type="email" required> </v-text-field> </v-flex> </v-layout> <v-layout> <v-flex xs12> <v-text-field name="password" label="Password" id="password" v-model="password" type="password" required></v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> //クリックすると<form></form>間に入力した情報が提出(submit)される <v-btn type="submit"> ログインボタン </v-btn> </v-flex> </v-layout> </form> </div> </template> <script> export default { data(){ return{ //入力したメールアドレス email: "", //入力したパスワード password: "" } }, computed: { //あなたのユーザー情報を取得 user(){ return this.$store.getters.user } }, watch: { //あなたのユーザーログイン処理が成功したらホーム画面へ遷移する user(value){ if(value !== null && value !== undefined){ this.$route.push("/") } } }, methods: { //v-modelで入力したemailとpasswordを引数にしてactionsの"signUserIn"へデータを渡す onSignin(){ this.$store.dispatch("signUserIn", {email: this.email, password: this.password}) } } } </script> store.js state: { //あなたのユーザー情報のstate。ログインするとユーザー情報のオブジェクトがnullに入る user: null }, mutations: { //stateのuserをactionsのユーザーオブジェクトにする。またはnullに戻す setLoginUser(state, payload){ state.user = payload } }, actions: { signUserIn({commit}, payload){ //dispatchで引数にしたemailとpasswordを使って、firebaseのAuthenticationsにて認証 firebase.auth().signInWithEmailAndPassword(payload.email, payload.password) .then( //ユーザーのオブジェクト user => { const newUser = { id: user.uid } //mutationsへログインするユーザーオブジェクトを渡す commit("setLoginUser", newUser) }) .catch( error =>{ console.log(error) }) }, } ユーザー認証処理のフロー: 新規登録処理とほぼ同じ流れ ① v-modelのアドレスとパスワードを入力して引数としてonSigninメソッドが動き、actionsのsignUserInが動く。 ② actionsでのsignInWithEmailAndPasswordにてFirebaseのAuthenticationsにアドレスとパスワードを認証。認証成功したら、そのユーザーオブジェクトをmutationsへ渡す。 ③ stateでnullになっているuserにmutationsのユーザーオブジェクトを上書きする。 ④ signin.vue にてgettersでstateのユーザーオブジェクトを引っ張ってきて、watchにて「gettersのuserにユーザーオブジェクト入りユーザー認証が完了したら、ホーム画面に遷移する」 ように監視する。 ⑤ ユーザー認証が完了し、ホーム画面に戻ることで完了 最後に 今回は自分なりに書きやすいPromiseでコードを書きましたが、async/awaiteもそろそろ使用してコードを書くことにもチャレンジしていこうかと思います。 できるだけ端的にまとめましたが、もし上記のフローでの理解に誤りがあったり、より良い表現などあればコメントいただければ幸いです。
- 投稿日:2020-12-27T22:52:32+09:00
JSXを使ってラジオボタンの設定をシンプルにする
始めに
Vue.jsでラジオボタンの設定をする時は以下のように書くと思いますが、毎回v-modelの設定をするのが面倒だと感じたことはないでしょうか?
ラジオボタンの設定<template lang="pug"> div label input(v-model="$data.value", type="radio", value="A") | A label input(v-model="$data.value", type="radio", value="B") | B </template>これを以下のようにselectと同じように親だけv-modelを設定するだけで済むようなコンポーネントを作ることができますので、そのやり方を紹介したいと思います。
selectと同じような設定方法<template lang="pug"> div //- 親コンポーネントだけv-modelを設定する RadioButtonGroup(v-model="$data.value") RadioButton(value="A") A RadioButton(value="B") B </template>実装方法
タイトルにも書いてありますが、JSXを使用します。JSXを使用することで子コンポーネントに対してプロパティを注入することができるので、
RadioButton
コンポーネントを探してv-model
のプロパティを注入する形になります(正確にはv-modelの対象となるprops名を入れます)。
vnodeの操作についてはvee-validateのコードを参考にしました。
- https://github.com/logaretm/vee-validate/blob/bf5a3707538c97d77ae0b4c48cdc6ee9a0ac2b7a/src/components/provider.js#L328
- https://github.com/logaretm/vee-validate/blob/bf5a370753/src/utils/vnode.js#L34
またvnodeのプロパティの注入はこちらを参考にしました。
JSXで必要なプロパティ・イベントを注入するconst RADIO_BUTTON_NAME = "RadioButton"; /** * リスナーオブジェクトにリスナーを追加する * @param {Object} listeners - リスナーオブジェクト * @param {string} eventName - イベント名 * @param {function} listener - コールバック関数 */ function _addListener(listeners, eventName, listener) { // リスナーが未登録の場合は登録して終了 if (!listeners[eventName]) { listeners[eventName] = [listener]; return; } // 既に単体でリスナーが登録されている時は配列形式にする if (typeof listeners[eventName] === "function") { listeners[eventName] = [listeners[eventName]]; } // 配列形式のリスナーは単純に追加する listeners[eventName].push(listener); } /** * vnodeにリスナーを追加する * @param {Object} vnode - vnode * @param {string} eventName - イベント名 * @param {function} listener - コールバック関数 */ function addListener(vnode, eventName, listener) { // リスナーのプロパティ自体がない時は初期化する if (!vnode.componentOptions.listeners) { vnode.componentOptions.listeners = {}; } _addListener(vnode.componentOptions.listeners, eventName, listener); } /** * componentNameにマッチするvnodeにapplyFuncを適応させる * @param {Array} vnodes - vnodeリスト * @param {string} componentName - コンポーネント名 * @param {function} applyFunc - マッチしたvnodeに対しての処理 */ function applyMatchedNodes(vnodes, componentName, applyFunc) { const regex = new RegExp(`${componentName}$`); for (let i = 0; i < vnodes.length; i++) { const vnode = vnodes[i]; if (regex.test(vnode.tag)) { applyFunc(vnode); } // 子供がある場合は再帰する if (vnode.children) { applyMatchedNodes(vnode.children, componentName, applyFunc); } } } export default { name: 'RadioButtonGroup', model: { prop: "selectedValue", event: "select", }, props: { selectedValue: { type: String }, }, render() { const vnodes = this.$slots.default; // ラジオボタンのコンポーネント全てにプロパティを注入する applyMatchedNodes(vnodes, RADIO_BUTTON_NAME, (vnode) => { if (!vnode.componentOptions || !vnode.componentOptions.propsData) { return; } // 注入するパラメータを入れる(v-modelの対象となるprops名をselectedValueにしているため、その値を入れる) vnode.componentOptions.propsData.selectedValue = this.$props.selectedValue; // リスナーを設定する addListener(vnode, "select", (value) => { this.$emit("select", value); }); }); return <div>{vnodes}</div>; }, };
v-model
の値を注入する処理は子孫まで見てくれるため、以下のようにスタイル調整のためにdivが入ってもきちんと値の連動はしてくれます。子孫でもv-modelの連携はできる<template lang="pug"> div RadioButtonGroup(v-model="$data.value") .list .list__item //- 途中divタグが入っているが、きちんとv-modelが注入されている RadioButton(value="A") A .list__item RadioButton(value="B") B .list__item RadioButton(value="C") C </template> <style lang="scss" scoped> .list { display: flex; &__item { width: 50px; } } </style>終わりに
以上がJSXを使ってラジオボタンの設定をシンプルにする方法でした。JSXはVue.jsでは普段使わないものですが、一部では使うと書きやすくなることがあるため、これを機会に使ってみるのはいかがでしょうか。
サンプルはCodeSandboxに書きましたので、興味がある方は是非見てください。https://codesandbox.io/s/jsxwoshituteraziobotannoshedingwosinpurunisuru-s0xz5?file=/src/App.vue
- 投稿日:2020-12-27T22:18:09+09:00
MailAddressとPasswordによるユーザー新規登録【Vue.js/Vuetify/Vuex】
概要
・ ポートフォリオでメールでユーザー新規登録機能を実装したので、コメントつきのソースコードを紹介
・ 使用した技術はRealtimeDatabase(Firebase)・Vuetify・Vue.js・Vuex
・ 開発環境はVue-Clisignup.vue<template> <v-container> //v-layoutなど省略 <h1>新規登録</h1> <v-divider></v-divider> <form @submit.prevent="onSignup"> <v-layout> <v-flex> <v-text-field name="email" label="Mail" id="email" v-model="email" type="email" required></v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> <v-text-field name="password" label="Password" id="password" v-model="password" type="password" required></v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> <v-btn type="submit">//クリックすると<form></form>間に入力した情報が提出(submit)される </v-btn> </v-flex> </v-layout> </form> </v-container> </template> <script> export default { data(){ return{ email: "", password: "" } }, computed: { user(){ return this.$store.getters.user } }, watch: { user(value){//signup成功したらホーム画面へ if(value !== null && value !== undefined){ this.$route.push("/") } } }, methods: { onSignup(){ this.$store.dispatch("signUserUp", {email: this.email, password: this.password}) } } } </script>storestate: { user: null }, mutations: { setLoginUser(state, payload){ state.user = payload } }, actions: { signUserUp({commit}, payload){ firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password) .then( user => { const newUser = { id: user.uid } commit("setLoginUser", newUser) }) .catch( error => { console.log(error) }) } }, getters: { user(state){ return state.user } }大まかな処理フロー
① v-modelのアドレスとパスワードを入力して引数としてonSignupメソッドが動き、store内のsignUserUpが動く。
② actionsでのcreateUserWithEmailAndPasswordにてFirebaseのAuthenticationsにアドレスとパスワードを登録。登録成功したら、そのユーザーIDをmutationsへ渡す。
③ mutationsによって、stateでnullになっているuserにsignUpしてきたユーザー情報(オブジェクト)を上書きする。
④ signup.vue にてgettersでstateのユーザー情報(オブジェクト)を引っ張ってきて、watchにて「stateのuser情報が入ってきてユーザー新規登録が完了したら、ホーム画面に戻る」 ように監視する。
⑤ 新規ユーザー登録完了し、ホーム画面に戻ることで完了
- 投稿日:2020-12-27T22:18:09+09:00
MailAddressとPasswordによるユーザー新規登録【Vue.js/Vuetify/Vuex/Firebase】
概要
・ ポートフォリオでメールでユーザー新規登録機能を実装したので、コメントつきのソースコードを紹介
・ 使用した技術はRealtimeDatabase(Firebase)・Vuetify・Vue.js・Vuex
・ 開発環境はVue-Clisignup.vue<template> <v-container> //v-layoutなど省略 <h1>新規登録</h1> <v-divider></v-divider> <form @submit.prevent="onSignup"> <v-layout> <v-flex> <v-text-field name="email" label="Mail" id="email" v-model="email" type="email" required></v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> <v-text-field name="password" label="Password" id="password" v-model="password" type="password" required></v-text-field> </v-flex> </v-layout> <v-layout> <v-flex> <v-btn type="submit">//クリックすると<form></form>間に入力した情報が提出(submit)される </v-btn> </v-flex> </v-layout> </form> </v-container> </template> <script> export default { data(){ return{ email: "", password: "" } }, computed: { user(){ return this.$store.getters.user } }, watch: { user(value){//signup成功したらホーム画面へ if(value !== null && value !== undefined){ this.$route.push("/") } } }, methods: { onSignup(){ this.$store.dispatch("signUserUp", {email: this.email, password: this.password}) } } } </script>storestate: { user: null }, mutations: { setLoginUser(state, payload){ state.user = payload } }, actions: { signUserUp({commit}, payload){ firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password) .then( user => { const newUser = { id: user.uid } commit("setLoginUser", newUser) }) .catch( error => { console.log(error) }) } }, getters: { user(state){ return state.user } }大まかな処理フロー
① v-modelのアドレスとパスワードを入力して引数としてonSignupメソッドが動き、store内のsignUserUpが動く。
② actionsでのcreateUserWithEmailAndPasswordにてFirebaseのAuthenticationsにアドレスとパスワードを登録。登録成功したら、そのユーザーIDをmutationsへ渡す。
※ Promise(.then/.catch)を付けないと、ユーザーのアドレスとパスワードがAuthenticationsに登録される前にuser情報がnullのままmuationsへ処理が進んでエラーになるので、Promiseは忘れないように。 Promiseについては、下記の記事がわかりやすく、参考にさせていただきました。
https://qiita.com/saka212/items/9b6cfe06b464580c2ee6③ mutationsによって、stateでnullになっているuserにsignUpしてきたユーザー情報(オブジェクト)を上書きする。
④ signup.vue にてgettersでstateのユーザー情報(オブジェクト)を引っ張ってきて、watchにて「stateのuser情報が入ってきてユーザー新規登録が完了したら、ホーム画面に戻る」 ように監視する。
⑤ 新規ユーザー登録完了し、ホーム画面に戻ることで完了
最後に
今回は自分なりに書きやすいPromiseでコードを書きましたが、async/awaiteもそろそろ使用してコードを書くことにもチャレンジしていこうかと思います。
できるだけ端的にまとめましたが、もし上記のフローでの理解に誤りがあったり、より良い表現などあればコメントいただければ幸いです。
- 投稿日:2020-12-27T19:33:45+09:00
VSCodeでVue + ESLint + Prettierの環境構築するメモ
概要
VSCodeで、Vue + ESLint + Prettierを導入し、vueファイルやjsファイルの保存時に、自動的にフォーマットがかかるような環境を整えようとしたが、ちゃんと動くまでに時間がかかったのでメモしておく。
(初心者のため間違い等あればご指摘願います。。)試した環境
- macOS Catalina (10.15.7)
- VSCode (1.52.1)
手順
1. Vueプロジェクトの作成
- vue cliをインストール
npm install -g @vue/cli
- プロジェクト作成(途中でvue 2か3かを聞かれるが、2にしておく。)
vue create (プロジェクト名)
2. ESlint, Prettier関連の設定
(https://www.npmjs.com/package/eslint-plugin-prettier-vue を参考にしたら比較的簡単にいった。)
上で作成したプロジェクトのルートディレクトリで、以下を実行
yarn add -D eslint-plugin-prettier-vue eslint-plugin-vue eslint-config-prettier eslint prettier
プロジェクト作成時に自動で作成された、ルートディレクトリにある
.eslintrc.js
を、以下のものに置き換える。なお、rulesのセクションで、色々とセミコロンとかクォーテーションの設定等をしているが、ここは好みのものにする。.eslintrc.jsmodule.exports = { extends: ['plugin:vue/recommended', 'plugin:prettier-vue/recommended', 'prettier/vue'], settings: { 'prettier-vue': { SFCBlocks: { template: true, script: true, style: true, customBlocks: { docs: { lang: 'markdown' }, config: { lang: 'json' }, module: { lang: 'js' }, comments: false, }, }, usePrettierrc: true, fileInfoOptions: { withNodeModules: false, }, }, }, rules: { 'prettier-vue/prettier': [ 'error', { printWidth: 100, singleQuote: true, semi: false, trailingComma: 'es5', }, ], }, }
- 以下のような
.prettierrc.js
をプロジェクトのルートディレクトリに作成。このファイルに書く設定は、.eslintrc.js
の、rulesのセクションに書いたものと必ず合わせる。.prettierrc.jsmodule.exports = { printWidth: 100, singleQuote: true, semi: false, trailingComma: 'es5', }
- プロジェクトの作成時に自動で作成された、
package.json
内のeslintConfig
セクションは、不要と思われるので削除しておく。3. VSCodeの準備
以下のextensionを導入する。(Veturは入れない)
- ESlint
- Prettier
- vue
ファイル保存時に自動的にprettierでフォーマットしてくれるように、プロジェクトのルートディレクトリに
.vscode
ディレクトリを作成し、その配下に、以下のようなsettings.json
を作成。.vscode/settings.json{ "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, }
- VSCodeを再起動する。
4. 適当にjsファイルかvueファイルをVSCodeで書いて保存してみる
- 書いているときにフォーマット違反があったらエラーを出す&保存時に自動フォーマットしてくれるはず
- 投稿日:2020-12-27T19:28:54+09:00
SPA作成の雛形【Vue.js/Vuetify】
概要
・ Vue.js/VuetifyでSPAを作成時にこの雛形から要素を付け足していくことにすればスムーズにSPAが作成できるかと思い投稿
・ 使用した技術はVuetify
・ 開発環境はVue-CliApp.vue<template> <v-app> //左に出てくるナビゲーションドローワー <v-navigation-drawer app v-model="drawer" temporary> <v-list-item> <v-list-item-content> <v-avatar> <img src="photoURL"> </v-avatar> </v-list-item-content> <v-list-item-content> <v-list-item-title>ユーザネーム</v-list-item-title> </v-list-item-content> </v-list-item> <v-divider></v-divider> <v-list-item v-for="item in menuItems" :key="item.title" :to="item.link"> <v-list-item-icon> <v-icon>{{ item.icon }}</v-icon> </v-list-item-icon> {{ item.title }} </v-list-item> </v-navigation-drawer> //画面の上に表示するナビゲーションバー <v-app-bar app> <v-app-bar-nav-icon @click.stop="drawer = !drawer"> </v-app-bar-nav-icon> <v-toolbar-title> <router-link to="/" tag="span" style="cursor: pointer">アプリケーション</router-link> </v-toolbar-title> <v-spacer></v-spacer> <v-toolbar-items class="hidden-xs-only"> <v-btn text v-for="item in menuItems" :key="item.title" :to="item.link"> <v-icon medium left>{{ item.icon }}</v-icon> {{ item.title }} </v-btn> </v-toolbar-items> </v-app-bar> //routerの画面の表示場所 <v-main> <router-view/> </v-main> </v-app> </template> <script> export default { name: 'app', data: () => ({ drawer : false }), computed: { menuItems(){ let menuItems = [ {icon: "mdi-login", title:"ログイン", link:"/login"}, {icon: "mdi-account-multiple", title:"アイテムを見る", link:"/items"}, {icon: "mdi-google-maps", title:"アイテムを投稿", link:"/item/new"} //以下省略... ] return menuItems } }; </script>■Vuetifyコンポーネントは下記を使用。バージョンによって変化するので注意が必要。
・ナビゲーションドローワー: v-navigation-drawer
参考:https://vuetifyjs.com/ja/components/navigation-drawers/
・ナビデーションバー: v-app-bar
参考:https://vuetifyjs.com/ja/components/app-bars/■menuItemsとして配列にアイテムを保存してv-forループで表示。
■class="hidden-xs-only" : 画面がXSサイズ(スマホサイズ)で見るときにだけバーのメニューが消える。
参考:https://vuetifyjs.com/ja/styles/display/#visibility■v-mainの中に遷移していく画面であるrouter-viewを入れる。router-viewのところに、router/index.jsの画面が遷移していく。
router/index.jsimport Vue from 'vue' import VueRouter from 'vue-router' import Home from '../components/Home.vue' import CreateFreeTalk from '../components/Item/CreateItemc.vue' //以下省略... Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/item/new', name: 'CreateItem', component: CreateItem }, //以下省略... ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
- 投稿日:2020-12-27T18:22:00+09:00
【Vue 2.x】Composition API の readonly と shallowReadonly で気を付けること
TL;DR
@vue/composition-api
v1.0.0-beta.21 からreadonly()
,shallowReadonly()
が提供されるようになったreadonly()
は引数で受け取ったオブジェクトの型を DeepReadonly 化して返しているだけであるshallowReadonly()
は Vue 3 のものとほぼ同じように使える
readonly()
とshallowReadonly()
とは?
readonly()
は Vue 3 ではリリース時から提供されているリアクティビティ API で、リアクティブな状態を受け取ってリードオンリーなリアクティブな状態を返すことを目的とする関数です。
readonly()
のコード例1
// Vue 3 import { reactive, readonly } from 'vue'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = readonly(original); original.countA++; copy.countA++; // Set operation on key "countA" failed: target is readonly. original.foo.countB++; copy.foo.countB++; // Set operation on key "countB" failed: target is readonly. console.log(original.countA); // 1 console.log(copy.countA); // 1 console.log(original.foo.countB); // 1 console.log(copy.foo.countB); // 1
shallowReadonly()
も Vue 3 ではリリース時から提供されているリアクティビティ API で、readonly()
との違いはリードオンリーになる範囲がオブジェクトの第1階層の値に限定される点です。
shallowReadonly()
のコード例1
// Vue 3 import { reactive, shallowReadonly } from 'vue'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = shallowReadonly(original); original.countA++; copy.countA++; // Set operation on key "countA" failed: target is readonly. original.foo.countB++; copy.foo.countB++; // ブラウザのコンソール上に警告が出ない console.log(original.countA); // 1 console.log(copy.countA); // 1 console.log(original.foo.countB); // 2 console.log(copy.foo.countB); // 2
ユースケース
readonly()
を用いることでprovide()
や props などによって子コンポーネントに状態を渡す際、子コンポーネント側からの状態の変更を防ぐことができます。
このことは Vue 3 ドキュメントのリアクティブの基礎 - readonly でリアクティブオブジェクトの変更を防ぐにも記載があります:例えば、provide されたリアクティブオブジェクトがある場合、それが注入された場所からの変更は防ぎたいことがあります。そうするために、元のオブジェクトに対する読み取り専用のプロキシを作成します
Vue 2 の
readonly()
とshallowReadonly()
についてVue 2 では Composition API は
@vue/composition-api
プラグインとして提供されていますが、@vue/composition-api
v1.0.0-beta.21 から Vue 2 向けにreadonly()
,shallowReadonly()
が提供されるようになりました。
readonly()
は Vue 3 のものとは全く異なる
@vue/composition-api
でのreadonly()
の実装2を確認すると、引数で受け取ったオブジェクトの型を DeepReadonly 化して返しているだけであることがわかります。そのため TypeScript による型チェックをすり抜けてしまった場合3、Vue 3 の
readonly()
とは異なり状態の変更ができてしまいます:// Vue 2 import { reactive, readonly } from '@vue/composition-api'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = readonly(original); original.countA++; copy.countA++; // ブラウザのコンソール上に警告が出ない original.foo.countB++; copy.foo.countB++; // ブラウザのコンソール上に警告が出ない console.log(original.countA); // 2 console.log(copy.countA); // 2 console.log(original.foo.countB); // 2 console.log(copy.foo.countB); // 2
shallowReadonly()
は Vue 3 のものとほぼ同じように使える
shallowReadonly()
は Vue 3 のものと同様にリードオンリーになる範囲がオブジェクトの第1階層の値に限定されますが、Vue 3 のものとほぼ同じように使うことができます。Vue 2 では場合によっては
readonly()
よりもshallowReadonly()
を使った方が良いことがあります。
例えば、各プロパティの値がすべてプリミティブ型であるようなオブジェクトにはshallowReadonly()
を用いることでreadonly()
よりも確実に状態の変更を防ぐことができます:// Vue 2 import { reactive, readonly, shallowReadonly } from '@vue/composition-api'; // 各プロパティの値がすべてプリミティブ型(string | number | boolean)である const original = reactive({ text1: '', text2: '', text3: '', number1: 0, number2: 0, }); // Not good const copy1 = readonly(original); // Better const copy2 = shallowReadonly(original);
Vue 2 の
shallowReadonly()
にはできないことについて
@vue/composition-api
でのshallowReadonly()
の実装4を確認すると、引数で受け取ったオブジェクトの(第1階層の)キーでループを回し5、別途定義したオブジェクトに対して同じキーを持つプロパティを定義する6実装となっていることがわかります。
そのためshallowReadonly(obj)
実行時にobj
が持っているプロパティの値に限ってリードオンリーとすることができます。// Vue 2 import { reactive, shallowReadonly } from '@vue/composition-api'; const original = reactive({ countA: 100, }); const copy = shallowReadonly(original); original.countB = 200; console.log(copy.countA); // 100 console.log(copy.countB); // undefined// Vue 3 import { reactive, shallowReadonly } from 'vue'; const original = reactive({ countA: 100, }); const copy = shallowReadonly(original); original.countB = 200; console.log(copy.countA); // 100 console.log(copy.countB); // 200
2020/12/27 時点でリリースされていない Vue 3 の IE11 互換ビルドを利用すると Vue 3 の
readonly()
,shallowReadonly()
の挙動が本記事で想定しているものと異なるものとなる可能性があります ↩
@vue/composition-api
v1.0.0-beta.22 でのreadonly()
の実装: https://github.com/vuejs/composition-api/blob/v1.0.0-beta.22/src/reactivity/readonly.ts#L42-L46 ↩特に Vue では
<template>
上のv-model
など型チェックが効きにくい場所があったりします ↩
@vue/composition-api
v1.0.0-beta.22 でのshallowReadonly()
の実装: https://github.com/vuejs/composition-api/blob/v1.0.0-beta.22/src/reactivity/readonly.ts#L48-L97 ↩
for (const key of Object.keys(obj)) { ... }
の部分 ↩
Object.defineProperty(readonlyObj, key, { ... })
の部分 ↩
- 投稿日:2020-12-27T12:53:57+09:00
[Vue.js]Storeの値がcommit以外で変わっちゃった時の話
前書き
業務でNuxt.jsアプリの改修をしていて、
なんかバグ出てるやん
→ どうやらStoreの値中の配列の値がおかしいぞ
→ 変な値がcommitされているんだな
→ commit値は正常だな・・
→ あ、変なところでまたcommitが呼ばれちゃってるんだな!
→ commitは(正常時の)1回しかされていないぞ・・
→ 詰なことがあったので、これを解決した時の話を書いてみます。
体験談
今回のポイントは、異常値を示した値の型が
配列
と言う点。最初はVue初級者が故に、
storeの値はcommitから以外で変わり得ない
、と言う前提はあったため、
VueXの仕様的に誤った使い方しているんじゃ、、と的外れなあたりをつけてVue周りを調べてました。そんな時、ふと配列で思い出したのが、
配列は参照型やん
、です。なので、
storeから取り出した配列を直接いじってる部分がないか
と言う方針で調査を進めました。そして見つけました。
lodash(JSライブラリ)の
_.remove()
メソッド※removeメソッドについてはこちらの記事がとても参考になります。
この処理の前後のstoreの値を確認し、確信しました。
この処理周りを改善し、無事バグ解決。
参照型とは
超ざっくり言うと、値が置いてある場所、のこと。
Java習いたてでよく注意点として出て来ます。ありがちな事象は以下
↓
ある変数を別の変数にコピーして、値2個できたやん、とか思って片方を変更する。
でも参照型の場合は実際には場所を指しているので、コピーされたのは場所情報だけ、変更されたのはその場所にある値である。
つまり同じ場所を指しているもう一方の変数も、一緒に値が変わってしまう。文面で起こすの辛いので実例↓
// JSの場合 var a = [1,2,3,4,5]; // 配列定義。 var b = a; // 変数をコピー。実際は配列のある場所だけコピーされる。 b.pop(); // bの末尾削除 console.log(a); // [1,2,3,4] console.log(b); // [1,2,3,4] // aも削除されちゃったまとめ
配列が参照型、と言うのは実際にその類のバグに遭遇しないと意識しないと思うので、
体験談を書き記してみました。これがあってから改めて意識するようになったのが、
- Vuexのstoreの中身がcommit以外から変更されるパターンもある(ReactのReduxなどでも同様だと思う)
- storeなど固定値として保持されている配列を直接いじらない
- 配列の中身に関するバグがあったら、直接操作を行っていないかを疑う
です。
ちなみにどうしてもいじる必要がある場合は、
例えばlodashの_.cloneDeep()
と言うメソッドを使うことで、
配列を完全複製し、それを使用する方法などが回避策になるかなと思います。この記事を見て、
うわ、こんなバグもありえるのか!、と感心していただけたり、
自分もあったわw、と共感していただける人がいたら幸いです。参考
- 投稿日:2020-12-27T10:36:06+09:00
vue cli, Netlify, Functionsの初期設定
vue-cliでアプリ作ってNetlifyに上げる。Fuctionsも使いたい。そんな備忘録。
環境はWin10上でWSL2(Ubuntu)です。
$ sudo npm install -g --force @vue/cli
- いつのだかわからないvue-cliが入ってたので、--forceで上書き
$ vue create my-application
$ cd my-application
$ git init
- ブラウザでGitHubにリポジトリ作成(README.mdの自動生成とかはしなかった。vue cliのと被るし。)
my-application
ディレクトリ直下で以下を実施(GitHubの画面に表示されいる通りに実施。mainブランチにするような手順になってたがmasterのままにした。)
$ git remote add origin git@github.com:<アカウント名>/<リポジトリ名>.git
$ git push -u origin master
- ブラウザでNetlifyで
New site from Git
とかそんな感じのボタンから当該リポジトリを追加
- Can’t see your repo here? Configure the Netlify app on GitHub.とか書いてあってリンクになってるのでそこから結び付けたいリポジトリを許可する手順も必要。
- あとはよしなに
- 完了的なのがでるので、以下の場所の矢印のとこをクリックするとVueのサンプル画面がでる。ここまででサイトのデプロイはOK。
![]()
- Functionsも設定していきましょう。
- コンソールに戻って、
$ cd my-application
$ vue add netlify-lambda
package.json
のbrowserslist
から"not dead"
の行を削除。←後述のエラーが出たので。$ npm run build && npm run serve
- ブラウザで
http://localhost:9000/hello
にアクセスするといい感じに見える![]()
- コンソールに戻って、serveをCtrl+cで止める
.gitignore
に/lambda
を加えるnetlify.toml
のcommand
をyarn build
からnpm run build
にする←デプロイしたときにyarnがないというエラーになったので(汗$ git add . && git commit -m "add functions" && git push
- ブラウザでNetlifyを確認しデプロイ状況を確認。
https://app.netlify.com/sites/Netlify上のアプリ名/deploys
published
になったらhttps://Netlify上のアプリ名.netlify.app/.netlify/functions/hello
にアクセスしてみる。ローカルでみたハロワ的なメッセージでたら完了、おつかれさんでした。よくわからん現象ズ
ビルドエラー
BrowserslistError: [BABEL] /opt/build/repo/src/lambda/hello.js: Unknown browser query `dead` (While processing: "/opt/build/repo/node_modules/babel-preset-env/lib/index.js")ローカルでのビルド時に発生したので
package.json
のbrowserslist
から"not dead"
の行を削除。
それで再実行するとエラーはなくなった。
その後もう一度"not dead"を追加したらエラーでなくなった。
それでpushしたところ、Netlify側でも同様のエラーが出た。(functionsのデプロイが失敗してた)
なのでやっぱり"not dead"
を削除してpush。
そしたらNetlify側でもビルド成功した。functionsにもアクセスできるようになりました。
- 投稿日:2020-12-27T10:18:43+09:00
そうだ、firebaseで、自動でログイン、ログアウトを実行してみよう!
最近、ユーザー認証でfirebaseを使用しているのですが、何と言っても凄いなと感じました。
例えば、Facebookとの連携を取る際に、ユーザーが重複しているかの確認も自動でしてくれますし、メール送信機能もGmailを使って送信することができるんですよ。
これを全て1から実装するとなると手間はかかりますよね。。。
話は変わりますが、firebaseで
updateEmail(),upadatePassword()
という関数があるのをご存じでしょうか?firebaseに触れたことがある方は恐らくご存じかと思います。
ふと、この関数を実行したところ、firebase側では変更されているのですが、Webサイト上では更新されていない!!!
これは困ったなと思い色々調べたところ、updateした後はログアウトをし、再度ログインしなきゃいけないらしい。
でもこれをユーザーにわざわざ操作させるなんてことはできない。
そこで、今回は、upadateした後に、自動でログアウトとログインを実行する方法を説明していきます!!!
また、メールアドレスやパスワードを変更する時、ユーザーの再認証が必要なのでこれも説明します。
そんなに難しくないので、是非学習の参考にしてください!
それでは順を追って説明します。(メールアドレス変更での実装となります。パスワードを変更する時でも同じく使えます。)
パスワードの入力
下記のように、ユーザーにパスワードの入力をしてもらいます。
reAuth.vue<template> <div class="reauth"> <div class="form-wrapper"> <h1>不正防止のためパスワードの入力をお願いします。</h1> <form> <div class="form-item"> <label for="email">現在のメールアドレス</label> <input type="email" name="email" required="required" :value="beforeEmail" disabled="true"> </div> <div class="form-item"> <label for="email2">変更後メールアドレス</label> <input type="email" name="email2" required="required" :value="updateEmail" disabled="true"> </div> <div class="form-item"> <label for="password">パスワード</label> <input type="password" name="password" required="required" placeholder="パスワードを入力してください" v-model="password"> </div> <div class="button-panel"> <input type="button" class="button" value="変更する" @click="update"> </div> </form> </div> </div> </template> <script> import firebase from "firebase/app"; export default{ props: ["updateEmail"], //変更するメールアドレス name: "reAuth", data() { return { beforeEmail: this.$store.state.user.email, //変更する前のメールアドレス password: "", //パスワード } }, } </script>再認証→ログアウト→ログインの実行
reAuth.vue<script> methods: { update() { let vm = this; const user = firebase.auth().currentUser; //現在のユーザーを取得 const credential = firebase.auth.EmailAuthProvider.credential(this.beforeEmail, this.password); //メールアドレスとパスワードでユーザーの確認 user.reauthenticateWithCredential(credential) //再認証 .then(() => { user.updateEmail(vm.updateEmail) //メールアドレスの更新 .then(() => { firebase.auth().signOut() //変更し終えたら、ログアウトを実行 .then(() => { firebase.auth().signInWithEmailAndPassword(vm.updateEmail, vm.password) //ログアウトし終えたら、ログインの実行 .then((user) => { vm.$store.dispatch("login", user); //Vuexのストア内のuserの書き換え vm.$router.replace({ //ページ遷移 name: "User", }) } ) }) }) .catch((error) => { alert(error); }) }) .catch((error) => { alert(error); }) } }, </script>このような流れで変更内容を反映することができます!!!
それぞれの処理が終わったら、
.then(() => {})
の中で実行することで、一連の動作を行えます。この
.then(() => {})
で行わないと、例えばログアウトをし終えてないのにログインしてしまうという流れになるので、くれぐれも気を付けてください!何かご不明な点がございましたら、コメントにてご報告ください。
以上、「firebaseで、自動でログイン、ログアウトを実行する方法」でした!!
良ければ、LGTM、コメントお願いします。
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
Thank you for reading
- 投稿日:2020-12-27T00:35:27+09:00
【Vue.js/Vuetify/Vuex】リアルタイム検索
概要
・ ポートフォリオでリアルタイム検索機能を実装したので、コメントつきのソースコードを紹介
・ 使用した技術はVue.js,Vuetify,Vuex
※ v-text-field のページは以下URL内にあり。
https://vuetifyjs.com/en/components/text-fields/#api
・ api経由でデータを取得し、ページネーション付きで表示する
・ 開発環境はVue-Clitemplate<v-layout> <v-flex2> <v-card> <v-card-title> <v-text-field label="検索する" v-model="search"> </v-text-field> </v-card-title> </v-card> </v-flex> </v-layout> <v-layout v-for="list in getLists" :key="list.index"> //以下リストの内容が表示される </v-layout>computed内では、stateから取得したリストをgetListsで自分が入力した内容とマッチするリストになるようにフィルタリング。
フィルタリングしたリストをv-forループで表示させる。scriptdata(){ return : { search: " } }, computed(){ getLists(){ const lists = this.$store.state.lists return lists.filter((list) => { return list.title.match(this.search) //search:検索欄に入力した内容 }) } }以下がgetListsから引き出したstateのリストの内容。
store(state)lists: [ { id: "akdddgela22nad", title: "FreeTalk in NewYork", date: "2017-09-29", location: "New York"}, { id: "akdbbraa5ffggg", title: "FreeTalk in Paris", date: "2017-10-20", location: "Paris", } //以下省略... ],下記のように" || "を使用すれば、リストの中のあらゆるワードや数字を拾って検索も可能になる。
scriptreturn list.title.match(this.search) || list.date.match(this.search) || list.location.match(this.search)
- 投稿日:2020-12-27T00:35:27+09:00
リアルタイム検索【Vue.js/Vuetify/Vuex】
概要
・ ポートフォリオでリアルタイム検索機能を実装したので、コメントつきのソースコードを紹介
・ 使用した技術はVue.js,Vuetify,Vuex
※ v-text-field のページは以下URL内にあり。
https://vuetifyjs.com/en/components/text-fields/#api
・ api経由でデータを取得し、ページネーション付きで表示する
・ 開発環境はVue-Clitemplate<v-layout> <v-flex2> <v-card> <v-card-title> <v-text-field label="検索する" v-model="search"> </v-text-field> </v-card-title> </v-card> </v-flex> </v-layout> <v-layout v-for="list in getLists" :key="list.index"> //以下リストの内容が表示される </v-layout>computed内では、stateから取得したリストをgetListsで自分が入力した内容とマッチするリストになるようにフィルタリング。
フィルタリングしたリストをv-forループで表示させる。scriptdata(){ return : { search: " } }, computed(){ getLists(){ const lists = this.$store.state.lists return lists.filter((list) => { return list.title.match(this.search) //search:検索欄に入力した内容 }) } }以下がgetListsから引き出したstateのリストの内容。
store(state)lists: [ { id: "akdddgela22nad", title: "FreeTalk in NewYork", date: "2017-09-29", location: "New York"}, { id: "akdbbraa5ffggg", title: "FreeTalk in Paris", date: "2017-10-20", location: "Paris", } //以下省略... ],下記のように" || "を使用すれば、リストの中のあらゆるワードや数字を拾って検索も可能になる。
scriptreturn list.title.match(this.search) || list.date.match(this.search) || list.location.match(this.search)
- 投稿日:2020-12-27T00:19:25+09:00
【解決!】Vue-Cliをインストール...できない!
状況
・Vue-Cliを使った本格的なアプリ開発をするためにVue-Cliをインストールしようとした
・過去にもVue-Cliをインストールして使った経験あり!
・コマンドプロンプトを開いて「いざ!やるぞ!」と思っていた矢先、早速出鼻をくじかれた...という話です。起こったこと①
・コマンドプロンプトで下のようにVue-Cliをインストール
npm -g install vue-cli・以下エラーが発生
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen) npm WARN deprecated har-validator@5.1.5: this library is no longer supported npm ERR! code EEXIST npm ERR! path C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue npm ERR! dest C:\Program Files (x86)\Nodist\bin\*vue.cmd* npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' ->'C:\Program Files (x86)\Nodist\bin\vue.cmd' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue.cmd npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Owner\AppData\Roaming\npm-cache\_logs\2020-12-24T15_55_11_169Z-debug.log対策①
ポイントは5行目~11行目。
要約すると
「既にインストールしているデータがある時のエラーだよ!」(5行目)
「具体的にはProgram Files (x86)\Nodist\bin\vue.cmd
のことだよ!」(8~9行目)
「このfileを消してもう一回やってみて!」(10行目)
とある。
・冒頭書いた通り、一度Vue-Cliはインストールしたことあるので、その時インストールしたファイルたちが残っていた。
どうもそのファイルが今回のインストールを邪魔している、らしい。
・なので、一旦Program Files (x86)\Nodist\bin
にあるvue.cmd
を消して再度npm -g install vue-cli
を実行起こったこと②
・開発へ進める!と思ったら、またしても以下エラー発生
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen) npm WARN deprecated har-validator@5.1.5: this library is no longer supported npm ERR! code EEXIST npm ERR! path C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue npm ERR! dest C:\Program Files (x86)\Nodist\bin\vue npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' -> 'C:\Program Files (x86)\Nodist\bin\*vue*' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly.・さっきと同じようなエラー。よくよく見ると...
npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' -> 'C:\Program Files (x86)\Nodist\bin\vue' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue・消すべきファイルの名前が変わっている。
対策②
・なるほど。過去インストールしたいくつかのファイルが邪魔して今回インストールできないわけだ、と悟り/同じく今回もvueファイルを消す。
・結局、「消す⇒npm -g install vue-cli
実行⇒エラー(○○を消してね!)⇒消す⇒...」を10回ほど繰り返した
○○に指定されて消したファイルは以下の通り
・こんなに何回もエラーを頻発した理由は、これらのファイルたちはnpm -g install vue-cli
を実行するとまた最新verが生まれてくるということ。
で、その生まれたファイルたちがエラーの原因となってしまうこともあった。
・結論、上図のファイルたちを一気に消してnpm -g install vue-cli
で正常にインストール完了!エラーの原因
・今回のエラーの原因はどうも先ほどお見せしたファイルたちのインストールした日時らしい。
・元々インストールしたファイルたちは2020/12/20にインストールしたモノだったので、これがある限りエラーを発生しまくった。
・そこで上記のようにファイルたちを一気に消してnpm -g install vue-cli
を実行し最新版のファイルが作成され、うまくいった!という流れ。最後に
大したことではないですが、ググって同じようなエラーコード出ている方々はいらっしゃいましたが、ほとんどの方はMacユーザーの方でした。
そういった方の対策案を参考にした自分はこのエラーも出していました。ここで初めてWindowユーザーである自分は"sudo"や"rm"などのLinuxが使えない、ということを学びました。
参考までに。