├── client-addon ├── public │ └── .gitkeep ├── .postcssrc.js ├── README.md ├── babel.config.js ├── src │ ├── components │ │ ├── ApolloView.vue │ │ ├── widgets │ │ │ ├── EngineKeyMetricsQueries.vue │ │ │ ├── EngineKeyMetricsQuery.vue │ │ │ ├── EngineKeyMetricsP95Time.vue │ │ │ ├── EngineKeyMetricsRequestRate.vue │ │ │ ├── EngineKeyMetricsErrorPercentage.vue │ │ │ ├── EngineKeyMetrics.vue │ │ │ └── EngineKeyMetricsView.vue │ │ ├── SimpleGraph.vue │ │ └── GraphqlPlayground.vue │ ├── utils │ │ └── math.js │ └── main.js ├── vue.config.js ├── .gitignore ├── .eslintrc.js └── package.json ├── .gitignore ├── graphql-client ├── index.js └── src │ └── index.js ├── logo.png ├── .github └── FUNDING.yml ├── screenshot.png ├── .eslintignore ├── .npmignore ├── ui-public ├── view-tip.png ├── apollo-engine.png ├── publish-task.png └── vue-apollo-graphql.png ├── docs ├── guide │ ├── webpack.md │ ├── engine.md │ ├── express-middleware.md │ ├── manual-changes.md │ ├── mocks.md │ ├── injected-commands.md │ ├── client-state.md │ ├── server.md │ ├── env.md │ ├── auth.md │ ├── directives.md │ ├── index.md │ ├── server-prod.md │ └── configuration.md ├── .vuepress │ ├── public │ │ ├── favicon.png │ │ └── screenshot.png │ ├── style.styl │ └── config.js └── README.md ├── generator ├── templates │ ├── api-server │ │ ├── default │ │ │ └── apollo-server │ │ │ │ ├── data-sources.js │ │ │ │ ├── directives.js │ │ │ │ ├── type-defs.js │ │ │ │ ├── mocks.js │ │ │ │ ├── context.js │ │ │ │ ├── schema.graphql │ │ │ │ └── resolvers.js │ │ └── examples │ │ │ └── apollo-server │ │ │ ├── server.js │ │ │ └── utils │ │ │ ├── db.js │ │ │ └── upload.js │ └── vue-apollo │ │ ├── examples │ │ └── src │ │ │ ├── graphql │ │ │ ├── MessageFragment.gql │ │ │ ├── HelloWorld.gql │ │ │ ├── FileFragment.gql │ │ │ ├── Files.gql │ │ │ ├── Messages.gql │ │ │ ├── MessageAdded.gql │ │ │ ├── UploadFile.gql │ │ │ └── AddMessage.gql │ │ │ └── components │ │ │ └── ApolloExample.vue │ │ └── default │ │ ├── apollo.config.js │ │ └── src │ │ └── vue-apollo.js └── index.js ├── .babelrc ├── ui ├── views.js ├── index.js ├── configs.js ├── widgets.js └── tasks.js ├── utils ├── load.js ├── check-schema.js ├── publish-schema.js ├── load-env.js ├── engine-api.js ├── generate-schema.js └── index.js ├── operations └── engine │ └── key-metrics │ ├── p95-time.js │ ├── request-rate.js │ └── error-percentage.js ├── .eslintrc.js ├── prompts.js ├── README.md ├── package.json ├── types.d.ts ├── graphql-server └── index.js └── index.js /client-addon/public/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | client-addon-dist/ 4 | -------------------------------------------------------------------------------- /graphql-client/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/index') 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/logo.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Akryum 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/screenshot.png -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | templates/ 3 | dist/ 4 | client-addon/ 5 | client-addon-dist/ 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | client-addon/ 3 | .babelrc 4 | .eslintignore 5 | .eslintrc.js 6 | yarn.lock 7 | -------------------------------------------------------------------------------- /client-addon/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /ui-public/view-tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/ui-public/view-tip.png -------------------------------------------------------------------------------- /client-addon/README.md: -------------------------------------------------------------------------------- 1 | # Client addon for vue-apollo cli plugin 2 | 3 | ``` 4 | yarn serve 5 | yarn build 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/guide/webpack.md: -------------------------------------------------------------------------------- 1 | # Injected webpack-chain Rules 2 | 3 | - `config.rule('gql')`: Loader for GraphQL files. 4 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/data-sources.js: -------------------------------------------------------------------------------- 1 | export default function() { 2 | return {}; 3 | } -------------------------------------------------------------------------------- /ui-public/apollo-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/ui-public/apollo-engine.png -------------------------------------------------------------------------------- /ui-public/publish-task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/ui-public/publish-task.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "modules": "commonjs" 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /client-addon/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /ui-public/vue-apollo-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/ui-public/vue-apollo-graphql.png -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/docs/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/MessageFragment.gql: -------------------------------------------------------------------------------- 1 | fragment Message on Message { 2 | id 3 | text 4 | } 5 | -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akryum/vue-cli-plugin-apollo/HEAD/docs/.vuepress/public/screenshot.png -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/HelloWorld.gql: -------------------------------------------------------------------------------- 1 | query HelloWorld ($name: String) { 2 | hello (name: $name) 3 | } 4 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/FileFragment.gql: -------------------------------------------------------------------------------- 1 | fragment file on File { 2 | id 3 | path 4 | filename 5 | mimetype 6 | encoding 7 | } 8 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/Files.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | query files { 4 | files: uploads { 5 | ...file 6 | } 7 | } -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/Messages.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | query messages { 4 | messages { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/MessageAdded.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | subscription messageAdded { 4 | messageAdded { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/directives.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // Schema directives 3 | // https://www.apollographql.com/docs/graphql-tools/schema-directives.html 4 | } 5 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/UploadFile.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | mutation uploadFile ($file: Upload!) { 4 | singleUpload (file: $file) { 5 | ...file 6 | } 7 | } -------------------------------------------------------------------------------- /ui/views.js: -------------------------------------------------------------------------------- 1 | module.exports = api => { 2 | api.addView({ 3 | id: 'org.akryum.vue-apollo.apollo', 4 | name: 'org.akryum.vue-apollo.routes.apollo', 5 | tooltip: 'Apollo GraphQL', 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/type-defs.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | export default fs.readFileSync(path.resolve(__dirname, './schema.graphql'), { encoding: 'utf8' }) 5 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/examples/src/graphql/AddMessage.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | mutation addMessage ($input: MessageInput!) { 4 | addMessage (input: $input) { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /client-addon/src/components/ApolloView.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /generator/templates/api-server/examples/apollo-server/server.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import express from 'express' 3 | 4 | export default app => { 5 | app.use('/files', express.static(path.resolve(__dirname, '../live/uploads'))) 6 | } 7 | -------------------------------------------------------------------------------- /client-addon/vue.config.js: -------------------------------------------------------------------------------- 1 | const { clientAddonConfig } = require('@vue/cli-ui') 2 | 3 | module.exports = { 4 | ...clientAddonConfig({ 5 | id: 'vue-apollo', 6 | port: 8043, 7 | }), 8 | outputDir: '../client-addon-dist', 9 | } 10 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/mocks.js: -------------------------------------------------------------------------------- 1 | // Enable mocking in vue.config.js with `"pluginOptions": { "enableMocks": true }` 2 | // Customize mocking: https://www.apollographql.com/docs/graphql-tools/mocking.html#Customizing-mocks 3 | export default { 4 | // Mock resolvers here 5 | } 6 | -------------------------------------------------------------------------------- /client-addon/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /docs/guide/engine.md: -------------------------------------------------------------------------------- 1 | # Apollo Engine 2 | 3 | [Apollo Engine](https://www.apollographql.com/engine) is a commercial product from Apollo. It enables lots of additional features like monitoring, error reporting, caching and query persisting. 4 | 5 | Create a key at [engine.apollographql.com](https://engine.apollographql.com) (it's free!). 6 | -------------------------------------------------------------------------------- /docs/.vuepress/style.styl: -------------------------------------------------------------------------------- 1 | .home .hero img 2 | max-width 80vw 3 | 4 | .gold-sponsor, 5 | .silver-sponsor, 6 | .bronze-sponsor 7 | margin 0 20px 8 | 9 | .gold-sponsor 10 | max-width 400px !important 11 | 12 | .silver-sponsor 13 | max-width 200px !important 14 | 15 | .bronze-sponsor 16 | max-width 100px !important 17 | max-height 50px !important 18 | -------------------------------------------------------------------------------- /docs/guide/express-middleware.md: -------------------------------------------------------------------------------- 1 | # Express middleware 2 | 3 | If you need to add express middlewares into the GraphQL server, you can create a `./apollo-server/server.js` file: 4 | 5 | ```js 6 | import path from 'path' 7 | import express from 'express' 8 | 9 | const distPath = path.resolve(__dirname, '../../dist') 10 | 11 | export default app => { 12 | app.use(express.static(distPath)) 13 | } 14 | ``` 15 | -------------------------------------------------------------------------------- /utils/load.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-global-assign 2 | require = require('esm')(module) 3 | 4 | module.exports = function (options) { 5 | if (options.typescript) require('ts-node/register/transpile-only') 6 | 7 | return { 8 | load, 9 | } 10 | } 11 | 12 | function load (file) { 13 | const module = require(file) 14 | if (module.default) { 15 | return module.default 16 | } 17 | return module 18 | } 19 | -------------------------------------------------------------------------------- /docs/guide/manual-changes.md: -------------------------------------------------------------------------------- 1 | # Manual code changes 2 | 3 | In case the plugin isn't able to modify the file containing the root Vue instance: 4 | 5 | Import the provider: 6 | 7 | ```js 8 | import { createProvider } from './vue-apollo' 9 | ``` 10 | 11 | Then in the root instance, set the `apolloProvider` option: 12 | 13 | ```js 14 | new Vue({ 15 | el: '#app', 16 | // Add this line 17 | apolloProvider: createProvider(), 18 | }) 19 | ``` 20 | -------------------------------------------------------------------------------- /generator/templates/api-server/examples/apollo-server/utils/db.js: -------------------------------------------------------------------------------- 1 | import Lowdb from 'lowdb' 2 | import FileSync from 'lowdb/adapters/FileSync' 3 | import mkdirp from 'mkdirp' 4 | import { resolve } from 'path' 5 | 6 | mkdirp(resolve(__dirname, '../../live')) 7 | 8 | export const db = new Lowdb(new FileSync(resolve(__dirname, '../../live/db.json'))) 9 | 10 | // Seed an empty DB 11 | db.defaults({ 12 | messages: [], 13 | uploads: [], 14 | }).write() 15 | -------------------------------------------------------------------------------- /client-addon/src/utils/math.js: -------------------------------------------------------------------------------- 1 | export function round (value) { 2 | return Math.round(value * 1000) / 1000 3 | } 4 | 5 | export function formatNumber (value) { 6 | if (Number.isNaN(value) || value == null) return 0 7 | let result = value 8 | const units = ['B', 'M', 'k'] 9 | const l = units.length 10 | for (let i = 0; i < l; i++) { 11 | const j = l - i 12 | if (result > 1000 ** j) { 13 | result /= 1000 ** j 14 | return `${round(result)}${units[i]}` 15 | } 16 | } 17 | return round(result) 18 | } 19 | -------------------------------------------------------------------------------- /docs/guide/mocks.md: -------------------------------------------------------------------------------- 1 | # Mocks 2 | 3 | You can enable automatic mocking on the GraphQL API Server. It can be [customized](https://www.apollographql.com/docs/graphql-tools/mocking.html#Customizing-mocks) in the `./apollo-server/mocks.js` file generated in your project. 4 | 5 | Enable it in `vue.config.js`: 6 | 7 | ``` js 8 | module.exports = { 9 | // Other options... 10 | pluginOptions: { 11 | // Apollo-related options 12 | apollo: { 13 | // Enable automatic mocking 14 | enableMocks: true, 15 | }, 16 | }, 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/context.js: -------------------------------------------------------------------------------- 1 | <% if (addExamples) { _%> 2 | import { db } from './utils/db' 3 | import { processUpload } from './utils/upload' 4 | <%_ } %> 5 | 6 | // Context passed to all resolvers (third argument) 7 | // req => Query 8 | // connection => Subscription 9 | // eslint-disable-next-line no-unused-vars 10 | export default ({ req, connection }) => { 11 | return { 12 | <% if (addExamples) { _%> 13 | db, 14 | processUpload, 15 | <%_ } else { %> 16 | // Put objects here 17 | <%_ } %> 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ui/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = api => { 4 | if (process.env.VUE_CLI_PLUGIN_DEV) { 5 | api.addClientAddon({ 6 | id: 'org.akryum.vue-apollo.client-addon', 7 | url: 'http://localhost:8043/index.js', 8 | }) 9 | } else { 10 | api.addClientAddon({ 11 | id: 'org.akryum.vue-apollo.client-addon', 12 | path: path.resolve(__dirname, '../client-addon-dist'), 13 | }) 14 | } 15 | 16 | require('./configs')(api) 17 | require('./tasks')(api) 18 | require('./widgets')(api) 19 | // require('./views')(api) 20 | } 21 | -------------------------------------------------------------------------------- /client-addon/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard', 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'warning' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 13 | 'comma-dangle': ['error', 'always-multiline'], 14 | }, 15 | parserOptions: { 16 | parser: 'babel-eslint', 17 | }, 18 | globals: { 19 | 'ClientAddonApi': false, 20 | 'mapSharedData': false, 21 | 'Vue': false, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /client-addon/src/main.js: -------------------------------------------------------------------------------- 1 | import GraphqlPlayground from './components/GraphqlPlayground.vue' 2 | import EngineKeyMetrics from './components/widgets/EngineKeyMetrics.vue' 3 | 4 | import ApolloView from './components/ApolloView.vue' 5 | 6 | ClientAddonApi.component('org.akryum.vue-apollo.components.playground', GraphqlPlayground) 7 | ClientAddonApi.component('org.akryum.vue-apollo.components.widgets.engine-key-metrics', EngineKeyMetrics) 8 | 9 | ClientAddonApi.addRoutes('org.akryum.vue-apollo', [ 10 | { 11 | path: '', 12 | name: 'org.akryum.vue-apollo.routes.apollo', 13 | component: ApolloView, 14 | }, 15 | ]) 16 | -------------------------------------------------------------------------------- /docs/guide/injected-commands.md: -------------------------------------------------------------------------------- 1 | # Injected Commands 2 | 3 | - **`vue-cli-service apollo:watch`** 4 | 5 | Run the GraphQL API server with info from `./apollo-server` and watch the files to restart itself automatically. 6 | 7 | - **`vue-cli-service apollo:run`** 8 | 9 | Run the GraphQL API server with info from `./apollo-server` once. 10 | 11 | - **`vue-cli-service apollo:schema:generate`** 12 | 13 | (WIP) Generates GraphQL and JSON files from the running API, useful for integration with other tools like IDE plugins. 14 | 15 | - **`vue-cli-service apollo:schema:publish`** 16 | 17 | Publish schema to Apollo Engine 18 | -------------------------------------------------------------------------------- /utils/check-schema.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ endpoint, key, tag, engineEndpoint }) => { 2 | const execa = require('execa') 3 | const { logWithSpinner, stopSpinner, done } = require('@vue/cli-shared-utils') 4 | 5 | logWithSpinner('📡', 'Comparing schema from Engine...') 6 | await execa('apollo', [ 7 | 'client:check', 8 | `--endpoint=${endpoint}`, 9 | `--key=${key}`, 10 | ...(tag ? [`--tag=${tag}`] : []), 11 | ...(engineEndpoint ? [`--engine=${engineEndpoint}`] : []), 12 | ], { 13 | stdio: ['inherit', 'inherit', 'inherit'], 14 | }) 15 | stopSpinner() 16 | done('Checked schema on Engine') 17 | } 18 | -------------------------------------------------------------------------------- /utils/publish-schema.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ endpoint, key, tag, engineEndpoint }) => { 2 | const execa = require('execa') 3 | const { logWithSpinner, stopSpinner, done } = require('@vue/cli-shared-utils') 4 | 5 | logWithSpinner('⬆️', 'Publishing schema to Engine...') 6 | await execa('apollo', [ 7 | 'schema:publish', 8 | `--endpoint=${endpoint}`, 9 | `--key=${key}`, 10 | ...(tag ? [`--tag=${tag}`] : []), 11 | ...(engineEndpoint ? [`--engine=${engineEndpoint}`] : []), 12 | ], { 13 | stdio: ['inherit', 'inherit', 'inherit'], 14 | }) 15 | stopSpinner() 16 | done('Published schema to Engine') 17 | } 18 | -------------------------------------------------------------------------------- /generator/templates/vue-apollo/default/apollo.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | // Load .env files 4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env') 5 | const env = loadEnv([ 6 | path.resolve(__dirname, '.env'), 7 | path.resolve(__dirname, '.env.local') 8 | ]) 9 | 10 | module.exports = { 11 | client: { 12 | service: env.VUE_APP_APOLLO_ENGINE_SERVICE, 13 | includes: ['src/**/*.{js,jsx,ts,tsx,vue,gql}'] 14 | }, 15 | service: { 16 | name: env.VUE_APP_APOLLO_ENGINE_SERVICE, 17 | localSchemaFile: path.resolve(__dirname, './node_modules/.temp/graphql/schema.json') 18 | }, 19 | engine: { 20 | endpoint: process.env.APOLLO_ENGINE_API_ENDPOINT, 21 | apiKey: env.VUE_APP_APOLLO_ENGINE_KEY 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client-addon/src/components/widgets/EngineKeyMetricsQueries.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | -------------------------------------------------------------------------------- /client-addon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-addon", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@vue/cli-ui": "^3.0.0", 12 | "@vue/ui": "^0.5.6", 13 | "core-js": "^3.1.2", 14 | "d3": "^5.7.0", 15 | "vue": "^2.5.16" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "^4.0.4", 19 | "@vue/cli-plugin-eslint": "^4.0.4", 20 | "@vue/cli-service": "^4.0.4", 21 | "@vue/cli-ui": "^3.0.0", 22 | "@vue/eslint-config-standard": "^4.0.0", 23 | "eslint": "^4.19.1", 24 | "eslint-plugin-vue": "^5.2.3", 25 | "stylus": "^0.54.5", 26 | "stylus-loader": "^3.0.2", 27 | "vue-template-compiler": "^2.5.16" 28 | }, 29 | "browserslist": [ 30 | "> 1%", 31 | "last 2 versions" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /screenshot.png 4 | actionText: Get Started → 5 | actionLink: /guide/ 6 | features: 7 | - title: Auto-pilot 8 | details: Automatically integrate vue-apollo into your Vue app! 9 | - title: Builtin Apollo client config 10 | details: Get started with a zero-config, customizable & upgradable Apollo client 11 | - title: Embedded Apollo Server 12 | details: Create a fullstack GraphQL app in minutes! Supports websocket subscriptions and more! 13 | footer: LICENCE MIT - Created by Guillaume CHAU (@Akryum) 14 | --- 15 | 16 |

