今すぐVue3でApolloを使いたい
abstract
現在、Vue3にApolloが対応していない。
しかし、後述のpatch
を当てることで利用することができる(できた)
現在このpatch
はPR中である。
いずれマージされればこのpatchを当てることなく利用できるとのこと。
参考
youtubeで詳しく解説されています。
(この記事はほぼその文字起こし)
環境
$vue --version
@vue/cli 4.5.11
$node -v
v14.0.0
*nodeのバージョンはかなりデリケート(新しすぎると互換性がなくて動かない)
create project
$vue create test-gg
(いろいろ聞かれるので下記のように回答)
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel
? Choose a version of Vue.js that you want to start the project with 3.x (Preview)
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
Build Apps With Vue 3 + Apollo Client3
Apollo Installation
Apollo Client:
$yarn add @apollo/client graphql
queryの作成・接続
jsにクライアント情報を追加する。
import { ApolloClient, InMemoryCache } from '@apollo/client'
const defaultClient = new ApolloClient({
uri: 'https://rickandmortyapi.com/graphql/',
cache: new InMemoryCache()
})
テストクエリを追加
適当にクエリを作成してみる。
適当に作ったクエリを記述する。
import { createApp } from 'vue'
import { ApolloClient, gql, InMemoryCache } from '@apollo/client'
import App from './App.vue'
const defaultClient = new ApolloClient({
uri: 'https://rickandmortyapi.com/graphql/',
cache: new InMemoryCache()
})
const query = gql`
query {
characters {
results {
name
}
}
}
`
defaultClient
.query({
query
})
.then(res => console.log(res))
createApp(App).mount('#app')
*gql
は@apollo/client
で用意されている。
react
がないとerrorがはかれる。
react installation
$yarn add react
yarn server
ローカルにアクセスし、consoleを開くとデータが取れている。
Composition APIのvue Apollo
vue-Apolloでは3つのパッケージが提供されている。
Vue3なのでComposition API
を選択
*vue2向けのパッケージだけど必要なので無理やり使う。
$yarn add @vue/apollo-composable
Vue2はnew Vue
によって生成する。
Vue3はcreate
した物をmountして生成する。
ここに無理が生じる。
次のように書き換えてみる。
import { createApp, provide, h } from 'vue'
import { ApolloClient, gql, InMemoryCache } from '@apollo/client'
import { DefaultApolloClient } from '@vue/apollo-composable'
import App from './App.vue'
const defaultClient = new ApolloClient({
uri: 'https://rickandmortyapi.com/graphql/',
cache: new InMemoryCache()
})
const query = gql`
query {
characters {
results {
name
}
}
}
`
defaultClient
.query({
query
})
.then(res => console.log(res))
createApp(
{
setup() {
provide(DefaultApolloClient, defaultClient)
},
render() {
return h(App)
},
}
).mount('#app')
consoleでエラーがなければ準備OK。
テストコードをコメントアウト。
import { createApp, provide, h } from 'vue'
import { ApolloClient, gql, InMemoryCache } from '@apollo/client'
import { DefaultApolloClient } from '@vue/apollo-composable'
import App from './App.vue'
const defaultClient = new ApolloClient({
uri: 'https://rickandmortyapi.com/graphql/',
cache: new InMemoryCache()
})
// const query = gql`
// query {
// characters {
// results {
// name
// }
// }
// }
// `
// defaultClient
// .query({
// query
// })
// .then(res => console.log(res))
createApp(
{
setup() {
provide(DefaultApolloClient, defaultClient)
},
render() {
return h(App)
},
}
).mount('#app')
vue.config.js
graphql
orgql
の拡張子が表示された場合、タグローダーを使用してインポートさせる。
module.exports = {
chainWebpack: config => {
config.module
.rule('graphql')
.test(/\.(graphql|gql)$/)
.use('graphql-tag/loader')
.loader('graphql-tag/loader')
.end();
}
};
grapgqlを作成
ディレクトリ を作成。
./src/graphql
gqlファイルを作成。
./src/graphql/allCharecters.query.gql
queryを追加。
*queryの名前もつける。
query allCharecters {
characters {
results {
name
image
}
}
}
vueファイル
テストメッセージを書いてみる。
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
+ {{ message }}
</template>
<script>
+ import { ref } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
+ setup() {
+ const message = ref('Hello, gamine.')
+
+ return { message }
+ },
}
</script>
<...>
サーバーにアクセスして表示されるか確認。
*Vue2ではtemplateの中をdivなどでラップする必要があったがVue3ではその必要がない。
queryの呼び出し
userQuery
でqueryを呼び出す。
import { ref } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
+ import { useQuery } from '@vue/apollo-composable'
+ import allCharactersQuery from './graphql/allCharacters.query.gql'
export default {
name: 'App',
components: {
HelloWorld
},
setup() {
const message = ref('Hello, gamine.')
+ const { result } = useQuery(allCharactersQuery)
console.log(result)
return { message }
},
}
</script>
ローカルを開くとエラー。vue-apolloがVue3に対応していないので。
$yarn serve
"export 'onServerPrefetch' was not found in 'vue-demi'
Uncaught Invariant Violation: Expecting a parsed GraphQL document. Perhaps you need to wrap the query string in a "gql" tag?
*2021-02-28現在、GitHubでPRが出されているもののまだマージされていないとのこと。
ハッキーな解決策
実行するだけのscriptを作成
$mkdir ./script
$touch ./script/patch.js
コードを記述。
const fs = require('fs')
const path = require('path')
const loadTrackingPath = path.resolve(
__dirname,
'../node_modules/@vue/apollo-composable/dist/util/loadingTracking.js'
)
fs.writeFileSync(
loadTrackingPath,
fs.readFileSync(loadTrackingPath, 'utf8').replace(/\.\$root/m, '.root')
)
const useQueryPath = path.resolve(
__dirname,
'../node_modules/@vue/apollo-composable/dist/useQuery.js'
)
fs.writeFileSync(
useQueryPath,
fs
.readFileSync(useQueryPath, 'utf8')
.replace(/(^.*onServerPrefetch)/m, '$1=()=>{}; $1')
.replace(/(.* require\("vue"\);)/m, '')
.replace(/^.*(nextTick)/m, 'vue_demi_1.$1')
)
// もしくはこっちの方法もある(違いはわからん)
// const fs = require('fs')
// const path = require('path')
// const loadTrackingPath = path.resolve(
// __dirname,
// '../node_modules/@vue/apollo-composable/dist/util/loadingTracking.js'
// )
// fs.writeFileSync(
// loadTrackingPath,
// fs.readFileSync(loadTrackingPath, 'utf8').replace(/\.\$root/m, '.root')
// )
// const useQueryPath = path.resolve(
// __dirname,
// '../node_modules/@vue/apollo-composable/dist/useQuery.js'
// )
// fs.writeFileSync(
// useQueryPath,
// fs
// .readFileSync(useQueryPath, 'utf8')
// .replace(/(^.*onServerPrefetch)/m, '$1=()=>{}; $1')
// .replace(/(.* require\("vue"\);)/m, '')
// .replace(/^.*(nextTick)/m, 'vue_demi_1.$1')
// )
実行
$node ./script/patch.js
ローカルで実行。
consoleでNetWorkを確認し、GraphQLのレスポンスがあればOK。
(console.logで表示してもOK)
補足
実践したときは、ここで次のようなエラーが発生した
ERROR Failed to compile with 1 errors
error in ./node_modules/@vue/apollo-composable/dist/useQuery.js
Module parse failed: Unexpected token (14:10)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import { ref, isRef, computed, watch,
| // @ts-expect-error
> vue_demi_1.nextTick, } from 'vue-demi';
| import { throttle, debounce } from 'throttle-debounce';
| import { useApolloClient } from './useApolloClient';
@ ./node_modules/@vue/apollo-composable/dist/index.js 1:0-39 1:0-39
@ ./src/main.js
@ multi (webpack)-dev-server/client?http://192.168.0.198:8080&sockPath=/sockjs-node (webpack)/hot/dev-server.js ./src/main.js
package.json
を下に変更したら直った。。。
{
"name": "vue-3-and-apollo-client-3",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"@apollo/client": "^3.2.3",
"@vue/apollo-composable": "^4.0.0-alpha.10",
"core-js": "^3.6.5",
"graphql": "^15.3.0",
"react": "^16.13.1",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0"
}
}
resultを解凍して利用する
useResult
でデータを使える形にし、表示する。
(深く理解していないけどresultはオブジェクトで、それをよしなに変換してくれる。
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
{{ message }}
+ {{ character }}
</template>
<script>
import { ref } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
- import { useQuery } from '@vue/apollo-composable'
+ import { useQuery, useResult } from '@vue/apollo-composable'
import allCharactersQuery from './graphql/allCharacters.query.gql'
export default {
name: 'App',
components: {
HelloWorld
},
setup() {
const message = ref('Hello, gamine.')
const { result } = useQuery(allCharactersQuery)
+ const character = useResult(result, null, data => data.characters.results)
console.log(result)
- return { message }
+ return { message, character }
},
}
</script>
queryの結果が表示されました🎉
リスト表示してみる
<ul>
<li v-for="character in characters" :key="character.id">
<h2>{{ character.name }}</h2>
</li>
</ul>
mutation
サーバを用意していないので割愛。
(参考にした動画で説明しています)
まとめ
いますぐVue3でApolloを使いたいって人のための記事でした。
近いうちにptchは不要になる
今回追加しているpatch
は、pr中。
近い将来mergeされ、patch
は不要になる予定。
Discussion