vue-cli-plugin-apollo
Version:
vue-cli 3 plugin to add Apollo and GraphQL
202 lines (175 loc) • 5.69 kB
JavaScript
const http = require('http')
const chalk = require('chalk')
const express = require('express')
const { ApolloServer, gql } = require('apollo-server-express')
const { PubSub } = require('graphql-subscriptions')
const merge = require('deepmerge')
const { defaultValue, autoCall } = require('../utils')
// eslint-disable-next-line no-global-assign
require = require('esm')(module)
module.exports = (options, cb = null) => {
const { load } = require('../utils/load')(options)
// Default options
options = merge({
integratedEngine: false,
}, options)
// Express app
const app = express()
// Customize those files
let typeDefs = load(options.paths.typeDefs)
const resolvers = load(options.paths.resolvers)
const context = load(options.paths.context)
const schemaDirectives = load(options.paths.directives)
let pubsub
try {
pubsub = load(options.paths.pubsub)
} catch (e) {
if (process.env.NODE_ENV !== 'production' && !options.quiet) {
console.log(chalk.yellow('Using default PubSub implementation for subscriptions.'))
console.log(chalk.grey('You should provide a different implementation in production (for example with Redis) by exporting it in \'apollo-server/pubsub.js\'.'))
}
}
let dataSources
try {
dataSources = load(options.paths.dataSources)
} catch (e) {
console.error(e)
}
// GraphQL API Server
// Realtime subscriptions
if (!pubsub) pubsub = new PubSub()
// Customize server
try {
const serverModule = load(options.paths.server)
serverModule(app)
} catch (e) {
console.error(e)
// No file found
}
// Apollo server options
typeDefs = processSchema(typeDefs)
let apolloServerOptions = {
typeDefs,
resolvers,
schemaDirectives,
dataSources,
tracing: true,
cacheControl: true,
engine: !options.integratedEngine,
// Resolvers context from POST
context: async ({ req, connection }) => {
let contextData
try {
if (connection) {
contextData = await autoCall(context, { connection })
} else {
contextData = await autoCall(context, { req })
}
} catch (e) {
console.error(e)
throw e
}
contextData = Object.assign({}, contextData, { pubsub })
return contextData
},
// Resolvers context from WebSocket
subscriptions: {
path: options.subscriptionsPath,
onConnect: async (connection, websocket) => {
let contextData = {}
try {
contextData = await autoCall(context, {
connection,
websocket,
})
contextData = Object.assign({}, contextData, { pubsub })
} catch (e) {
console.error(e)
throw e
}
return contextData
},
},
}
// Automatic mocking
if (options.enableMocks) {
// Customize this file
apolloServerOptions.mocks = load(options.paths.mocks)
apolloServerOptions.mockEntireSchema = false
if (!options.quiet) {
if (process.env.NODE_ENV === 'production') {
console.warn('Automatic mocking is enabled, consider disabling it with the \'enableMocks\' option.')
} else {
console.log('✔️ Automatic mocking is enabled')
}
}
}
// Apollo Engine
if (options.enableEngine && options.integratedEngine) {
if (options.engineKey) {
apolloServerOptions.engine = {
apiKey: options.engineKey,
schemaTag: options.schemaTag,
...options.engineOptions || {},
}
console.log('✔️ Apollo Engine is enabled')
} else if (!options.quiet) {
console.log(chalk.yellow('Apollo Engine key not found.') + `To enable Engine, set the ${chalk.cyan('VUE_APP_APOLLO_ENGINE_KEY')} env variable.`)
console.log('Create a key at https://engine.apollographql.com/')
console.log('You may see `Error: Must provide document` errors (query persisting tries).')
}
} else {
apolloServerOptions.engine = false
}
// Final options
apolloServerOptions = merge(apolloServerOptions, defaultValue(options.serverOptions, {}))
// Apollo Server
const server = new ApolloServer(apolloServerOptions)
// Express middleware
server.applyMiddleware({
app,
path: options.graphqlPath,
cors: options.cors,
// gui: {
// endpoint: graphqlPath,
// subscriptionEndpoint: graphqlSubscriptionsPath,
// },
})
// Start server
const httpServer = http.createServer(app)
httpServer.setTimeout(options.timeout)
server.installSubscriptionHandlers(httpServer)
httpServer.listen({
host: options.host || 'localhost',
port: options.port,
}, () => {
if (!options.quiet) {
console.log(`✔️ GraphQL Server is running on ${chalk.cyan(`http://localhost:${options.port}${options.graphqlPath}`)}`)
if (process.env.NODE_ENV !== 'production' && !process.env.VUE_CLI_API_MODE) {
console.log(`✔️ Type ${chalk.cyan('rs')} to restart the server`)
}
}
cb && cb()
})
}
function processSchema (typeDefs) {
if (Array.isArray(typeDefs)) {
return typeDefs.map(processSchema)
}
if (typeof typeDefs === 'string') {
// Convert schema to AST
typeDefs = gql(typeDefs)
}
// Remove upload scalar (it's already included in Apollo Server)
removeFromSchema(typeDefs, 'ScalarTypeDefinition', 'Upload')
return typeDefs
}
function removeFromSchema (document, kind, name) {
const definitions = document.definitions
const index = definitions.findIndex(
def => def.kind === kind && def.name.kind === 'Name' && def.name.value === name,
)
if (index !== -1) {
definitions.splice(index, 1)
}
}