17 | 18 | Become a Patreon 19 | 20 |

21 | 22 | ## Sponsors 23 | 24 | [![sponsors logos](https://guillaume-chau.info/sponsors.png)](https://guillaume-chau.info/sponsors) 25 | 26 | ## Quick Start 27 | 28 | ```bash 29 | vue add apollo 30 | ``` 31 | -------------------------------------------------------------------------------- /utils/load-env.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | exports.loadEnv = (paths) => paths.reduce((res, file) => { 4 | if (fs.existsSync(file)) { 5 | Object.assign(res, parse(fs.readFileSync(file, 'utf-8'))) 6 | } 7 | return res 8 | }, {}) 9 | 10 | function parse (src) { 11 | const res = {} 12 | src.split('\n').forEach(line => { 13 | // matching "KEY' and 'VAL' in 'KEY=VAL' 14 | const keyValueArr = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/) 15 | // matched? 16 | if (keyValueArr != null) { 17 | const key = keyValueArr[1] 18 | let value = keyValueArr[2] || '' 19 | 20 | // expand newlines in quoted values 21 | const len = value ? value.length : 0 22 | if (len > 0 && value.charAt(0) === '"' && value.charAt(len - 1) === '"') { 23 | value = value.replace(/\\n/gm, '\n') 24 | } 25 | 26 | // remove any surrounding quotes and extra spaces 27 | value = value.replace(/(^['"]|['"]$)/g, '').trim() 28 | 29 | res[key] = value 30 | } 31 | }) 32 | return res 33 | } 34 | -------------------------------------------------------------------------------- /operations/engine/key-metrics/p95-time.js: -------------------------------------------------------------------------------- 1 | const gql = require('graphql-tag') 2 | 3 | module.exports = gql` 4 | query p95TimeKeyMetrics( 5 | $serviceId: ID! 6 | $timeFrom: Timestamp! 7 | $timeTo: Timestamp 8 | $resolution: Resolution 9 | $filter: ServiceQueryStatsFilter 10 | ) { 11 | service(id: $serviceId) { 12 | id 13 | name 14 | stats(from: $timeFrom, to: $timeTo, resolution: $resolution) { 15 | globalStats: queryStats( 16 | filter: $filter 17 | ) { 18 | timestamp 19 | metrics { 20 | totalLatencyHistogram { 21 | p95Time: durationMs(percentile: 0.95) 22 | } 23 | } 24 | } 25 | queriesStats: queryStats( 26 | limit: 4 27 | filter: $filter 28 | ) { 29 | timestamp 30 | group: groupBy { 31 | queryId 32 | queryName 33 | querySignature 34 | } 35 | metrics { 36 | totalLatencyHistogram { 37 | p95Time: durationMs(percentile: 0.95) 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | ` 45 | -------------------------------------------------------------------------------- /operations/engine/key-metrics/request-rate.js: -------------------------------------------------------------------------------- 1 | const gql = require('graphql-tag') 2 | 3 | module.exports = gql` 4 | query requestRateKeyMetrics( 5 | $serviceId: ID! 6 | $timeFrom: Timestamp! 7 | $timeTo: Timestamp 8 | $resolution: Resolution 9 | $filter: ServiceQueryStatsFilter 10 | ) { 11 | service(id: $serviceId) { 12 | id 13 | name 14 | stats(from: $timeFrom, to: $timeTo, resolution: $resolution) { 15 | globalStats: queryStats( 16 | filter: $filter 17 | ) { 18 | timestamp 19 | metrics { 20 | uncachedRequestsCount 21 | cachedRequestsCount 22 | } 23 | } 24 | queriesStats: queryStats( 25 | limit: 4 26 | orderBy: [{ column: UNCACHED_REQUESTS_COUNT, direction: DESCENDING }] 27 | filter: $filter 28 | ) { 29 | timestamp 30 | group: groupBy { 31 | queryId 32 | queryName 33 | querySignature 34 | } 35 | metrics { 36 | uncachedRequestsCount 37 | cachedRequestsCount 38 | } 39 | } 40 | } 41 | } 42 | } 43 | ` 44 | -------------------------------------------------------------------------------- /utils/engine-api.js: -------------------------------------------------------------------------------- 1 | const { createHttpLink } = require('apollo-link-http') 2 | const fetch = require('node-fetch') 3 | const { toPromise, execute } = require('apollo-link') 4 | const { print } = require('graphql') 5 | 6 | const ENGINE_ENDPOINT = process.env.APOLLO_ENGINE_API_ENDPOINT || 'https://engine-graphql.apollographql.com/api/graphql/' 7 | 8 | const engineLink = createHttpLink({ 9 | uri: ENGINE_ENDPOINT, 10 | fetch, 11 | }) 12 | 13 | exports.execute = async ({ query, variables, key }) => { 14 | const response = await toPromise( 15 | execute(engineLink, { 16 | query, 17 | variables, 18 | context: { 19 | headers: { 20 | 'X-Api-Key': key, 21 | uri: ENGINE_ENDPOINT, 22 | }, 23 | }, 24 | }), 25 | ) 26 | if (process.env.VUE_APP_CLI_UI_DEBUG) { 27 | console.log(`${ENGINE_ENDPOINT}\n`, print(query), `\nKey: ${key}`, '\nVariables:\n', variables, '\nResponse:\n', response) 28 | } 29 | if (response.errors) { 30 | const error = new Error('Errors were returned from API') 31 | error.response = response 32 | console.log(response.errors) 33 | throw error 34 | } 35 | return response 36 | } 37 | -------------------------------------------------------------------------------- /generator/templates/api-server/examples/apollo-server/utils/upload.js: -------------------------------------------------------------------------------- 1 | import { createWriteStream } from 'fs' 2 | import { resolve } from 'path' 3 | import { sync } from 'mkdirp' 4 | import { generate } from 'shortid' 5 | import { db } from './db' 6 | 7 | const uploadDir = resolve(__dirname, '../../live/uploads') 8 | 9 | // Ensure upload directory exists 10 | sync(uploadDir) 11 | 12 | const storeUpload = async ({ stream, filename }) => { 13 | const id = generate() 14 | const file = `${id}-${filename}` 15 | const path = `${uploadDir}/${file}` 16 | const urlPath = `files/${file}` 17 | 18 | return new Promise((resolve, reject) => 19 | stream 20 | .pipe(createWriteStream(path)) 21 | .on('finish', () => resolve({ id, path: urlPath })) 22 | .on('error', reject), 23 | ) 24 | } 25 | 26 | const recordFile = file => 27 | db 28 | .get('uploads') 29 | .push(file) 30 | .last() 31 | .write() 32 | 33 | export async function processUpload (file) { 34 | const { stream, filename, mimetype, encoding } = await file 35 | const { id, path } = await storeUpload({ stream, filename }) 36 | return recordFile({ id, filename, mimetype, encoding, path }) 37 | } 38 | -------------------------------------------------------------------------------- /docs/guide/client-state.md: -------------------------------------------------------------------------------- 1 | # Client state 2 | 3 | You can use [local state](https://www.apollographql.com/docs/tutorial/local-state/) for client-only local data with the related options of `createApolloClient`: 4 | 5 | ```js 6 | import gql from 'graphql-tag' 7 | import { createApolloClient } from 'vue-cli-plugin-apollo/graphql-client' 8 | 9 | const options = { 10 | // ... 11 | 12 | typeDefs: gql` 13 | type Query { 14 | connected: Boolean! 15 | } 16 | `, 17 | resolvers: { 18 | Mutation: { 19 | connectedSet: (root, { value }, { cache }) => { 20 | const data = { 21 | connected: value, 22 | } 23 | cache.writeData({ data }) 24 | }, 25 | }, 26 | }, 27 | onCacheInit: cache => { 28 | const data = { 29 | connected: false, 30 | } 31 | cache.writeData({ data }) 32 | }, 33 | } 34 | 35 | const { apolloClient } = createApolloClient(options) 36 | ``` 37 | 38 | Then you need to use the `@client` directive: 39 | 40 | ```graphql 41 | query isConnected { 42 | connected @client 43 | } 44 | ``` 45 | 46 | ```graphql 47 | mutation setConnected ($value: Boolean!) { 48 | connectedSet (value: $value) @client 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/guide/server.md: -------------------------------------------------------------------------------- 1 | # Server Usage 2 | 3 | If you enabled the GraphQL API Server, start it alongside the client: 4 | 5 | ``` 6 | npm run apollo 7 | ``` 8 | 9 | You can edit the files generated in the `./apollo-server` folder: 10 | 11 | - `schema.graphql` contains the Schema written with the [schema definition language](https://github.com/facebook/graphql/blob/master/spec/Section%203%20--%20Type%20System.md). 12 | - `resolvers.js` declares the [Apollo resolvers](https://www.apollographql.com/docs/graphql-tools/resolvers.html). 13 | - `context.js` allows injecting a context object into all the resolvers (third argument). 14 | - `mocks.js` defines the custom resolvers used for mocking ([more info](https://www.apollographql.com/docs/graphql-tools/mocking.html#Customizing-mocks)). 15 | - `directives.js` defines the custom schema directives ([more info](https://www.apollographql.com/docs/graphql-tools/schema-directives.html))). 16 | 17 | The server will be automatically restarted when a change is detected. 18 | 19 | To run the server only once, use this command: 20 | 21 | ``` 22 | npm run run-graphql-api 23 | ``` 24 | 25 | **Updating `vue-cli-plugin-apollo` will also update the GraphQL Server service :+1:** 26 | -------------------------------------------------------------------------------- /operations/engine/key-metrics/error-percentage.js: -------------------------------------------------------------------------------- 1 | const gql = require('graphql-tag') 2 | 3 | module.exports = gql` 4 | query errorPercentageKeyMetrics( 5 | $serviceId: ID! 6 | $timeFrom: Timestamp! 7 | $timeTo: Timestamp 8 | $resolution: Resolution 9 | $filter: ServiceQueryStatsFilter 10 | ) { 11 | service(id: $serviceId) { 12 | id 13 | name 14 | stats(from: $timeFrom, to: $timeTo, resolution: $resolution) { 15 | globalStats: queryStats( 16 | filter: $filter 17 | ) { 18 | timestamp 19 | metrics { 20 | cachedRequestsCount 21 | uncachedRequestsCount 22 | requestsWithErrorsCount 23 | } 24 | } 25 | queriesStats: queryStats( 26 | limit: 4 27 | orderBy: [{ column: REQUESTS_WITH_ERRORS_COUNT, direction: DESCENDING }] 28 | filter: $filter 29 | ) { 30 | timestamp 31 | group: groupBy { 32 | queryId 33 | queryName 34 | querySignature 35 | } 36 | metrics { 37 | cachedRequestsCount 38 | uncachedRequestsCount 39 | requestsWithErrorsCount 40 | } 41 | } 42 | } 43 | } 44 | } 45 | ` 46 | -------------------------------------------------------------------------------- /docs/guide/env.md: -------------------------------------------------------------------------------- 1 | # Env variables 2 | 3 | - **`VUE_APP_GRAPHQL_HTTP`** 4 | 5 | The url to the graphql HTTP endpoint, default: `http://localhost:4000` 6 | 7 | - **`VUE_APP_GRAPHQL_WS`** 8 | 9 | The url to the graphql Websockets endpoint for subscriptions, default: `ws://localhost:4000` 10 | 11 | ## With the GraphQL server enabled 12 | 13 | - **`VUE_APP_GRAPHQL_HOST`** 14 | 15 | Hostname of GraphQL API Server, default: `localhost` 16 | 17 | - **`VUE_APP_GRAPHQL_PATH`** 18 | 19 | Path on which to serve graphQL, defaultL `/graphql` 20 | 21 | - **`VUE_APP_GRAPHQL_PORT`** 22 | 23 | Port of the GraphQL API Server, default: `4000` 24 | 25 | - **`VUE_APP_APOLLO_ENGINE_KEY`** 26 | 27 | API key for [Apollo Engine](https://engine.apollographql.com) 28 | 29 | - **`VUE_APP_APOLLO_ENGINE_TAG`** 30 | 31 | Queries made to the API will be marked with this Schema Tag. Useful for segmenting queries (for example 'test', 'staging', 'prod'). 32 | 33 | - **`VUE_APP_GRAPHQL_SUBSCRIPTIONS_PATH`** 34 | 35 | Subscriptions path, default: `/graphql` 36 | 37 | ## Advanced 38 | 39 | - **`APOLLO_ENGINE_API_ENDPOINT`** 40 | 41 | Endpoint to use to the Engine requests. 42 | 43 | - **`APOLLO_ENGINE_FRONTEND`** 44 | 45 | URL to the Engine website. 46 | -------------------------------------------------------------------------------- /docs/guide/auth.md: -------------------------------------------------------------------------------- 1 | # Authorization Header 2 | 3 | By default, `createApolloClient` will retrieve the `Authorization` header value from `localStorage`. You can override this behavior with the `getAuth` option: 4 | 5 | ```js 6 | const options = { 7 | // ... 8 | 9 | getAuth: (tokenName) => getUserToken(), 10 | } 11 | 12 | const { apolloClient } = createApolloClient(options) 13 | ``` 14 | 15 | If you use cookies, you can return `undefined`. 16 | 17 | Example `apolloserver/context.js` that validates the token and set `userId` on resolvers context: 18 | 19 | ```js 20 | import users from './connectors/users' 21 | 22 | // Context passed to all resolvers (third argument) 23 | // req => Query 24 | // connection => Subscription 25 | // eslint-disable-next-line no-unused-vars 26 | export default ({ req, connection }) => { 27 | // If the websocket context was already resolved 28 | if (connection && connection.context) return connection.context 29 | 30 | let token 31 | // HTTP 32 | if (req) token = req.get('Authorization') 33 | // Websocket 34 | if (connection) token = connection.authorization 35 | 36 | // User validation 37 | let userId 38 | if (token && users.validateToken(token)) { 39 | userId = token.userId 40 | } 41 | 42 | return { 43 | token, 44 | userId, 45 | } 46 | } 47 | ``` -------------------------------------------------------------------------------- /docs/guide/directives.md: -------------------------------------------------------------------------------- 1 | # Directives 2 | 3 | A GraphQL directive is an annotation to either a GraphQL schema or a GraphQL document (for queries). It allows to modify the behavior of the API in a declaractive way. 4 | 5 | The usage syntax is with the 'at' character: `@myDirective`. 6 | 7 | [More documentation](https://www.apollographql.com/docs/graphql-tools/schema-directives.html) 8 | 9 | You can add custom GraphQL directives in the `./apollo-server/directives.js` file. 10 | 11 | ```js 12 | export default { 13 | // Now you can use '@private' in the schema 14 | private: PrivateDirective 15 | } 16 | ``` 17 | 18 | Here is an example directive: 19 | 20 | ```js 21 | const { SchemaDirectiveVisitor } = require('graphql-tools') 22 | const { defaultFieldResolver } = require('graphql') 23 | 24 | module.exports = class PrivateDirective extends SchemaDirectiveVisitor { 25 | visitFieldDefinition (field) { 26 | const { resolve = defaultFieldResolver } = field 27 | field.resolve = (root, args, context, info) => { 28 | if (!context.userId) throw new Error('Unauthorized') 29 | return resolve(root, args, context, info) 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | On the GraphQL server schema, use the directive like this: 36 | 37 | ```grahpql 38 | type Query { 39 | messages: [Message] @private 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /client-addon/src/components/widgets/EngineKeyMetricsQuery.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | 40 | 66 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ::: warning 4 | This plugin is intended to be used in a project created with Vue CLI 3. 5 | ::: 6 | 7 | Add the plugin to the project: 8 | 9 | ```bash 10 | vue add apollo 11 | ``` 12 | 13 | ::: tip 14 | An example `ApolloExample.vue` component alongside some GraphQL query files will be added into your sources if you chose to include the examples. 15 | ::: 16 | 17 | Start your app: 18 | 19 | ``` 20 | npm run serve 21 | ``` 22 | 23 | [Recommended VS Code extension](https://github.com/prismagraphql/vscode-graphql) 24 | 25 | **Updating `vue-cli-plugin-apollo` will also update both Apollo Client and its configuration for you! :+1:** 26 | 27 | Read the [vue-apollo doc](https://github.com/Akryum/vue-apollo). 28 | 29 | ## Sponsors 30 | 31 | [![sponsors logos](https://guillaume-chau.info/sponsors.png)](https://guillaume-chau.info/sponsors) 32 | 33 | ## Become a sponsor 34 | 35 | Is your company using vue-apollo or vue-cli-plugin-apollo to build awesome apps? Join the other patrons and become a sponsor to add your logo on this documentation! Supporting me on Patreon allows me to work less for a job and to work more on Free Open Source Software such as vue-apollo! Thank you! 36 | 37 |

