From d46814386d6ab8609aad01a10aeb028e6a829ecb Mon Sep 17 00:00:00 2001 From: Alec Aivazis Date: Mon, 23 Jan 2023 18:00:02 -0800 Subject: [PATCH] Consolidate schema polling config (#842) * move all schema polling things into config.watchSchema * update docs * fix documented watchSchema params * update init command * more doc updates * clean up examples * changeset --- .changeset/breezy-mirrors-provide.md | 5 ++ e2e/sveltekit/houdini.config.js | 1 - example/houdini.config.js | 8 +-- packages/houdini/src/cmd/init.ts | 6 +- packages/houdini/src/lib/config.ts | 12 ++-- packages/houdini/src/runtime/lib/config.ts | 53 +++++++------- packages/houdini/src/test/index.ts | 1 - site/src/routes/api/config/+page.svx | 70 +++++++++++++++---- .../src/routes/guides/release-notes/+page.svx | 23 ++++++ 9 files changed, 123 insertions(+), 56 deletions(-) create mode 100644 .changeset/breezy-mirrors-provide.md diff --git a/.changeset/breezy-mirrors-provide.md b/.changeset/breezy-mirrors-provide.md new file mode 100644 index 0000000000..25c2d2c8b8 --- /dev/null +++ b/.changeset/breezy-mirrors-provide.md @@ -0,0 +1,5 @@ +--- +'houdini': major +--- + +Grouped `apiUrl`, `schemaPollHeaders`, and `schemaPollInterval` together diff --git a/e2e/sveltekit/houdini.config.js b/e2e/sveltekit/houdini.config.js index 0ae14aa921..2eccafd02a 100644 --- a/e2e/sveltekit/houdini.config.js +++ b/e2e/sveltekit/houdini.config.js @@ -4,7 +4,6 @@ /** @type {import('houdini').ConfigFile} */ const config = { schemaPath: '../_api/*.graphql', - defaultCachePolicy: 'CacheOrNetwork', defaultPartial: true, scalars: { DateTime: { diff --git a/example/houdini.config.js b/example/houdini.config.js index 44663169e2..0c16fa48c6 100644 --- a/example/houdini.config.js +++ b/example/houdini.config.js @@ -1,6 +1,8 @@ /** @type {import('houdini').ConfigFile} */ const config = { - apiUrl: 'http://localhost:4000/graphql', + watchSchema: { + url: 'http://localhost:4000/graphql', + }, scalars: { DateTime: { type: 'Date', @@ -13,9 +15,7 @@ const config = { }, }, plugins: { - 'houdini-svelte': { - client: './src/client.ts', - }, + 'houdini-svelte': {}, }, } diff --git a/packages/houdini/src/cmd/init.ts b/packages/houdini/src/cmd/init.ts index 632807db0b..d1c77bb18a 100644 --- a/packages/houdini/src/cmd/init.ts +++ b/packages/houdini/src/cmd/init.ts @@ -285,7 +285,9 @@ const writeConfigFile = async ({ // if we have no url, we are using a local schema if (url !== null) { - config.apiUrl = url + config.watchSchema = { + url, + } } // if it's different for defaults, write it down @@ -563,7 +565,7 @@ async function detectTools(cwd: string): Promise { const hasDependency = (dep: string) => Boolean(devDependencies?.[dep] || dependencies?.[dep]) - let framework: ConfigFile['framework'] = 'svelte' + let framework: 'svelte' | 'kit' = 'svelte' if (hasDependency('@sveltejs/kit')) { framework = 'kit' } diff --git a/packages/houdini/src/lib/config.ts b/packages/houdini/src/lib/config.ts index a3f68550af..5414a93c50 100644 --- a/packages/houdini/src/lib/config.ts +++ b/packages/houdini/src/lib/config.ts @@ -96,8 +96,7 @@ export class Config { types = {}, logLevel, defaultFragmentMasking = 'enable', - schemaPollInterval = 2000, - schemaPollHeaders = {}, + watchSchema, projectDir, } = this.configFile @@ -136,8 +135,8 @@ export class Config { this.logLevel = ((logLevel as LogLevel) || LogLevel.Summary).toLowerCase() as LogLevel this.defaultFragmentMasking = defaultFragmentMasking this.routesDir = path.join(this.projectRoot, 'src', 'routes') - this.schemaPollInterval = schemaPollInterval - this.schemaPollHeaders = schemaPollHeaders + this.schemaPollInterval = watchSchema?.interval ?? 2000 + this.schemaPollHeaders = watchSchema?.headers ?? {} this.rootDir = path.join(this.projectRoot, '$houdini') // hold onto the key config @@ -153,12 +152,13 @@ export class Config { } async apiURL() { - if (!this.configFile.apiUrl) { + const apiURL = this.configFile.watchSchema?.url + if (!apiURL) { return '' } const env = await this.getEnv() - return this.processEnvValues(env, this.configFile.apiUrl) + return this.processEnvValues(env, apiURL) } get include() { diff --git a/packages/houdini/src/runtime/lib/config.ts b/packages/houdini/src/runtime/lib/config.ts index 91b511f720..b41b9dbb03 100644 --- a/packages/houdini/src/runtime/lib/config.ts +++ b/packages/houdini/src/runtime/lib/config.ts @@ -84,11 +84,6 @@ export type ConfigFile = { */ schema?: string | GraphQLSchema - /** - * A url to use to pull the schema. For more information: https://www.houdinigraphql.com/api/cli#generate - */ - apiUrl?: string | ((env: Record) => string) - /** * An object describing custom scalars for your project. For more information: https://www.houdinigraphql.com/api/config#custom-scalars */ @@ -99,12 +94,6 @@ export type ConfigFile = { */ definitionsPath?: string - /** - * One of "kit" or "svelte". Used to tell the preprocessor what kind of loading paradigm to generate for you. (default: `kit`) - * @deprecated please follow the steps here: http://www.houdinigraphql.com/guides/release-notes#0170 - */ - framework?: 'kit' | 'svelte' - /** * One of "esm" or "commonjs". Tells the artifact generator what kind of modules to create. (default: `esm`) */ @@ -158,23 +147,9 @@ export type ConfigFile = { defaultFragmentMasking?: 'enable' | 'disable' /** - * Configures the houdini plugin's schema polling behavior. By default, houdini will poll your APIs - * during development in order to keep it's definition of your schema up to date. The schemaPollingInterval - * config value sets the amount of time between each request in milliseconds (default 2 seconds). - * To limit the schema introspection to just on the start of the server, set schemaPollingInterval to 0. - * To disable the schema introspection, set schemaPollingInterval to null. + * Configure the dev environment to watch a remote schema for changes */ - schemaPollInterval?: number | null - - /** - * An object containing the environment variables you want passed onto the api when polling for a new schema. - * The keys dictate the header names. If the value is a string, the corresponding environment variable will be used - * directly. If the value is a function, the current environment will be passed to your function so you can perform any - * logic you need - */ - schemaPollHeaders?: - | Record) => string)> - | ((env: Record) => Record) + watchSchema?: WatchSchemaConfig /** * An object describing the plugins enabled for the project @@ -206,6 +181,30 @@ export type TypeConfig = { } } +export type WatchSchemaConfig = { + /** + * A url to use to pull the schema. For more information: https://www.houdinigraphql.com/api/cli#generate + */ + url: string | ((env: Record) => string) + + /** + * sets the amount of time between each request in milliseconds (default 2 seconds). + * To limit the schema introspection to just on the start of the server, set interval to 0. + * To disable the schema introspection, set interval to null. + */ + interval?: number | null + + /** + * An object containing the environment variables you want passed onto the api when polling for a new schema. + * The keys dictate the header names. If the value is a string, the corresponding environment variable will be used + * directly. If the value is a function, the current environment will be passed to your function so you can perform any + * logic you need + */ + headers?: + | Record) => string)> + | ((env: Record) => Record) +} + export type ScalarSpec = { // the type to use at runtime type: string diff --git a/packages/houdini/src/test/index.ts b/packages/houdini/src/test/index.ts index 46abe1a960..439cf25223 100644 --- a/packages/houdini/src/test/index.ts +++ b/packages/houdini/src/test/index.ts @@ -226,7 +226,6 @@ export function testConfigFile({ plugins, ...config }: Partial = {}) }, }, }, - framework: 'kit', types: { Ghost: { keys: ['name', 'aka'], diff --git a/site/src/routes/api/config/+page.svx b/site/src/routes/api/config/+page.svx index 6f991514a1..91932d49cd 100644 --- a/site/src/routes/api/config/+page.svx +++ b/site/src/routes/api/config/+page.svx @@ -8,12 +8,21 @@ description: A description of every valid configuration value for Houdini. All configuration for your houdini application is defined in a single file that is imported by both the runtime and the command-line tool (called `houdini.config.js`). Because of this, you must make sure that any imports and logic are resolvable in both environments. This means that if you rely on process.env or other node-specifics you will have to use a plugin to replace the expression with something that can run in the browser. ```javascript:title=houdini.config.js +/** @type {import('houdini').ConfigFile} */ export default { - apiUrl: 'http://localhost:4000/graphql', - schemaPollHeaders: { - Authentication(env) { - return `Bearer ${env.AUTH_TOKEN}` - } + watchSchema: { + url: 'http://localhost:4000/graphql', + }, + scalars: { + DateTime: { + type: 'Date', + unmarshal(val) { + return new Date(val) + }, + marshal(date) { + return date.getTime() + } + } } } ``` @@ -25,7 +34,7 @@ By default, your config file can contain the following values: - `include` (optional, default: `"src/**/*.{svelte,graphql,gql,ts,js}"`): a pattern (or list of patterns) to identify source code files. - `exclude` (optional): a pattern (or list of patterns) that filters out files that match the include pattern - `schemaPath` (optional, default: `"./schema.graphql"`): the path to the static representation of your schema, can be a glob pointing to multiple files -- `apiUrl` (optional, a string or function): Configures the url to use to pull the schema. If you don't pass an `apiUrl`, the kit plugin will not poll for schema changes. If you want to access an environment variable, you can either prefix your string with `env:` or set it to a function that takes the current environment and returns a string. For more information see the [section below](#environment-variables). +- `watchSchema` (optional, an object): configure the development server to poll a remote url for changes in the schema. When a change is detected, the dev serer will automatically regenerate your runtime. For more information see [Schema Polling](#schema-polling). - `module` (optional, default: `"esm"`): One of `"esm"` or `"commonjs"`. Used to tell the artifact generator what kind of modules to create. (default: `esm`) - `definitionsPath` (optional, default: `"$houdini/graphql"`): a path that the generator will use to write `schema.graphql` and `documents.gql` files containing all of the internal fragment and directive definitions used in the project. - `scalars` (optional): An object describing custom scalars for your project (see below). @@ -36,8 +45,6 @@ By default, your config file can contain the following values: - `types` (optional): an object that customizes the resolution behavior for a specific type. For more information see the [Caching Guide](/guides/caching-data#custom-ids). - `logLevel` (optional, default: `"summary"`): Specifies the style of logging houdini will use when generating your file. One of "quiet", "full", "summary", or "short-summary". - `defaultFragmentMasking` (optional, default: `enable`): `"enable"` to mask fragment and use collocated data requirement as best or `"disable"` to access fragment data directly in operation. Can be overridden individually at fragment level. -- `schemaPollHeaders` (optional): An object specifying the headers to use when pulling your schema. Keys of the object are header names and its values can be either a strings or a function that takes the current `process.env` and returns the the value to use. If you want to access an environment variable, prefix your string with `env:`, ie `env:API_KEY`. For more information see the [section below](#environment-variables). -- `schemaPollInterval` (optional, default: `2000`): Configures the schema polling behavior for the kit plugin. If its value is greater than `0`, the plugin will poll the set number of milliseconds. If set to `0`, the plugin will only pull the schema when you first run `dev`. If you set to `null`, the plugin will never look for schema changes. You can see use the [pull-schema command](/api/cli#pull-schema) to get updates. - `defaultListTarget` (optional): Can be set to `all` for all list operations to ignore parent ID and affect all lists with the name. - `defaultListPosition` (optional, default: "first"): One of `"first"` or `"last"` to indicate the default location for list operations. - `plugins` (optional): An object containing the set of plugins you want to add to your houdini application. The keys are plugin names, the values are plugin-specific configuration. The actual plugin API is undocumented and considered unstable while we try out various things internally. For an overview of your framework plugin's specific configuration, see below. @@ -47,6 +54,9 @@ By default, your config file can contain the following values: Configuring the svelte plugin is done inside of the `plugins` key in your config file: ```javascript:title=houdini.config.js +/// + +/** @type {import('houdini').ConfigFile} */ export default { // ... plugins: { @@ -89,16 +99,43 @@ export default { } ``` -## Environment Variables +## Schema Polling + +You can configure your development server to poll a remote URL for changes in your schema using the `watchSchema` +argument: + +```typescript +export default { + watchSchema: { + url: 'http://localhost:4000/graphql', + headers: { + Authentication(env) { + return `Bearer ${env.AUTH_TOKEN}` + } + } + } +} +``` + +You can pass the following parameters to `watchSchema`: -There are a few different options for using environment variables in your `apiUrl` and `schemaPollHeaders` +- `url` (a string or function): Configures the url to use to pull the schema. If you don't pass an `apiUrl`, the kit plugin will not poll for schema changes. If you want to access an environment variable, you can either prefix your string with `env:` or set it to a function that takes the current environment and returns a string. For more information see the [section below](#environment-variables). +- `headers` (optional): An object specifying the headers to use when pulling your schema. Keys of the object are header names and its values can be either a strings or a function that takes the current `process.env` and returns the the value to use. If you want to access an environment variable, prefix your string with `env:`, ie `env:API_KEY`. For more information see the [section below](#environment-variables). +- `interval` (optional, default: `2000`): Configures the schema polling behavior for the kit plugin. If its value is greater than `0`, the plugin will poll the set number of milliseconds. If set to `0`, the plugin will only pull the schema when you first run `dev`. If you set to `null`, the plugin will never look for schema changes. You can see use the [pull-schema command](/api/cli#pull-schema) to get updates. + +### Environment Variables + +There are a few different options for using environment variables in your `url` and `headers` config values. Keep in mind that Houdini will look for `.env` and `.env.local` files for environment variables. For simple cases, you can just prepend `env:` to the value: ```javascript export default { - schemaPollHeaders: { - Authentication: 'env:AUTH_TOKEN' + watchSchema: { + url: '...', + headers: { + Authentication: 'env:AUTH_TOKEN' + } } } ``` @@ -109,9 +146,12 @@ environment variables: ```javascript export default { - schemaPollHeaders: { - Authentication: function (env) { - return `Bearer ${env.AUTH_TOKEN}` + watchSchema: { + url: '...', + headers: { + Authentication(env) { + return `Bearer ${env.AUTH_TOKEN}` + } } } } diff --git a/site/src/routes/guides/release-notes/+page.svx b/site/src/routes/guides/release-notes/+page.svx index af53f17a3e..daadbcd38b 100644 --- a/site/src/routes/guides/release-notes/+page.svx +++ b/site/src/routes/guides/release-notes/+page.svx @@ -206,6 +206,29 @@ need to pass a new config to your client: +### Grouped `apiUrl`, `schemaPollHeaders`, and `schemaPollInterval` together + +In order to clarify the difference between the `apiUrl` config value and the +value passed to `HoudiniClient`, we moved all of the schema polling related +config values into a single `watchSchema` object: + +```diff + export default { +- apiUrl: "http://my.awesome.app.com, +- schemaPollInterval: 6000, +- schemaPollHeaders: { +- Authorization: (env) => `Bearer ${env.TOKEN}`, +- }, ++ watchSchema { ++ url: "http://my.awesome.app.com, ++ interval: 6000, ++ headers: { ++ Authorization: (env) => `Bearer ${env.TOKEN}`, ++ } ++ }, +} +``` + ### Imperative Cache Reworked We removed all of that `setFieldType` complexity and now you can read and write data by passing