使用 Vue.js 建立簡單的 GraphQL client
建立專案 (使用 @vue/cli (3.x.x))
$vue create graphql-vue Vue CLI v3.0.0-rc.3 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, Linter ? Pick a linter / formatter config: Basic ? Pick additional lint features: Lint on save ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No Vue CLI v3.0.0-rc.3 ✨ Creating project in xxx ? Initializing git repository... ⚙ Installing CLI plugins. This might take a while...
加入 apollo plugin
$vue add apollo ? Installing vue-cli-plugin-apollo... > [email protected] install /tmp/graphql-vue/node_modules/fsevents > node install [fsevents] Success: "/tmp/graphql-vue/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" already installed Pass --update-binary to reinstall or --build-from-source to recompile > [email protected] postinstall /tmp/graphql-vue/node_modules/protobufjs > node scripts/postinstall > [email protected] postinstall /tmp/graphql-vue/node_modules/nodemon > node bin/postinstall || exit 0 + [email protected] added 470 packages from 327 contributors in 55.574s ✔ Successfully installed plugin: vue-cli-plugin-apollo ? Add example code No ? Add a GraphQL API Server? No ? Invoking generator for vue-cli-plugin-apollo... ? Installing additional dependencies... added 2 packages from 3 contributors in 24.734s ⚓ Running completion hooks... Successfully invoked generator for plugin: vue-cli-plugin-apollo The following files have been updated / added: src/vue-apollo.js package-lock.json package.json src/main.js You should review these changes with git diff and commit them.
目前檔案
$tree -I node_modules . ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html └── src ├── App.vue ├── assets │ └── logo.png ├── components │ └── HelloWorld.vue ├── main.js └── vue-apollo.js
檢查 src/vue-apollo.js
是否連結對的 GraphQL server
import Vue from 'vue' import VueApollo from 'vue-apollo' import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client' // Install the vue plugin Vue.use(VueApollo) // Name of the localStorage item const AUTH_TOKEN = 'apollo-token' // Config const defaultOptions = { // You can use `https` for secure connection (recommended in production) httpEndpoint: process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:4000/graphql', // You can use `wss` for secure connection (recommended in production) // Use `null` to disable subscriptions wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:4000/graphql', // LocalStorage token tokenName: AUTH_TOKEN, // Enable Automatic Query persisting with Apollo Engine persisting: false, // Use websockets for everything (no HTTP) // You need to pass a `wsEndpoint` for this to work websocketsOnly: false, // Is being rendered on the server? ssr: false, // Override default http link // link: myLink // Override default cache // cache: myCache // Override the way the Authorization header is set // getAuth: (tokenName) => ... // Additional ApolloClient options // apollo: { ... } // Client local data (see apollo-link-state) // clientState: { resolvers: { ... }, defaults: { ... } } } // Call this in the Vue app file export function createProvider (options = {}) { // Create apollo client const { apolloClient, wsClient } = createApolloClient({ ...defaultOptions, ...options, }) apolloClient.wsClient = wsClient // Create vue apollo provider const apolloProvider = new VueApollo({ defaultClient: apolloClient, defaultOptions: { $query: { // fetchPolicy: 'cache-and-network', }, }, errorHandler (error) { // eslint-disable-next-line no-console console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message) }, }) return apolloProvider } // Manually call this when user log in export async function onLogin (apolloClient, token) { localStorage.setItem(AUTH_TOKEN, token) if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient) try { await apolloClient.resetStore() } catch (e) { // eslint-disable-next-line no-console console.log('%cError on cache reset (login)', 'color: orange;', e.message) } } // Manually call this when user log out export async function onLogout (apolloClient) { localStorage.removeItem(AUTH_TOKEN) if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient) try { await apolloClient.resetStore() } catch (e) { // eslint-disable-next-line no-console console.log('%cError on cache reset (logout)', 'color: orange;', e.message) } }
src/main.js
加入 apollo provider
import Vue from 'vue' import App from './App.vue' import { createProvider } from './vue-apollo' Vue.config.productionTip = false new Vue({ provide: createProvider().provide(), render: h => h(App) }).$mount('#app')
加入簡單的 component components/MyApollo.vue
<template> <div class="my-apollo"> <h1>{{ msg }}</h1> <div class="user-info"> <table> <thead> <tr> <th>username</th> <th>email</th> </tr> </thead> <tbody> <tr v-for="user in users" :key="user.id"> <td>{{user.username}}</td> <td>{{user.email}}</td> </tr> </tbody> </table> </div> </div> </template> <script> import gql from 'graphql-tag'; export default { name: 'MyApollo', props: { msg: String }, apollo: { users: gql`{ users { id username email }}` }, data() { return { users: [] } } } </script> <style scoped> .user-info { display: flex; justify-content: center; } table { table-layout: fixed; width: 80%; border: 2px solid grey; border-collapse: collapse; letter-spacing: 1px; } thead th { border: 1px solid grey; } tbody { text-align: left; } tbody tr:nth-child(even) { background: #eaeaea; } tbody tr td { border-right: 1px solid grey; } th, td { padding: 5px 10px; } </style>
修改 src/App.vue
<template> <div id="app"> <img src="https://blog.onionstudio.com.tw/wp-content/uploads/2018/07/logo.png"> <MyApollo msg="Welcome to Your Vue.js App"/> </div> </template> <script> import MyApollo from './components/MyApollo.vue'; export default { name: 'app', components: { MyApollo } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
執行
$npm run serve DONE Compiled successfully in 494ms 10:47:40 App running at: - Local: http://localhost:8080/ - Network: http://10.0.1.196:8080/