38 | 39 | Become a Patreon 40 | 41 |

42 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Use only this configuration 3 | root: true, 4 | // File parser 5 | parser: 'vue-eslint-parser', 6 | parserOptions: { 7 | // Use babel-eslint for JavaScript 8 | parser: 'babel-eslint', 9 | ecmaVersion: 2017, 10 | // With import/export syntax 11 | sourceType: 'module', 12 | }, 13 | // Environment global objects 14 | env: { 15 | browser: true, 16 | es6: true, 17 | jest: true, 18 | }, 19 | extends: [ 20 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 21 | 'standard', 22 | // https://github.com/vuejs/eslint-plugin-vue#priority-c-recommended-minimizing-arbitrary-choices-and-cognitive-overhead 23 | 'plugin:vue/recommended', 24 | ], 25 | rules: { 26 | 'comma-dangle': ['error', 'always-multiline'], 27 | 28 | // Vue 29 | 30 | // Error 31 | 'vue/html-closing-bracket-newline': ['error', { 32 | singleline: 'never', 33 | multiline: 'always', 34 | }], 35 | 'vue/html-closing-bracket-spacing': ['error', { 36 | startTag: 'never', 37 | endTag: 'never', 38 | selfClosingTag: 'never', 39 | }], 40 | 'vue/max-attributes-per-line': ['error', { 41 | singleline: 2, 42 | multiline: { 43 | max: 1, 44 | allowFirstLine: false, 45 | }, 46 | }], 47 | // Warn 48 | 'vue/require-default-prop': 'warn', 49 | 'vue/require-prop-types': 'warn', 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/schema.graphql: -------------------------------------------------------------------------------- 1 | "Included scalars" 2 | scalar JSON 3 | scalar Upload 4 | 5 | <% if (addExamples) { _%> 6 | "It will increment!" 7 | type Counter { 8 | "Number of increments" 9 | count: Int! 10 | "Full message for testing" 11 | countStr: String 12 | } 13 | 14 | "A text message send by users" 15 | type Message { 16 | id: ID! 17 | "Message content" 18 | text: String! 19 | } 20 | 21 | "Input from user to create a message" 22 | input MessageInput { 23 | "Message content" 24 | text: String! 25 | } 26 | 27 | type File { 28 | id: ID! 29 | path: String! 30 | filename: String! 31 | mimetype: String! 32 | encoding: String! 33 | } 34 | <%_ } %> 35 | 36 | type Query { 37 | "Test query with a parameter" 38 | hello(name: String): String! 39 | <% if (addExamples) { _%> 40 | "List of messages sent by users" 41 | messages: [Message] 42 | uploads: [File] 43 | <%_ } %> 44 | } 45 | 46 | type Mutation { 47 | myMutation: String! 48 | <% if (addExamples) { _%> 49 | "Add a message and publish it on 'messages' subscription channel" 50 | addMessage (input: MessageInput!): Message! 51 | singleUpload (file: Upload!): File! 52 | multipleUpload (files: [Upload!]!): [File!]! 53 | <%_ } %> 54 | } 55 | 56 | type Subscription { 57 | mySub: String! 58 | <% if (addExamples) { _%> 59 | "This will update every 2 seconds" 60 | counter: Counter! 61 | "When a new message is added" 62 | messageAdded: Message! 63 | <%_ } %> 64 | } 65 | -------------------------------------------------------------------------------- /utils/generate-schema.js: -------------------------------------------------------------------------------- 1 | module.exports = async (options) => { 2 | const path = require('path') 3 | const fs = require('fs-extra') 4 | const { logWithSpinner, stopSpinner, done } = require('@vue/cli-shared-utils') 5 | const { graphql, getIntrospectionQuery, printSchema } = require('graphql') 6 | const { makeExecutableSchema } = require('graphql-tools') 7 | const { load } = require('./load')(options) 8 | 9 | // JS Schema 10 | const typeDefs = load(options.paths.typeDefs) 11 | const resolvers = load(options.paths.resolvers) 12 | const schemaDirectives = load(options.paths.directives) 13 | const schema = makeExecutableSchema({ 14 | typeDefs, 15 | resolvers, 16 | schemaDirectives, 17 | allowUndefinedInResolve: true, 18 | }) 19 | 20 | // JSON schema 21 | logWithSpinner('📄', 'Generating JSON file...') 22 | await fs.ensureDir(path.dirname(options.jsonOutput)) 23 | const result = await graphql(schema, getIntrospectionQuery()) 24 | if (result.errors) { 25 | throw new Error(`Generating JSON failed: ${result.errors.map(e => e.message).join(' | ')}`) 26 | } 27 | fs.writeFileSync( 28 | options.jsonOutput, 29 | JSON.stringify(result, null, 2), 30 | ) 31 | stopSpinner() 32 | done(`Generated ${options.jsonOutput}`) 33 | 34 | // GraphQL schema 35 | logWithSpinner('📄', 'Generating GraphQL file...') 36 | await fs.ensureDir(path.dirname(options.graphqlOutput)) 37 | fs.writeFileSync( 38 | options.graphqlOutput, 39 | printSchema(schema), 40 | ) 41 | stopSpinner() 42 | done(`Generated ${options.graphqlOutput}`) 43 | } 44 | -------------------------------------------------------------------------------- /docs/guide/server-prod.md: -------------------------------------------------------------------------------- 1 | # Running the GraphQL server in production 2 | 3 | ## Production app 4 | 5 | ``` 6 | cross-env NODE_ENV=production yarn run apollo:run --mode production 7 | ``` 8 | 9 | If you deploy on now.sh, add the following script to your `package.json`: 10 | 11 | ```json 12 | { 13 | "scripts": { 14 | "start": "cross-env NODE_ENV=production yarn run apollo:run --mode production" 15 | } 16 | } 17 | ``` 18 | 19 | ## Library published on npm 20 | 21 | If your project is meant to be used as a package installed from npm, you will need to move `vue-cli-plugin-apollo` from the `devDependencies` field to `dependencies` in your `package.json` file. Then you can run the server: 22 | 23 | ```js 24 | const server = require('vue-cli-plugin-apollo/graphql-server') 25 | 26 | const opts = { 27 | host: 'localhost', 28 | port: 4000, 29 | graphqlPath: '/graphql', 30 | subscriptionsPath: '/graphql', 31 | enableMocks: false, 32 | enableEngine: false, 33 | cors: '*', 34 | timeout: 1000000, 35 | quiet: true, 36 | paths: { 37 | typeDefs: require.resolve('some-folder/apollo-server/type-defs.js'), 38 | resolvers: require.resolve('some-folder/apollo-server/resolvers.js'), 39 | context: require.resolve('some-folder/apollo-server/context.js'), 40 | pubsub: require.resolve('some-folder/apollo-server/pubsub.js'), 41 | server: require.resolve('some-folder/apollo-server/server.js'), 42 | directives: require.resolve('some-folder/apollo-server/directives.js') 43 | dataSources: require.resolve('some-folder/apollo-server/data-sources.js') 44 | } 45 | } 46 | 47 | server(opts, () => { 48 | console.log('Server is running!') 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /client-addon/src/components/SimpleGraph.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 58 | 59 | 80 | -------------------------------------------------------------------------------- /client-addon/src/components/widgets/EngineKeyMetricsP95Time.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 77 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | base: '/', 3 | serviceWorker: true, 4 | head: [ 5 | ['link', { rel: 'icon', href: '/favicon.png' }], 6 | ], 7 | locales: { 8 | '/': { 9 | lang: 'en-US', 10 | title: 'Vue CLI Apollo plugin', 11 | description: '⚡️ Integrate GraphQL in your Vue.js apps!', 12 | }, 13 | }, 14 | themeConfig: { 15 | repo: 'Akryum/vue-cli-plugin-apollo', 16 | docsDir: 'docs', 17 | editLinks: true, 18 | serviceWorker: { 19 | updatePopup: true, 20 | }, 21 | locales: { 22 | '/': { 23 | selectText: 'Languages', 24 | label: 'English', 25 | lastUpdated: 'Last Updated', 26 | nav: [ 27 | { 28 | text: 'Guide', 29 | link: '/guide/', 30 | }, 31 | { 32 | text: 'vue-apollo', 33 | link: 'https://github.com/Akryum/vue-apollo', 34 | }, 35 | { 36 | text: 'Patreon', 37 | link: 'https://www.patreon.com/akryum', 38 | }, 39 | ], 40 | sidebarDepth: 3, 41 | sidebar: { 42 | '/guide/': [ 43 | '', 44 | 'server', 45 | 'injected-commands', 46 | 'env', 47 | 'webpack', 48 | 'manual-changes', 49 | { 50 | title: 'Advanced', 51 | collapsable: false, 52 | children: [ 53 | 'configuration', 54 | 'client-state', 55 | 'auth', 56 | 'mocks', 57 | 'directives', 58 | 'engine', 59 | 'express-middleware', 60 | 'server-prod', 61 | ], 62 | }, 63 | ], 64 | }, 65 | }, 66 | }, 67 | }, 68 | } 69 | -------------------------------------------------------------------------------- /client-addon/src/components/widgets/EngineKeyMetricsRequestRate.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 80 | -------------------------------------------------------------------------------- /client-addon/src/components/widgets/EngineKeyMetricsErrorPercentage.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 86 | -------------------------------------------------------------------------------- /prompts.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | type: 'confirm', 4 | name: 'addExamples', 5 | message: 'Add example code', 6 | description: 'This will generate a component, graphql files and an example schema (if server is added).', 7 | default: false, 8 | }, 9 | { 10 | type: 'confirm', 11 | name: 'addServer', 12 | message: 'Add a GraphQL API Server?', 13 | description: 'Generate GraphQL server files in a `apollo-server` folder.', 14 | group: 'GraphQL Server', 15 | default: false, 16 | }, 17 | { 18 | type: 'confirm', 19 | name: 'addMocking', 20 | message: 'Enable automatic mocking?', 21 | description: 'Missing resolvers will be automatically mocked.', 22 | group: 'GraphQL Server', 23 | default: false, 24 | when: answers => answers.addServer, 25 | }, 26 | { 27 | type: 'confirm', 28 | name: 'addApolloEngine', 29 | message: 'Configure Apollo Engine?', 30 | link: 'http://engine.apollographql.com/', 31 | group: 'GraphQL Server', 32 | default: false, 33 | }, 34 | { 35 | type: 'input', 36 | name: 'apolloEngineService', 37 | message: 'Apollo Service ID (create one at https://engine.apollographql.com):', 38 | group: 'GraphQL Server', 39 | validate: input => !!input, 40 | when: answers => answers.addApolloEngine, 41 | }, 42 | { 43 | type: 'input', 44 | name: 'apolloEngineKey', 45 | message: 'API Key:', 46 | description: 'It should look like this: \'service:name-xxxx:xxxxxxxxxxxxxxxxxxxxxx\'', 47 | group: 'GraphQL Server', 48 | validate: input => !!input, 49 | when: answers => answers.addApolloEngine, 50 | }, 51 | { 52 | type: 'input', 53 | name: 'apolloEngineTag', 54 | message: 'Default Schema Tag:', 55 | description: 'You can have data over multiples tags, which is useful when having several env like staging and production.', 56 | group: 'GraphQL Server', 57 | when: answers => answers.addApolloEngine, 58 | }, 59 | { 60 | type: 'confirm', 61 | name: 'publishSchema', 62 | message: 'Publish schema on Apollo Engine?', 63 | group: 'GraphQL Server', 64 | default: false, 65 | when: answers => answers.addApolloEngine, 66 | }, 67 | ] 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cli-plugin-apollo 2 | 3 | [![npm](https://img.shields.io/npm/v/vue-cli-plugin-apollo.svg) ![npm](https://img.shields.io/npm/dm/vue-cli-plugin-apollo.svg)](https://www.npmjs.com/package/vue-cli-plugin-apollo) 4 | [![vue-cli3](https://img.shields.io/badge/vue--cli-3.x-brightgreen.svg)](https://github.com/vuejs/vue-cli) 5 | [![apollo-2](https://img.shields.io/badge/apollo-2.x-blue.svg)](https://www.apollographql.com/) 6 | 7 | **:rocket: Start building a Vue app with Apollo and GraphQL in 2 minutes!** 8 | 9 | This is a vue-cli 3.x plugin to add Apollo and GraphQL in your Vue project. 10 | 11 |

