使用 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/

未命名_2018-07-05_11-19-35.png

Notice: compact(): Undefined variable: limits in /var/www/html/wp-includes/class-wp-comment-query.php on line 853 Notice: compact(): Undefined variable: groupby in /var/www/html/wp-includes/class-wp-comment-query.php on line 853

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *