Skip to content

Commit

Permalink
Local schema improvements (hmr and printing) (#1203)
Browse files Browse the repository at this point in the history
Co-authored-by: Alec Aivazis <[email protected]>
  • Loading branch information
jycouet and AlecAivazis committed Oct 15, 2023
1 parent f6ef67e commit a6a5147
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ jobs:
# Run tests

- name: Build packages
run: pnpm run compile
run: pnpm run build

- name: End-to-End Tests ${{ matrix.framework }}
run: pnpm run --filter ${{ matrix.framework }} build && pnpm --filter ${{ matrix.framework }} tests
Expand Down
9 changes: 9 additions & 0 deletions e2e/react/.graphqlrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
projects:
default:
schema:
- ./$houdini/graphql/schema.graphql
documents:
- '**/*.gql'
- '**/*.jsx'
- '**/*.tsx'
- ./$houdini/graphql/documents.gql
2 changes: 1 addition & 1 deletion e2e/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"build:": "cd ../../ && ((run build && cd -) || (cd - && exit 1))",
"build:": "cd ../../ && ((pnpm run build && cd -) || (cd - && exit 1))",
"build:dev": "pnpm build: && pnpm dev",
"build:web": "pnpm build: && pnpm web",
"build:test": "pnpm build: && pnpm test",
Expand Down
93 changes: 2 additions & 91 deletions e2e/react/src/api/+schema.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,6 @@
import { makeExecutableSchema } from '@graphql-tools/schema'

const typeDefs = /* GraphQL */ `
type Query {
welcome: String!
links(delay: Int): [Link!]!
sponsors: [Sponsor!]!
giveMeAnError: String
}
type Mutation {
hello(name: String!): String!
}
type Link {
name: String
url: String
}
type Sponsor {
login: String!
name: String!
avatarUrl: String!
websiteUrl: String
tiersTitle: String!
}
`

const resolvers = {
Query: {
welcome: () => 'Welcome to Houdini 🎩',
links: async (_: any, args: { delay?: number }) => {
if (args.delay) {
await new Promise((resolve) => setTimeout(resolve, args.delay))
}
return [
{ name: 'GitHub', url: 'https://github.com/HoudiniGraphql/houdini' },
{ name: 'Documentation', url: 'https://houdinigraphql.com/' },
{ name: 'Discord', url: 'https://discord.gg/Gd8vfvxpsD' },
]
},
sponsors: async () => {
const res = await fetch(
'https://raw.githubusercontent.com/HoudiniGraphql/sponsors/main/generated/sponsors.json'
)
const jsonData = await res.json()

function getTier(value: number) {
if (value >= 1500) {
return 'Wizard'
}
if (value >= 500) {
return 'Mage'
}
if (value >= 25) {
return "Magician's Apprentice"
}
if (value >= 10) {
return 'Supportive Muggle'
}
return 'Past Sponsors'
}

return jsonData.map(
(c: {
sponsor: {
login: string
name: string
avatarUrl: string
websiteUrl: string
}
monthlyDollars: number
}) => {
return {
login: c.sponsor.login,
name: c.sponsor.name,
avatarUrl: c.sponsor.avatarUrl,
websiteUrl: c.sponsor.websiteUrl,
tiersTitle: getTier(c.monthlyDollars),
}
}
)
},
giveMeAnError: () => {
throw new Error(`Yes, I'm an error!`)
},
},
Mutation: {
hello: (_: any, args: { name: string }) => {
return `👋 Hey, hello ${args.name}! `
},
},
}
import { resolvers } from './resolvers'
import { typeDefs } from './typeDefs'

export default makeExecutableSchema({ typeDefs, resolvers })
1 change: 1 addition & 0 deletions e2e/react/src/api/dico.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const dico = { HELLO: `👋 Hey, hello` }
5 changes: 5 additions & 0 deletions e2e/react/src/api/extra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const extra = /* GraphQL */ `
extend type Query {
welcomeTooEveryone: String!
}
`
67 changes: 67 additions & 0 deletions e2e/react/src/api/resolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { dico } from './dico'

export const resolvers = {
Query: {
welcome: () => 'Welcome to Houdini 🎩',
links: async (_: any, args: { delay?: number }) => {
if (args.delay) {
await new Promise((resolve) => setTimeout(resolve, args.delay))
}
return [
{ name: 'GitHub', url: 'https://github.com/HoudiniGraphql/houdini' },
{ name: 'Documentation', url: 'https://houdinigraphql.com/' },
{ name: 'Discord', url: 'https://discord.gg/Gd8vfvxpsD' },
]
},
sponsors: async () => {
const res = await fetch(
'https://raw.githubusercontent.com/HoudiniGraphql/sponsors/main/generated/sponsors.json'
)
const jsonData = await res.json()

function getTier(value: number) {
if (value >= 1500) {
return 'Wizard'
}
if (value >= 500) {
return 'Mage'
}
if (value >= 25) {
return "Magician's Apprentice"
}
if (value >= 10) {
return 'Supportive Muggle'
}
return 'Past Sponsors'
}

return jsonData.map(
(c: {
sponsor: {
login: string
name: string
avatarUrl: string
websiteUrl: string
}
monthlyDollars: number
}) => {
return {
login: c.sponsor.login,
name: c.sponsor.name,
avatarUrl: c.sponsor.avatarUrl,
websiteUrl: c.sponsor.websiteUrl,
tiersTitle: getTier(c.monthlyDollars),
}
}
)
},
giveMeAnError: () => {
throw new Error(`Yes, I'm an error!`)
},
},
Mutation: {
hello: (_: any, args: { name: string }) => {
return `${dico.HELLO} ${args.name}!`
},
},
}
25 changes: 25 additions & 0 deletions e2e/react/src/api/typeDefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const typeDefs = /* GraphQL */ `
type Query {
welcome: String!
links(delay: Int): [Link!]!
sponsors: [Sponsor!]!
giveMeAnError: String
}
type Mutation {
hello(name: String!): String!
}
type Link {
name: String
url: String
}
type Sponsor {
login: String!
name: String!
avatarUrl: String!
websiteUrl: String
tiersTitle: String!
}
`
8 changes: 4 additions & 4 deletions packages/houdini-react/src/plugin/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
type ArtifactKinds,
type Document,
type Config,
type Plugin,
ArtifactKind,
plugin,
fragmentKey,
load_manifest,
type ArtifactKinds,
type Document,
type Config,
type Plugin,
type ProjectManifest,
} from 'houdini'
import path from 'node:path'
Expand Down
4 changes: 2 additions & 2 deletions packages/houdini-react/src/plugin/vite.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
PluginHooks,
path,
fs,
load_manifest,
isSecondaryBuild,
load_manifest,
path,
type ProjectManifest,
type RouterManifest,
routerConventions,
Expand Down
7 changes: 6 additions & 1 deletion packages/houdini/src/codegen/generators/definitions/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import * as graphql from 'graphql'

import type { Config } from '../../../lib'
import { fs } from '../../../lib'
import enums from './enums'

// schemaGenerator updates the schema file to contain all of the generated
export default async function schemaGenerator(config: Config) {
await Promise.all([
fs.writeFile(config.definitionsSchemaPath, config.newSchema),
fs.writeFile(
config.definitionsSchemaPath,
config.localSchema ? graphql.printSchema(config.schema) : config.newSchema
),
fs.writeFile(config.definitionsDocumentsPath, config.newDocuments),
enums(config),
])
Expand Down
12 changes: 8 additions & 4 deletions packages/houdini/src/lib/router/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type * as graphql from 'graphql'
import path from 'node:path'

import type { Config } from '../config'
import { type ConfigFile, localApiEndpoint } from '../types'
import { localApiEndpoint, type ConfigFile } from '../types'

export function isSecondaryBuild() {
return process.env.HOUDINI_SECONDARY_BUILD && process.env.HOUDINI_SECONDARY_BUILD !== 'false'
Expand All @@ -26,22 +26,26 @@ export async function buildLocalSchema(config: Config): Promise<void> {

process.env.HOUDINI_SECONDARY_BUILD = 'true'

const schema = path.join(config.localApiDir, '+schema')

// build the schema somewhere we can import from
await build({
logLevel: 'silent',
build: {
outDir: path.join(config.rootDir, 'temp'),
rollupOptions: {
input: {
schema: path.join(config.localApiDir, '+schema'),
schema,
},
output: {
entryFileNames: 'assets/[name].js',
},
},
ssr: true,
lib: {
entry: path.join(config.localApiDir, '+schema'),
entry: {
schema,
},
formats: ['es'],
},
},
Expand All @@ -55,7 +59,7 @@ export async function loadLocalSchema(config: Config): Promise<graphql.GraphQLSc

// import the schema we just built
const { default: schema } = await import(
path.join(config.rootDir, 'temp', 'assets', 'schema.js')
path.join(config.rootDir, 'temp', 'assets', `schema.js?${Date.now().valueOf()}}`)
)

return schema
Expand Down
30 changes: 23 additions & 7 deletions packages/houdini/src/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import generate from '../codegen'
import type { PluginConfig } from '../lib'
import { getConfig, formatErrors, path, loadLocalSchema } from '../lib'
import houdini_vite from './houdini'
import watch_remote_schema from './schema'
import { watch_local_schema, watch_remote_schema } from './schema'

export * from './ast'
export * from './imports'
Expand All @@ -18,23 +18,39 @@ export default function (opts?: PluginConfig): Plugin[] {
// so we don't get an error when importing.
process.env.HOUDINI_PLUGIN = 'true'

// a container of a list
const watchSchemaListref = { list: [] as string[] }

return [
houdini_vite(opts),
watch_remote_schema(opts),
watch_local_schema(watchSchemaListref),
watch_and_run([
{
name: 'Houdini',
quiet: true,
async watchFile(filepath: string) {
// load the config file
let config = await getConfig(opts)
const config = await getConfig(opts)

// we need to watch some specific files
const schemaPath = path.join(path.dirname(config.filepath), config.schemaPath!)
if (minimatch(filepath, schemaPath)) {
// if it's a schema change, let's reload the config
config = await getConfig({ ...opts, forceReload: true })
return true
if (config.localSchema) {
const toWatch = watchSchemaListref.list
if (toWatch.includes(filepath)) {
// if it's a schema change, let's reload the config
await getConfig({ ...opts, forceReload: true })
return true
}
} else {
const schemaPath = path.join(
path.dirname(config.filepath),
config.schemaPath!
)
if (minimatch(filepath, schemaPath)) {
// if it's a schema change, let's reload the config
await getConfig({ ...opts, forceReload: true })
return true
}
}

return config.includeFile(filepath, { root: process.cwd() })
Expand Down
Loading

0 comments on commit a6a5147

Please sign in to comment.