12 | 13 | Become a Patreon 14 | 15 |

16 | 17 |
18 | 19 |

Documentation

20 | 21 |
22 | 23 | ## Sponsors 24 | 25 | [![sponsors logos](https://guillaume-chau.info/sponsors.png)](https://guillaume-chau.info/sponsors) 26 | 27 |
28 | 29 | ![screenshot](./screenshot.png) 30 | 31 |
32 | 33 | ## :star: Features 34 | 35 | - Automatically integrate [vue-apollo](https://github.com/Akryum/vue-apollo) into your Vue app 36 | - Embed Apollo client config (upgradable and customizable) 37 | - Websockets 38 | - File uploads 39 | - Client state with [apollo-link-state](https://github.com/apollographql/apollo-link-state) 40 | - Included optional Graphql Server (upgradable and customizable): 41 | - Dead simple GraphQL API sources generated into your project (with import/export support) 42 | - Upgradable service running [apollo-server](https://www.apollographql.com/docs/apollo-server/) 43 | - Websocket subscriptions support 44 | - Optional automatic mocking 45 | - [Apollo Engine](https://www.apollographql.com/engine) support 46 | - GraphQL playground integrated in the CLI UI 47 | - Configuration screen in the CLI UI 48 | - Server-Side Rendering with [@akryum/vue-cli-plugin-ssr](https://github.com/Akryum/vue-cli-plugin-ssr) 49 | - Included optional example component with: 50 | - Watched query 51 | - Mutation 52 | - Realtime subscription using Websockets 53 | - Fully working image gallery with image upload 54 | - GraphQL validation using ESLint 55 | -------------------------------------------------------------------------------- /generator/templates/api-server/default/apollo-server/resolvers.js: -------------------------------------------------------------------------------- 1 | import GraphQLJSON from 'graphql-type-json' 2 | <% if (addExamples) { _%> 3 | import shortid from 'shortid' 4 | <%_ } %> 5 | 6 | export default { 7 | JSON: GraphQLJSON, 8 | 9 | <% if (addExamples) { _%> 10 | Counter: { 11 | countStr: counter => `Current count: ${counter.count}`, 12 | }, 13 | <%_ } %> 14 | 15 | Query: { 16 | hello: (root, { name }) => `Hello ${name || 'World'}!`, 17 | <% if (addExamples) { _%> 18 | messages: (root, args, { db }) => db.get('messages').value(), 19 | uploads: (root, args, { db }) => db.get('uploads').value(), 20 | <%_ } %> 21 | }, 22 | 23 | Mutation: { 24 | myMutation: (root, args, context) => { 25 | const message = 'My mutation completed!' 26 | context.pubsub.publish('hey', { mySub: message }) 27 | return message 28 | }, 29 | <% if (addExamples) { _%> 30 | addMessage: (root, { input }, { pubsub, db }) => { 31 | const message = { 32 | id: shortid.generate(), 33 | text: input.text, 34 | } 35 | 36 | db 37 | .get('messages') 38 | .push(message) 39 | .last() 40 | .write() 41 | 42 | pubsub.publish('messages', { messageAdded: message }) 43 | 44 | return message 45 | }, 46 | 47 | singleUpload: (root, { file }, { processUpload }) => processUpload(file), 48 | multipleUpload: (root, { files }, { processUpload }) => Promise.all(files.map(processUpload)), 49 | <%_ } %> 50 | }, 51 | 52 | Subscription: { 53 | mySub: { 54 | subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator('hey'), 55 | }, 56 | <% if (addExamples) { _%> 57 | counter: { 58 | subscribe: (parent, args, { pubsub }) => { 59 | const channel = Math.random().toString(36).substring(2, 15) // random channel name 60 | let count = 0 61 | setInterval(() => pubsub.publish( 62 | channel, 63 | { 64 | // eslint-disable-next-line no-plusplus 65 | counter: { count: count++ }, 66 | } 67 | ), 2000) 68 | return pubsub.asyncIterator(channel) 69 | }, 70 | }, 71 | 72 | messageAdded: { 73 | subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator('messages'), 74 | }, 75 | <%_ } %> 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /docs/guide/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ## createApolloClient options 4 | 5 | ```js 6 | createApolloClient({ 7 | // URL to the HTTP API 8 | httpEndpoint, 9 | // Url to the Websocket API 10 | wsEndpoint: null, 11 | // Token used in localstorage 12 | tokenName: 'apollo-token', 13 | // Enable this if you use Query persisting with Apollo Engine 14 | persisting: false, 15 | // Or, advanced persisting options, see https://github.com/apollographql/apollo-link-persisted-queries#options 16 | // Example: 17 | // persisting: { 18 | // generateHash: query => sha256() 19 | // .update(print(query)) 20 | // .digest('hex'), 21 | //}, 22 | // Is currently Server-Side Rendering or not 23 | ssr: false, 24 | // Only use Websocket for all requests (including queries and mutations) 25 | websocketsOnly: false, 26 | // Custom starting link. 27 | // If you want to replace the default HttpLink, set `defaultHttpLink` to false 28 | link: null, 29 | // Custom pre-auth links 30 | // Useful if you want, for example, to set a custom middleware for refreshing an access token. 31 | preAuthLinks: [], 32 | // If true, add the default HttpLink. 33 | // Disable it if you want to replace it with a terminating link using `link` option. 34 | defaultHttpLink: true, 35 | // Options for the default HttpLink 36 | httpLinkOptions: {}, 37 | // Custom Apollo cache implementation (default is apollo-cache-inmemory) 38 | cache: null, 39 | // Options for the default cache 40 | inMemoryCacheOptions: {}, 41 | // Additional Apollo client options 42 | apollo: {}, 43 | // apollo-link-state options 44 | clientState: null, 45 | // Function returning Authorization header token 46 | getAuth: defaultGetAuth, 47 | }) 48 | ``` 49 | 50 | ## Plugin options 51 | 52 | The GraphQL API Server can be configured via the `pluginOptions` in `vue.config.js`: 53 | 54 | ``` js 55 | module.exports = { 56 | // Other options... 57 | pluginOptions: { 58 | // Apollo-related options 59 | apollo: { 60 | // Enable automatic mocking 61 | enableMocks: true, 62 | // Enable Apollo Engine 63 | enableEngine: true, 64 | // Enable ESLint for `.gql` files 65 | lintGQL: false, 66 | 67 | /* Other options (with default values) */ 68 | 69 | // Base folder for the server source files 70 | serverFolder: './apollo-server', 71 | // Cross-Origin options 72 | cors: '*', 73 | // Requests timeout (ms) 74 | timeout: 120000, 75 | // Integrated apollo engine 76 | integratedEngine: true, 77 | // For enable typescript server files 78 | // if you don't have @vue/cli-plugin-typescript 79 | typescript: true, 80 | // Apollo server options (will be merged with the included default options) 81 | serverOptions: { 82 | // ... 83 | }, 84 | }, 85 | }, 86 | } 87 | ``` 88 | 89 | See [Apollo Server options](https://www.apollographql.com/docs/apollo-server/v2/api/apollo-server.html#constructor-options-lt-ApolloServer-gt). 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli-plugin-apollo", 3 | "version": "0.22.2", 4 | "description": "vue-cli 3 plugin to add Apollo and GraphQL", 5 | "main": "index.js", 6 | "types": "./types.d.ts", 7 | "scripts": { 8 | "dev": "nodemon --exec 'npm run build' --watch graphql-client/src", 9 | "build": "yarn build:graphql-client && yarn build:client-addon", 10 | "build:graphql-client": "babel graphql-client/src --out-dir graphql-client/dist", 11 | "build:client-addon": "cd ./client-addon && yarn build && cd ../", 12 | "prepublishOnly": "npm run test && npm run build", 13 | "test": "npm run test:eslint && cd ./client-addon npm run lint", 14 | "test:eslint": "eslint --ext .js .", 15 | "docs:dev": "vuepress dev docs", 16 | "docs:build": "vuepress build docs" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Akryum/vue-cli-plugin-apollo.git" 21 | }, 22 | "keywords": [ 23 | "vue", 24 | "vue-cli", 25 | "apollo", 26 | "graphql" 27 | ], 28 | "author": "Guillaume Chau ", 29 | "license": "ISC", 30 | "bugs": { 31 | "url": "https://github.com/Akryum/vue-cli-plugin-apollo/issues" 32 | }, 33 | "homepage": "https://github.com/Akryum/vue-cli-plugin-apollo#readme", 34 | "dependencies": { 35 | "apollo": "^2.28.2", 36 | "apollo-cache-inmemory": "^1.6.6", 37 | "apollo-client": "^2.6.10", 38 | "apollo-link": "^1.2.14", 39 | "apollo-link-context": "^1.0.20", 40 | "apollo-link-http": "^1.5.17", 41 | "apollo-link-persisted-queries": "^0.2.2", 42 | "apollo-link-state": "^0.4.2", 43 | "apollo-link-ws": "^1.0.20", 44 | "apollo-server-express": "^2.14.2", 45 | "apollo-upload-client": "^13.0.0", 46 | "apollo-utilities": "^1.3.4", 47 | "chalk": "^4.0.0", 48 | "deepmerge": "^4.2.2", 49 | "dotenv": "^8.2.0", 50 | "esm": "^3.2.25", 51 | "execa": "^4.0.2", 52 | "express": "^4.17.1", 53 | "fs-extra": "^9.0.1", 54 | "graphql": "^15.1.0", 55 | "graphql-subscriptions": "^1.1.0", 56 | "graphql-tag": "^2.10.3", 57 | "graphql-tools": "^6.0.9", 58 | "node-fetch": "^2.6.0", 59 | "nodemon": "^2.0.4", 60 | "subscriptions-transport-ws": "^0.9.16", 61 | "ts-node": "^8.10.2" 62 | }, 63 | "devDependencies": { 64 | "@babel/cli": "^7.4.4", 65 | "@babel/core": "^7.4.5", 66 | "@babel/preset-env": "^7.4.5", 67 | "babel-eslint": "^10.0.1", 68 | "eslint": "^7.2.0", 69 | "eslint-config-standard": "^14.0.0", 70 | "eslint-plugin-import": "^2.8.0", 71 | "eslint-plugin-node": "^11.0.0", 72 | "eslint-plugin-promise": "^4.0.1", 73 | "eslint-plugin-standard": "^4.0.0", 74 | "eslint-plugin-vue": "^6.0.0", 75 | "vuepress": "^0.14.8" 76 | }, 77 | "peerDependencies": { 78 | "@vue/cli-shared-utils": "^3.0.0 || ^4.0.0-0", 79 | "typescript": ">=2.0" 80 | }, 81 | "peerDependenciesMeta": { 82 | "typescript": { 83 | "optional": true 84 | } 85 | }, 86 | "engines": { 87 | "node": ">=10" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /client-addon/src/components/GraphqlPlayground.vue: -------------------------------------------------------------------------------- 1 |