From 92f5e2bc73c5ba9893bd8e61e922fba3dea3b65d Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Sat, 2 Mar 2019 16:51:37 +0100 Subject: [PATCH 01/12] Support an `express.ts` file in which the express instance is passed --- packages/yoga/package.json | 3 +- packages/yoga/src/cli/commands/start/index.ts | 4 +- packages/yoga/src/helpers.ts | 8 +- packages/yoga/src/index.ts | 25 +++- packages/yoga/src/server.ts | 118 ++++++++++-------- packages/yoga/src/types.ts | 29 ++--- packages/yoga/src/yogaDefaults.ts | 11 ++ packages/yoga/tslint.json | 3 + 8 files changed, 126 insertions(+), 75 deletions(-) diff --git a/packages/yoga/package.json b/packages/yoga/package.json index 3faae7b..8e7a172 100644 --- a/packages/yoga/package.json +++ b/packages/yoga/package.json @@ -16,7 +16,7 @@ "yoga": "dist/cli/index.js" }, "dependencies": { - "apollo-server": "^2.4.2", + "apollo-server-express": "^2.4.8", "chalk": "^2.4.2", "chokidar": "^2.1.1", "create-yoga": "0.0.2", @@ -34,6 +34,7 @@ }, "devDependencies": { "@types/chokidar": "1.7.5", + "@types/express": "^4.16.1", "@types/graphql": "14.0.7", "@types/inquirer": "0.0.44", "@types/js-yaml": "3.12.0", diff --git a/packages/yoga/src/cli/commands/start/index.ts b/packages/yoga/src/cli/commands/start/index.ts index 644dff7..beec87b 100644 --- a/packages/yoga/src/cli/commands/start/index.ts +++ b/packages/yoga/src/cli/commands/start/index.ts @@ -2,7 +2,5 @@ import { start } from '../../../server' import { importYogaConfig } from '../../../config' export default async () => { - const { yogaConfig, prismaClientDir } = importYogaConfig() - - return start(yogaConfig, prismaClientDir) + return start(importYogaConfig()) } diff --git a/packages/yoga/src/helpers.ts b/packages/yoga/src/helpers.ts index 9ec71c4..7788733 100644 --- a/packages/yoga/src/helpers.ts +++ b/packages/yoga/src/helpers.ts @@ -54,14 +54,14 @@ export function importUncached( */ export function importFile( filePath: string, - exportName: string, + exportName?: string, invalidateModule: boolean = false, ): T { - const importedModule = importUncached(filePath, invalidateModule) + const importedModule = importUncached(filePath, invalidateModule) - if (importedModule[exportName] === undefined) { + if (exportName && importedModule[exportName] === undefined) { throw new Error(`\`${filePath}\` must have a '${exportName}' export`) } - return importedModule[exportName] + return exportName ? importedModule[exportName] : importedModule } diff --git a/packages/yoga/src/index.ts b/packages/yoga/src/index.ts index 53824d0..1bc1d1a 100644 --- a/packages/yoga/src/index.ts +++ b/packages/yoga/src/index.ts @@ -1,4 +1,25 @@ +import * as ApolloServer from 'apollo-server-express' +import { ExpressContext } from 'apollo-server-express/dist/ApolloServer' +import { InputConfig, Yoga } from './types' +import { core } from 'nexus/dist' +import { Application } from 'express' + export * from 'nexus' export * from 'nexus-prisma' -export * from 'apollo-server' -export { InputConfig, Yoga } from './types' +export { ApolloServer } + +export function config(opts: InputConfig) { + return opts +} + +export function eject(opts: Yoga) { + return opts +} + +export function express(fn: (app: Application) => core.MaybePromise) { + return fn +} + +export function context(ctx: ((ctx: ExpressContext) => object) | object) { + return ctx +} diff --git a/packages/yoga/src/server.ts b/packages/yoga/src/server.ts index 252595f..6584fcd 100644 --- a/packages/yoga/src/server.ts +++ b/packages/yoga/src/server.ts @@ -1,15 +1,16 @@ -import { ApolloServer } from 'apollo-server' +import { ApolloServer } from 'apollo-server-express' import { watch as nativeWatch } from 'chokidar' +import express from 'express' import { makeSchema } from 'nexus' import { makePrismaSchema } from 'nexus-prisma' import * as path from 'path' import PrettyError from 'pretty-error' import { register } from 'ts-node' import { importYogaConfig } from './config' -import { findFileByExtension, importFile, importUncached } from './helpers' +import { findFileByExtension, importFile } from './helpers' import * as logger from './logger' import { makeSchemaDefaults } from './nexusDefaults' -import { Config, Yoga } from './types' +import { Config, ConfigWithInfo, Yoga } from './types' const pe = new PrettyError().appendStyle({ 'pretty-error': { @@ -31,6 +32,7 @@ register({ export async function watch(): Promise { logger.clearConsole() logger.info('Starting development server...') + logger.warn('DEV') let info = importYogaConfig() let filesToWatch = [path.join(info.projectDir, '**', '*.ts')] @@ -39,11 +41,7 @@ export async function watch(): Promise { filesToWatch.push(info.datamodelInfoDir) } - let oldServer: any | undefined = await start( - info.yogaConfig, - info.prismaClientDir, - true, - ) + let oldServer: any | undefined = await start(info, true) let filesToReloadBatched = [] as string[] nativeWatch(filesToWatch, { @@ -71,27 +69,21 @@ export async function watch(): Promise { return Promise.resolve(true) } } - console.clear() + logger.clearConsole() logger.info('Compiling') - const yogaServer = getYogaServer(info.yogaConfig, info.prismaClientDir) + const { server, startServer, stopServer } = getYogaServer(info) if (oldServer !== undefined) { - await yogaServer.stopServer(oldServer) + await stopServer(oldServer) } - const serverInstance = await yogaServer.server( - info.yogaConfig.ejectFilePath - ? path.dirname(info.yogaConfig.ejectFilePath) - : __dirname, - ) - - oldServer = serverInstance + const serverInstance = await server() logger.clearConsole() logger.done('Compiled succesfully') - await yogaServer.startServer(serverInstance) + oldServer = await startServer(serverInstance) } catch (e) { console.error(pe.render(e)) } @@ -123,26 +115,19 @@ function getIgnoredFiles( } export async function start( - yogaConfig: Config, - prismaClientDir: string | undefined, + info: ConfigWithInfo, withLog: boolean = false, ): Promise { try { - const yogaServer = getYogaServer(yogaConfig, prismaClientDir) - const serverInstance = await yogaServer.server( - yogaConfig.ejectFilePath - ? path.dirname(yogaConfig.ejectFilePath) - : __dirname, - ) + const { server, startServer } = getYogaServer(info) + const serverInstance = await server() if (withLog) { logger.clearConsole() logger.done('Compiled successfully') } - await yogaServer.startServer(serverInstance) - - return serverInstance + return startServer(serverInstance) } catch (e) { console.error(pe.render(e)) } @@ -154,30 +139,43 @@ export async function start( * * @param resolversPath The `resolversPath` property from the `yoga.config.ts` file * @param contextPath The `contextPath` property from the `yoga.config.ts` file + * @param expressPath The `expressPath` property from the `yoga.config.ts` file */ -function importGraphqlTypesAndContext( +function importTypesContextExpressMiddleware( resolversPath: string, contextPath: string | undefined, + expressPath: string | undefined, ): { types: Record context?: any /** Context | ContextFunction */ + expressMiddleware?: (app: Express.Application) => Promise | void } { - const tsFiles = findFileByExtension(resolversPath, '.ts') + const types = findFileByExtension(resolversPath, '.ts').map(file => + importFile(file), + ) let context = undefined + let express = undefined if (contextPath !== undefined) { context = importFile(contextPath, 'default') if (typeof context !== 'function') { - throw new Error('Context must be a default exported function') + throw new Error(`${contextPath} must default export a function`) } } - const types = tsFiles.map(file => importUncached(file)) + if (expressPath !== undefined) { + express = importFile(expressPath, 'default') + + if (typeof express !== 'function') { + throw new Error(`${expressPath} must default export a function`) + } + } return { context, - types: types.reduce((a, b) => ({ ...a, ...b }), {}), + expressMiddleware: express, + types, } } @@ -185,21 +183,28 @@ function importGraphqlTypesAndContext( * * @param config The yoga config object */ -function getYogaServer( - config: Config, - prismaClientDir: string | undefined, -): Yoga { +function getYogaServer(info: ConfigWithInfo): Yoga { + const { yogaConfig: config } = info + if (!config.ejectFilePath) { return { async server() { - const { types, context } = importGraphqlTypesAndContext( + const app = express() + const { + types, + context, + expressMiddleware, + } = importTypesContextExpressMiddleware( config.resolversPath, config.contextPath, + config.expressPath, ) + const allTypes: any[] = [types] + const makeSchemaOptions = makeSchemaDefaults( config, - types, - prismaClientDir, + allTypes, + info.prismaClientDir, ) const schema = config.prisma ? makePrismaSchema({ @@ -207,21 +212,32 @@ function getYogaServer( prisma: config.prisma, }) : makeSchema(makeSchemaOptions) - - return new ApolloServer({ + const server = new ApolloServer({ schema, context, }) + + if (expressMiddleware) { + await expressMiddleware(app) + } + + server.applyMiddleware({ app, path: '/' }) + + return { express: app, server } }, - startServer(server) { - return server - .listen() - .then(({ url }) => console.log(`🚀 Server ready at ${url}`)) + async startServer({ express, server }) { + const httpServer = await express.listen({ port: 4000 }, () => { + console.log( + `🚀 Server ready at http://localhost:4000${server.graphqlPath}`, + ) + }) + + return { express: httpServer, server } }, - stopServer(server) { - return server.stop() + stopServer({ express }) { + return express.close() }, - } as Yoga + } } const yogaServer = importFile(config.ejectFilePath, 'default') diff --git a/packages/yoga/src/types.ts b/packages/yoga/src/types.ts index e442ca2..03be429 100644 --- a/packages/yoga/src/types.ts +++ b/packages/yoga/src/types.ts @@ -1,10 +1,6 @@ -import { PrismaClientInput } from 'nexus-prisma/dist/types' +import { PrismaClientInput, PrismaSchemaConfig } from 'nexus-prisma/dist/types' -export interface DatamodelInfo { - uniqueFieldsByModel: Record - clientPath: string - schema: { __schema: any } -} +export type DatamodelInfo = PrismaSchemaConfig['prisma']['datamodelInfo'] export type InputPrismaConfig = { /** @@ -37,23 +33,30 @@ export type InputOutputFilesConfig = { export type InputConfig = { /** - * Path to the directory where your resolvers are defined. + * Path to the resolvers directory. * **Path has to exist** * @default ./src/graphql/ */ resolversPath?: string /** - * Path to your context.ts file. **If provided, path has to exist** + * Path to the context.ts file. **If provided, path has to exist** * @default ./src/context.ts */ contextPath?: string /** - * Path to an `server.ts` file to eject from default configuration file `yoga.config.ts`. + * Path to the `server.ts` file to eject from default configuration file `yoga.config.ts`. * When provided, all other configuration properties are ignored and should be configured programatically. * **If provided, path has to exist** * @default ./src/server.ts */ ejectFilePath?: string + /** + * Path to the `express.ts` file. + * This file gets injected the underlying express instance (to add routes, or middlewares etc...) + * **If provided, path has to exist** + * @default ./src/express.ts + */ + expressPath?: string /** * Config for the outputted files (schema, typings ..) */ @@ -74,10 +77,8 @@ export type Config = { contextPath?: RequiredProperty<'contextPath'> ejectFilePath?: RequiredProperty<'ejectFilePath'> output: RequiredProperty<'output'> - prisma?: { - datamodelInfo: DatamodelInfo - client: PrismaClientInput - } + prisma?: PrismaSchemaConfig['prisma'] + expressPath?: RequiredProperty<'expressPath'> } export type ConfigWithInfo = { @@ -90,7 +91,7 @@ export type ConfigWithInfo = { } export interface Yoga { - server: (dirname: string) => Server | Promise + server: () => Server | Promise startServer: (server: Server) => any | Promise stopServer: (server: Server) => any | Promise } diff --git a/packages/yoga/src/yogaDefaults.ts b/packages/yoga/src/yogaDefaults.ts index 88c589c..c341555 100644 --- a/packages/yoga/src/yogaDefaults.ts +++ b/packages/yoga/src/yogaDefaults.ts @@ -40,6 +40,7 @@ export const DEFAULTS: Config = { $graphql: null as any, // FIXME }, }, + expressPath: './src/express.ts', } export const DEFAULT_META_SCHEMA_DIR = './.yoga/nexus-prisma/' @@ -56,6 +57,7 @@ export function normalizeConfig( contextPath: contextPath(projectDir, config.contextPath), resolversPath: resolversPath(projectDir, config.resolversPath), ejectFilePath: ejectFilePath(projectDir, config.ejectFilePath), + expressPath: expressPath(projectDir, config.expressPath), output: output(projectDir, config.output), prisma: prisma(projectDir, config.prisma), } @@ -156,6 +158,15 @@ function ejectFilePath( return optional(path, input, buildError(projectDir, path, 'ejectFilePath')) } +function expressPath( + projectDir: string, + input: string | undefined, +): string | undefined { + const path = inputOrDefaultPath(projectDir, input, DEFAULTS.expressPath!) + + return optional(path, input, buildError(projectDir, path, 'expressPath')) +} + function output( projectDir: string, input: InputOutputFilesConfig | undefined, diff --git a/packages/yoga/tslint.json b/packages/yoga/tslint.json index cd6c029..29de186 100644 --- a/packages/yoga/tslint.json +++ b/packages/yoga/tslint.json @@ -1,5 +1,8 @@ { "extends": ["tslint-config-standard", "tslint-config-prettier"], + "linterOptions": { + "exclude": ["node_modules/**"] + }, "rules": { "no-use-before-declare": false, "space-before-function-paren": false From 33fa35832d2ccfce3e72661569b9182565e29358 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:34:18 +0100 Subject: [PATCH 02/12] Update build command for apollo-server-express --- examples/minimal-ejected/src/server.ts | 40 ++++++++---- examples/minimal-ejected/tsconfig.json | 1 - packages/yoga/src/cli/commands/build/index.ts | 61 +++++++++++++------ packages/yoga/src/index.ts | 20 +++--- packages/yoga/src/server.ts | 23 ++++--- packages/yoga/src/types.ts | 12 ++-- 6 files changed, 106 insertions(+), 51 deletions(-) diff --git a/examples/minimal-ejected/src/server.ts b/examples/minimal-ejected/src/server.ts index 7f9f3d2..0de01f3 100644 --- a/examples/minimal-ejected/src/server.ts +++ b/examples/minimal-ejected/src/server.ts @@ -1,20 +1,23 @@ import * as path from 'path' -import { ApolloServer, makeSchema, Yoga } from 'yoga' +import { Server } from 'http' +import { ApolloServer, makeSchema, eject, express } from 'yoga' import context from './context' import * as types from './graphql' -export default { - server: dirname => { +export default eject({ + async server() { + const app = express() + const schema = makeSchema({ types, outputs: { - schema: path.join(dirname, './schema.graphql'), - typegen: path.join(dirname, '../.yoga/nexus.ts'), + schema: path.join(__dirname, './schema.graphql'), + typegen: path.join(__dirname, '../.yoga/nexus.ts'), }, typegenAutoConfig: { sources: [ { - source: path.join(dirname, './context.ts'), + source: path.join(__dirname, './context.ts'), alias: 'ctx', }, ], @@ -22,12 +25,27 @@ export default { }, }) - return new ApolloServer({ + const apolloServer = new ApolloServer.ApolloServer({ schema, context, }) + + apolloServer.applyMiddleware({ app, path: '/' }) + + return app + }, + async startServer(express) { + return new Promise((resolve, reject) => { + const httpServer = express + .listen({ port: 4000 }, () => { + console.log(`🚀 Server ready at http://localhost:4000/`) + + resolve(httpServer) + }) + .on('error', err => reject(err)) + }) + }, + async stopServer(httpServer) { + return httpServer.close() }, - startServer: server => - server.listen().then(s => console.log(`Server listening at ${s.url}`)), - stopServer: server => server.stop(), -} as Yoga +}) diff --git a/examples/minimal-ejected/tsconfig.json b/examples/minimal-ejected/tsconfig.json index 15412a8..cfb5ef8 100644 --- a/examples/minimal-ejected/tsconfig.json +++ b/examples/minimal-ejected/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { "module": "commonjs", - "moduleResolution": "node", "target": "es5", "rootDir": ".", "outDir": "dist", diff --git a/packages/yoga/src/cli/commands/build/index.ts b/packages/yoga/src/cli/commands/build/index.ts index 8291935..d34f310 100644 --- a/packages/yoga/src/cli/commands/build/index.ts +++ b/packages/yoga/src/cli/commands/build/index.ts @@ -4,7 +4,7 @@ import * as path from 'path' import * as ts from 'typescript' import { findConfigFile, importYogaConfig } from '../../../config' import { findFileByExtension } from '../../../helpers' -import { Config, ConfigWithInfo } from '../../../types' +import { ConfigWithInfo } from '../../../types' import { DEFAULTS } from '../../../yogaDefaults' const diagnosticHost: ts.FormatDiagnosticsHost = { @@ -46,7 +46,7 @@ export default () => { 'index.ts', ) - writeEntryPoint(info, ejectFilePath!, config) + writeEntryPoint(info, ejectFilePath, config) } else { useEntryPoint(info, info.yogaConfig.ejectFilePath, config) } @@ -117,14 +117,18 @@ function useEntryPoint( config: ts.ParsedCommandLine, ) { const indexFile = ` - import yogaServer from '${getRelativePath( + import yoga from '${getRelativePath( path.dirname(ejectFilePath), ejectFilePath, )}' - const serverInstance = yogaServer.server(__dirname) + async function main() { + const serverInstance = await yoga.server() - yogaServer.startServer(serverInstance) + return yoga.startServer(serverInstance) + } + + main() ` const indexFilePath = path.join(path.dirname(ejectFilePath), 'index.ts') @@ -138,7 +142,7 @@ function writeEntryPoint( ) { const ejectFile = info.yogaConfig.prisma ? prismaIndexFile(path.dirname(ejectFilePath), info) - : simpleIndexfile(path.dirname(ejectFilePath), info.yogaConfig) + : simpleIndexfile(path.dirname(ejectFilePath), info) outputFile(ejectFile, ejectFilePath, config.options, info) @@ -151,7 +155,7 @@ function writeEntryPoint( function prismaIndexFile(filePath: string, info: ConfigWithInfo) { return ` - import { ApolloServer, makePrismaSchema } from 'yoga' + import { ApolloServer, makePrismaSchema, express } from 'yoga' import datamodelInfo from '${getRelativePath( filePath, info.datamodelInfoDir!, @@ -170,6 +174,7 @@ function prismaIndexFile(filePath: string, info: ConfigWithInfo) { info.yogaConfig.resolversPath, )}' + const schema = makePrismaSchema({ types, prisma: { @@ -179,35 +184,57 @@ function prismaIndexFile(filePath: string, info: ConfigWithInfo) { outputs: false }) - new ApolloServer({ + const apolloServer = new ApolloServer.ApolloServer({ schema, ${info.yogaConfig.contextPath ? 'context' : ''} - }).listen().then(s => console.log(\`🚀 Server listening at \${s.url}\`)) + }) + const app = express() + + apolloServer.applyMiddleware({ app, path: '/' }) + + app.listen({ port: 4000 }, () => { + console.log( + \`🚀 Server ready at http://localhost:4000/\`, + ) + }) ` } -function simpleIndexfile(filePath: string, yogaConfig: Config) { +function simpleIndexfile(filePath: string, info: ConfigWithInfo) { return `\ -import { ApolloServer, makeSchema } from 'yoga' +import { ApolloServer, makeSchema, express } from 'yoga' ${ - yogaConfig.contextPath + info.yogaConfig.contextPath ? `import context from '${getRelativePath( filePath, - yogaConfig.contextPath, + info.yogaConfig.contextPath, )}'` : '' } -import * as types from '${getRelativePath(filePath, yogaConfig.resolversPath)}' +import * as types from '${getRelativePath( + filePath, + info.yogaConfig.resolversPath, + )}' const schema = makeSchema({ types, outputs: false }) -new ApolloServer({ +const apolloServer = new ApolloServer.ApolloServer({ schema, - context, -}).listen().then(s => console.log(\`🚀 Server listening at \${s.url}\`)), + ${info.yogaConfig.contextPath ? 'context' : ''} +}) + +const app = express() + +apolloServer.applyMiddleware({ app, path: '/' }) + +app.listen({ port: 4000 }, () => { + console.log( + \`🚀 Server ready at http://localhost:4000/\`, + ) +}) ` } diff --git a/packages/yoga/src/index.ts b/packages/yoga/src/index.ts index 1bc1d1a..fc44578 100644 --- a/packages/yoga/src/index.ts +++ b/packages/yoga/src/index.ts @@ -1,25 +1,29 @@ import * as ApolloServer from 'apollo-server-express' import { ExpressContext } from 'apollo-server-express/dist/ApolloServer' -import { InputConfig, Yoga } from './types' -import { core } from 'nexus/dist' -import { Application } from 'express' +import express from 'express' +import * as Http from 'http' +import { InputConfig as YogaConfig, Yoga, MaybePromise } from './types' export * from 'nexus' export * from 'nexus-prisma' -export { ApolloServer } +export { ApolloServer, express } -export function config(opts: InputConfig) { +export function config(opts: YogaConfig) { return opts } -export function eject(opts: Yoga) { +export function eject( + opts: Yoga, +) { return opts } -export function express(fn: (app: Application) => core.MaybePromise) { +export function useExpress( + fn: (app: express.Application) => MaybePromise, +) { return fn } -export function context(ctx: ((ctx: ExpressContext) => object) | object) { +export function context(ctx: ((ctx: ExpressContext) => T) | T) { return ctx } diff --git a/packages/yoga/src/server.ts b/packages/yoga/src/server.ts index 6584fcd..751fd15 100644 --- a/packages/yoga/src/server.ts +++ b/packages/yoga/src/server.ts @@ -1,6 +1,7 @@ import { ApolloServer } from 'apollo-server-express' import { watch as nativeWatch } from 'chokidar' import express from 'express' +import { Server } from 'http' import { makeSchema } from 'nexus' import { makePrismaSchema } from 'nexus-prisma' import * as path from 'path' @@ -223,19 +224,21 @@ function getYogaServer(info: ConfigWithInfo): Yoga { server.applyMiddleware({ app, path: '/' }) - return { express: app, server } + return app }, - async startServer({ express, server }) { - const httpServer = await express.listen({ port: 4000 }, () => { - console.log( - `🚀 Server ready at http://localhost:4000${server.graphqlPath}`, - ) - }) + async startServer(express) { + return new Promise((resolve, reject) => { + const httpServer = express + .listen({ port: 4000 }, () => { + console.log(`🚀 Server ready at http://localhost:4000/`) - return { express: httpServer, server } + resolve(httpServer) + }) + .on('error', err => reject(err)) + }) }, - stopServer({ express }) { - return express.close() + stopServer(httpServer) { + return httpServer.close() }, } } diff --git a/packages/yoga/src/types.ts b/packages/yoga/src/types.ts index 03be429..38e52b1 100644 --- a/packages/yoga/src/types.ts +++ b/packages/yoga/src/types.ts @@ -1,4 +1,8 @@ import { PrismaClientInput, PrismaSchemaConfig } from 'nexus-prisma/dist/types' +import Express from 'express' +import { Server as HttpServer } from 'http' + +export type MaybePromise = Promise | T export type DatamodelInfo = PrismaSchemaConfig['prisma']['datamodelInfo'] @@ -90,8 +94,8 @@ export type ConfigWithInfo = { prismaClientDir?: string } -export interface Yoga { - server: () => Server | Promise - startServer: (server: Server) => any | Promise - stopServer: (server: Server) => any | Promise +export interface Yoga { + server: () => MaybePromise + startServer: (params: T) => MaybePromise + stopServer: (params: U) => any } From b3681f720dfc9aaba4529e0ac12df920ddb10741 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:44:14 +0100 Subject: [PATCH 03/12] prefix config helpers by `yoga` --- packages/yoga/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/yoga/src/index.ts b/packages/yoga/src/index.ts index fc44578..2fb6f7e 100644 --- a/packages/yoga/src/index.ts +++ b/packages/yoga/src/index.ts @@ -8,22 +8,22 @@ export * from 'nexus' export * from 'nexus-prisma' export { ApolloServer, express } -export function config(opts: YogaConfig) { +export function yogaConfig(opts: YogaConfig) { return opts } -export function eject( +export function yogaEject( opts: Yoga, ) { return opts } -export function useExpress( +export function yogaExpress( fn: (app: express.Application) => MaybePromise, ) { return fn } -export function context(ctx: ((ctx: ExpressContext) => T) | T) { +export function yogaContext(ctx: ((ctx: ExpressContext) => object) | object) { return ctx } From 756c34c27cb30fc01b287d0aca4955db939666ff Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:44:43 +0100 Subject: [PATCH 04/12] Update examples --- examples/minimal-ejected/src/context.ts | 6 ++++-- examples/minimal-ejected/src/server.ts | 6 +++--- examples/with-db/src/context.ts | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/minimal-ejected/src/context.ts b/examples/minimal-ejected/src/context.ts index 8699c36..fc02355 100644 --- a/examples/minimal-ejected/src/context.ts +++ b/examples/minimal-ejected/src/context.ts @@ -1,3 +1,5 @@ +import { yogaContext } from 'yoga' + interface UserModel { id: string name: string @@ -22,6 +24,6 @@ export interface Context { users: UserModel[] } -export default () => ({ +export default yogaContext(() => ({ users, -}) +})) diff --git a/examples/minimal-ejected/src/server.ts b/examples/minimal-ejected/src/server.ts index 0de01f3..e3878ed 100644 --- a/examples/minimal-ejected/src/server.ts +++ b/examples/minimal-ejected/src/server.ts @@ -1,10 +1,10 @@ -import * as path from 'path' import { Server } from 'http' -import { ApolloServer, makeSchema, eject, express } from 'yoga' +import * as path from 'path' +import { ApolloServer, express, makeSchema, yogaEject } from 'yoga' import context from './context' import * as types from './graphql' -export default eject({ +export default yogaEject({ async server() { const app = express() diff --git a/examples/with-db/src/context.ts b/examples/with-db/src/context.ts index 8ff3eae..138402a 100644 --- a/examples/with-db/src/context.ts +++ b/examples/with-db/src/context.ts @@ -1,9 +1,11 @@ import { prisma, Prisma } from '../.yoga/prisma-client' +import { yogaContext } from 'yoga' export interface Context { prisma: Prisma } -export default () => ({ +export default yogaContext(({ req }) => ({ + req, prisma, -}) +})) From 898c43a433ea24945e68a278a72993ec6b884092 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:45:06 +0100 Subject: [PATCH 05/12] Update artifacts --- examples/minimal-ejected/.yoga/nexus.ts | 2 +- examples/minimal-ejected/src/schema.graphql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/minimal-ejected/.yoga/nexus.ts b/examples/minimal-ejected/.yoga/nexus.ts index a784eee..99555a6 100644 --- a/examples/minimal-ejected/.yoga/nexus.ts +++ b/examples/minimal-ejected/.yoga/nexus.ts @@ -1,5 +1,5 @@ /** - * This file was automatically generated by Nexus 0.9.14 + * This file was automatically generated by Nexus 0.10.0 * Do not make changes to this file directly */ diff --git a/examples/minimal-ejected/src/schema.graphql b/examples/minimal-ejected/src/schema.graphql index f87eb44..9c8de0b 100644 --- a/examples/minimal-ejected/src/schema.graphql +++ b/examples/minimal-ejected/src/schema.graphql @@ -1,4 +1,4 @@ -### This file was autogenerated by Nexus 0.9.14 +### This file was autogenerated by Nexus 0.10.0 ### Do not make changes to this file directly From 9a7b98773428e5d52761d3b3d62cb86c9d836a2e Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:53:20 +0100 Subject: [PATCH 06/12] Add `typesPath` property to override default types --- packages/yoga/src/nexusDefaults.ts | 8 ++++++++ packages/yoga/src/server.ts | 8 ++------ packages/yoga/src/types.ts | 8 +++++++- packages/yoga/src/yogaDefaults.ts | 11 +++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/yoga/src/nexusDefaults.ts b/packages/yoga/src/nexusDefaults.ts index 61e7369..9628a79 100644 --- a/packages/yoga/src/nexusDefaults.ts +++ b/packages/yoga/src/nexusDefaults.ts @@ -37,6 +37,14 @@ export function makeSchemaDefaults( }, ] : []), + ...(config.typesPath + ? [ + { + source: config.typesPath, + alias: 'types', + }, + ] + : []), ], ...(config.contextPath ? { contextType: 'ctx.Context' } : {}), }, diff --git a/packages/yoga/src/server.ts b/packages/yoga/src/server.ts index 751fd15..b956b82 100644 --- a/packages/yoga/src/server.ts +++ b/packages/yoga/src/server.ts @@ -142,7 +142,7 @@ export async function start( * @param contextPath The `contextPath` property from the `yoga.config.ts` file * @param expressPath The `expressPath` property from the `yoga.config.ts` file */ -function importTypesContextExpressMiddleware( +function importArtifacts( resolversPath: string, contextPath: string | undefined, expressPath: string | undefined, @@ -191,11 +191,7 @@ function getYogaServer(info: ConfigWithInfo): Yoga { return { async server() { const app = express() - const { - types, - context, - expressMiddleware, - } = importTypesContextExpressMiddleware( + const { types, context, expressMiddleware } = importArtifacts( config.resolversPath, config.contextPath, config.expressPath, diff --git a/packages/yoga/src/types.ts b/packages/yoga/src/types.ts index 38e52b1..b4f3100 100644 --- a/packages/yoga/src/types.ts +++ b/packages/yoga/src/types.ts @@ -43,10 +43,15 @@ export type InputConfig = { */ resolversPath?: string /** - * Path to the context.ts file. **If provided, path has to exist** + * Path to the `context.ts` file to inject a context into your graphql resolvers. **If provided, path has to exist** * @default ./src/context.ts */ contextPath?: string + /** + * Path to the `types.ts` file to override nexus default types **If provided, path has to exist** + * @default ./src/types.ts + */ + typesPath?: string /** * Path to the `server.ts` file to eject from default configuration file `yoga.config.ts`. * When provided, all other configuration properties are ignored and should be configured programatically. @@ -80,6 +85,7 @@ export type Config = { resolversPath: RequiredProperty<'resolversPath'> contextPath?: RequiredProperty<'contextPath'> ejectFilePath?: RequiredProperty<'ejectFilePath'> + typesPath?: RequiredProperty<'typesPath'> output: RequiredProperty<'output'> prisma?: PrismaSchemaConfig['prisma'] expressPath?: RequiredProperty<'expressPath'> diff --git a/packages/yoga/src/yogaDefaults.ts b/packages/yoga/src/yogaDefaults.ts index c341555..864f557 100644 --- a/packages/yoga/src/yogaDefaults.ts +++ b/packages/yoga/src/yogaDefaults.ts @@ -16,6 +16,7 @@ import * as logger from './logger' export const DEFAULTS: Config = { contextPath: './src/context.ts', resolversPath: './src/graphql/', + typesPath: './src/types.ts', ejectFilePath: './src/server.ts', output: { typegenPath: './.yoga/nexus.ts', @@ -56,6 +57,7 @@ export function normalizeConfig( const outputConfig: Config = { contextPath: contextPath(projectDir, config.contextPath), resolversPath: resolversPath(projectDir, config.resolversPath), + typesPath: typesPath(projectDir, config.typesPath), ejectFilePath: ejectFilePath(projectDir, config.ejectFilePath), expressPath: expressPath(projectDir, config.expressPath), output: output(projectDir, config.output), @@ -149,6 +151,15 @@ function resolversPath(projectDir: string, input: string | undefined): string { return requiredPath(path, buildError(projectDir, path, 'resolversPath')) } +function typesPath( + projectDir: string, + input: string | undefined, +): string | undefined { + const path = inputOrDefaultPath(projectDir, input, DEFAULTS.typesPath!) + + return optional(path, input, buildError(projectDir, path, 'typesPath')) +} + function ejectFilePath( projectDir: string, input: string | undefined, From 81c2a0c0a049e9433ee1e79ac1e47fcffda2a456 Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 13:56:30 +0100 Subject: [PATCH 07/12] remove ci cache --- .circleci/config.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 826d624..165acff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,8 +10,6 @@ jobs: - run: name: update-npm command: sudo npm install -g npm@latest - - restore_cache: - key: dependency-cache-{{ checksum "package.json" }} - run: name: install-package-dependencies command: yarn run bootstrap:ci @@ -22,10 +20,6 @@ jobs: - run: name: run-build command: sudo yarn run build:ci - - save_cache: - key: dependency-cache-{{ checksum "package.json" }} - paths: - - ./node_modules - run: name: run lint command: yarn run lint From e80f0b01b1f270544eef512e2de077b5d9ae349a Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 14:08:43 +0100 Subject: [PATCH 08/12] Fixes ora and shellSync --- packages/create-yoga/package.json | 2 +- packages/yoga/src/server.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/create-yoga/package.json b/packages/create-yoga/package.json index 7ba536d..5b29752 100644 --- a/packages/create-yoga/package.json +++ b/packages/create-yoga/package.json @@ -25,7 +25,7 @@ "inquirer-path": "^1.0.0-beta5", "js-yaml": "^3.12.2", "meow": "^5.0.0", - "ora": "^3.0.0", + "ora": "^3.2.0", "parse-github-url": "^1.0.2", "prettier": "^1.16.4", "prisma-datamodel": "^1.28.3", diff --git a/packages/yoga/src/server.ts b/packages/yoga/src/server.ts index b956b82..36dfd50 100644 --- a/packages/yoga/src/server.ts +++ b/packages/yoga/src/server.ts @@ -33,7 +33,6 @@ register({ export async function watch(): Promise { logger.clearConsole() logger.info('Starting development server...') - logger.warn('DEV') let info = importYogaConfig() let filesToWatch = [path.join(info.projectDir, '**', '*.ts')] From 4c27551987151aafc8823c65d1201362df3d4c2e Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 17:32:13 +0100 Subject: [PATCH 09/12] Fix build command --- packages/yoga/src/cli/commands/build/index.ts | 22 +------------------ packages/yoga/src/config.ts | 2 +- packages/yoga/src/index.ts | 2 +- packages/yoga/src/server.ts | 4 +--- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/packages/yoga/src/cli/commands/build/index.ts b/packages/yoga/src/cli/commands/build/index.ts index d34f310..99add13 100644 --- a/packages/yoga/src/cli/commands/build/index.ts +++ b/packages/yoga/src/cli/commands/build/index.ts @@ -35,9 +35,8 @@ export default () => { tsConfigPath, ) const config = fixConfig(inputConfig, info.projectDir) - const rootNames = getRootNames(info) - compile(rootNames, config.options) + compile(config.fileNames, config.options) if (!info.yogaConfig.ejectFilePath) { const ejectFilePath = path.join( @@ -69,25 +68,6 @@ function compile(rootNames: string[], options: ts.CompilerOptions) { } } -function getRootNames(info: ConfigWithInfo) { - const rootNames = findFileByExtension(info.yogaConfig.resolversPath, '.ts') - - if (info.yogaConfig.contextPath) { - rootNames.push(info.yogaConfig.contextPath) - } - - if (info.yogaConfig.ejectFilePath) { - rootNames.push(info.yogaConfig.ejectFilePath) - } - - if (info.yogaConfig.prisma) { - rootNames.push(...findFileByExtension(info.prismaClientDir!, '.ts')) - rootNames.push(...findFileByExtension(info.datamodelInfoDir!, '.ts')) - } - - return rootNames -} - /** * Do post-processing on config options to support `ts-node`. */ diff --git a/packages/yoga/src/config.ts b/packages/yoga/src/config.ts index 05bca82..5f40527 100644 --- a/packages/yoga/src/config.ts +++ b/packages/yoga/src/config.ts @@ -63,7 +63,7 @@ function getDatamodelInfoDir( } if (inputConfig.prisma && inputConfig.prisma.datamodelInfoPath) { - return inputConfig.prisma.datamodelInfoPath + return path.join(projectDir, inputConfig.prisma.datamodelInfoPath) } return path.join(projectDir, DEFAULT_META_SCHEMA_DIR) diff --git a/packages/yoga/src/index.ts b/packages/yoga/src/index.ts index 2fb6f7e..fe86b73 100644 --- a/packages/yoga/src/index.ts +++ b/packages/yoga/src/index.ts @@ -2,7 +2,7 @@ import * as ApolloServer from 'apollo-server-express' import { ExpressContext } from 'apollo-server-express/dist/ApolloServer' import express from 'express' import * as Http from 'http' -import { InputConfig as YogaConfig, Yoga, MaybePromise } from './types' +import { InputConfig as YogaConfig, MaybePromise, Yoga } from './types' export * from 'nexus' export * from 'nexus-prisma' diff --git a/packages/yoga/src/server.ts b/packages/yoga/src/server.ts index 36dfd50..1118be4 100644 --- a/packages/yoga/src/server.ts +++ b/packages/yoga/src/server.ts @@ -195,11 +195,9 @@ function getYogaServer(info: ConfigWithInfo): Yoga { config.contextPath, config.expressPath, ) - const allTypes: any[] = [types] - const makeSchemaOptions = makeSchemaDefaults( config, - allTypes, + types, info.prismaClientDir, ) const schema = config.prisma From 85400cd55c86d743e41dd969336d64e63ffeb33b Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Mon, 11 Mar 2019 17:36:58 +0100 Subject: [PATCH 10/12] Fix prisma-client import --- packages/yoga/src/yogaDefaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoga/src/yogaDefaults.ts b/packages/yoga/src/yogaDefaults.ts index 864f557..7a780d7 100644 --- a/packages/yoga/src/yogaDefaults.ts +++ b/packages/yoga/src/yogaDefaults.ts @@ -213,7 +213,7 @@ export function client( ): PrismaClientInput { if (input === undefined) { const clientPath = requiredPath( - join(projectDir, datamodelInfo.clientPath), + join(projectDir, datamodelInfo.clientPath, 'index.ts'), `${buildError( projectDir, datamodelInfo.clientPath, From d9f10826a21e3b2fc89e65bec42168267af7ef5a Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Thu, 14 Mar 2019 18:09:52 +0100 Subject: [PATCH 11/12] Add .docz to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9ad76d4..9667ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ dist yalc.lock yarn.lock package-lock.json -.idea \ No newline at end of file +.idea +.docz \ No newline at end of file From 865a9f49848a8179938d3c042ffda4bf3e944b6c Mon Sep 17 00:00:00 2001 From: Flavian DESVERNE Date: Thu, 14 Mar 2019 18:10:14 +0100 Subject: [PATCH 12/12] Fix comment --- packages/yoga/src/yogaDefaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoga/src/yogaDefaults.ts b/packages/yoga/src/yogaDefaults.ts index 7a780d7..e1cdd38 100644 --- a/packages/yoga/src/yogaDefaults.ts +++ b/packages/yoga/src/yogaDefaults.ts @@ -34,7 +34,7 @@ export const DEFAULTS: Config = { }, /** * Do not use that as a default value, this is just a placeholder - * When `client` isn't provided, we're importing it from `DEFAULT_NEXUS_PRISMA_SCHEMA_PATH` defined below + * When `client` isn't provided, we're importing it from `datamodel.clientPath` */ client: { $exists: null,