Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow changing the Houdini generated output directory #1386

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/spicy-masks-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'houdini-adapter-static': minor
'houdini-svelte': minor
'houdini-react': minor
'houdini': minor
---

Added support for configuring Houdini's output directory
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ vite.config.*.timestamp-*

.vercel
.netlify

mise.toml
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
auto-install-peers=true
strict-peer-dependencies=false

engine-strict=true
4 changes: 2 additions & 2 deletions e2e/kit/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ node_modules
.env.*
!.env.example

$houdini
.houdini
playwright-report
test-results
test-results
1 change: 1 addition & 0 deletions e2e/kit/houdini.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const config = {
schemaPath: '../_api/*.graphql',
defaultPartial: true,
acceptImperativeInstability: true,
runtimeDir: '.houdini',
// logLevel: 'Full',
scalars: {
DateTime: {
Expand Down
3 changes: 1 addition & 2 deletions e2e/kit/svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ const config = {
adapter: adapter(),

alias: {
$houdini: path.resolve('./$houdini'),
$lib: path.resolve('./src/lib')
$houdini: '.houdini/'
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion e2e/kit/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"rootDirs": [".", "./.svelte-kit/types", "./$houdini/types"],
"rootDirs": [".", "./.svelte-kit/types", "./.houdini/types"],
"noImplicitAny": true
}
}
16 changes: 8 additions & 8 deletions e2e/kit/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,30 @@ const config = {
libReporter([
{
name: 'houdini runtime core',
includes: ['$houdini/runtime'],
includes: ['.houdini/runtime'],
excludes: [
'$houdini/index.js',
'$houdini/plugins/index.js',
'.houdini/index.js',
'.houdini/plugins/index.js',
'houdini.config.js',
'graphql-ws',
'svelte'
]
},
{
name: 'houdini runtime svelte',
includes: ['$houdini/plugins/houdini-svelte/runtime', 'src/client.ts'],
includes: ['.houdini/plugins/houdini-svelte/runtime', 'src/client.ts'],
excludes: [
'$houdini/runtime',
'$houdini/index.js',
'$houdini/plugins/index.js',
'.houdini/runtime',
'.houdini/index.js',
'.houdini/plugins/index.js',
'graphql-ws',
'vite/preload-helper',
'svelte'
]
},
{
name: 'houdini full e2e',
includes: ['$houdini', 'src/client.ts', 'houdini.config.js'],
includes: ['.houdini', 'src/client.ts', 'houdini.config.js'],
excludes: ['graphql-ws', 'vite/preload-helper', 'svelte']
}
])
Expand Down
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@
"*.js": "prettier -w ",
"*.json": "prettier -w "
},
"resolutions": {
"graphql": "15.5.0"
"pnpm": {
"overrides": {
"graphql": "15.5.0"
}
},
"engines": {
"node": "^20",
"pnpm": "^8"
}
}
12 changes: 6 additions & 6 deletions packages/adapter-static/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ import ReactDOM from 'react-dom/server'
// in order to prepare the app as a single-page app, we have 2 create 2 additional files:
// - an index.js that imports the application and calls React.render. This file needs to be built by vite so it's passed with the includePaths option for an adapter
// - an index.html containing the static shell that wraps the application.
const adapter: Adapter = async ({ outDir }) => {
const adapter: Adapter = async ({ outDir, config: { runtimeDir } }) => {
// the first thing we need to do is pull out the rendered html file into the root of the outDir
await fs.copyFile(
path.join(outDir, 'assets', '$houdini', 'temp', 'spa-shell', 'index.html'),
path.join(outDir, 'assets', runtimeDir, 'temp', 'spa-shell', 'index.html'),
path.join(outDir, 'index.html')
)

try {
await fs.rmdir(path.join(outDir, 'assets', '$houdini'))
await fs.rmdir(path.join(outDir, 'assets', runtimeDir))
} catch {}
}

// make sure we include the app entry point in the bundle
adapter.includePaths = {
shell: '$houdini/temp/spa-shell/index.html',
}
adapter.includePaths = ({ config: { runtimeDir } }) => ({
shell: path.join(runtimeDir, 'temp', 'spa-shell', 'index.html'),
})

// we dont want any server artifacts to be generated
adapter.disableServer = true
Expand Down
2 changes: 1 addition & 1 deletion packages/houdini-react/src/plugin/codegen/typeRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export async function generate_type_root({

const all_queries = (page?.query_options ?? []).concat(layout?.query_options ?? [])

// compute the path prefix to bring us to the root of the $houdini directory
// compute the path prefix to bring us to the root of the houdini runtimeDir
const relative = path.relative(target_dir, config.rootDir)

// build up the type definitions
Expand Down
17 changes: 12 additions & 5 deletions packages/houdini-react/src/plugin/vite.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {
PluginHooks,
fs,
isSecondaryBuild,
load_manifest,
path,
PluginHooks,
type ProjectManifest,
type RouterManifest,
routerConventions,
type RouterManifest,
} from 'houdini'
import React from 'react'
import { build, ConfigEnv, type BuildOptions, type Connect } from 'vite'
import { build, type BuildOptions, ConfigEnv, type Connect } from 'vite'

import { manifest, setManifest } from '.'

Expand Down Expand Up @@ -72,8 +72,15 @@ export default {
'entries/adapter': routerConventions.adapter_config_path(config),
}

if (env.command === 'build' && config.adapter && config.adapter?.includePaths) {
Object.assign(conf.build!.rollupOptions!.input, config.adapter?.includePaths)
if (env.command === 'build' && config.adapter && config.adapter.includePaths) {
if (typeof config.adapter?.includePaths === 'function') {
Object.assign(
conf.build!.rollupOptions!.input,
config.adapter.includePaths({ config })
)
} else {
Object.assign(conf.build!.rollupOptions!.input, config.adapter.includePaths)
}
}

// every page in the manifest is a new entry point for vite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default async function componentTypesGenerator(
// we can just filter out the ones that don't apply:t
// - in kit, exclude the route directory
// - group the files by directory
// - generate ./$houdini in the typeroot directory at the correct spot
// - generate runtimeDir in the typeroot directory at the correct spot

// there could be many queries in a given component so we can't just think about filepaths
const queries: Record<string, { name: string; query: string }[]> = {}
Expand Down
2 changes: 1 addition & 1 deletion packages/houdini-svelte/src/plugin/fsPatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ function is_root_route(filepath: PathLike): boolean {
filepath.endsWith(path.join('src', 'routes')) &&
// ignore the src/routes that exists in the type roots
!filepath.includes('.svelte-kit') &&
!filepath.includes('$houdini')
!filepath.includes(_config.runtimeDir ?? '$houdini')
endigma marked this conversation as resolved.
Show resolved Hide resolved
)
}

Expand Down
24 changes: 13 additions & 11 deletions packages/houdini/src/cmd/init.ts
endigma marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ async function houdiniConfig(
}
}

config.runtimeDir = '.houdini'

// if it's different for defaults, write it down
if (schemaPath !== './schema.graphql') {
config.schemaPath = schemaPath
Expand Down Expand Up @@ -431,7 +433,7 @@ const config = {
kit: {
adapter: adapter(),
alias: {
$houdini: './$houdini',
$houdini: '.houdini/'
}
}
};
Expand All @@ -446,7 +448,7 @@ const config = {
kit: {
adapter: adapter(),
alias: {
$houdini: './$houdini',
$houdini: '.houdini/'
}
}
};
Expand All @@ -465,8 +467,8 @@ async function gitIgnore(targetPath: string) {
const filepath = path.join(targetPath, '.gitignore')
const existing = (await fs.readFile(filepath)) || ''

if (!existing.includes('\n$houdini\n')) {
await fs.writeFile(filepath, existing + '\n$houdini\n')
if (!existing.includes('\n.houdini\n')) {
await fs.writeFile(filepath, existing + '\n.houdini\n')
}
}

Expand All @@ -478,11 +480,11 @@ async function graphqlRC(targetPath: string) {
default:
schema:
- ./schema.graphql
- ./$houdini/graphql/schema.graphql
- ./.houdini/graphql/schema.graphql
documents:
- '**/*.gql'
- '**/*.svelte'
- ./$houdini/graphql/documents.gql
- ./.houdini/graphql/documents.gql
`

await fs.writeFile(target, content)
Expand All @@ -507,7 +509,7 @@ export default defineConfig({

resolve: {
alias: {
$houdini: path.resolve('$houdini'),
$houdini: '.houdini/',
},
},
})
Expand Down Expand Up @@ -553,9 +555,9 @@ async function tjsConfig(targetPath: string, frameworkInfo: HoudiniFrameworkInfo

// new rootDirs (will overwrite the one in "extends": "./.svelte-kit/tsconfig.json")
if (frameworkInfo.framework === 'svelte') {
tjsConfig.compilerOptions.rootDirs = ['.', './$houdini/types']
tjsConfig.compilerOptions.rootDirs = ['.', './.houdini/types']
} else if (frameworkInfo.framework === 'kit') {
tjsConfig.compilerOptions.rootDirs = ['.', './.svelte-kit/types', './$houdini/types']
tjsConfig.compilerOptions.rootDirs = ['.', './.svelte-kit/types', './.houdini/types']
}

// In kit, no need to add manually the path. Why? Because:
Expand All @@ -565,8 +567,8 @@ async function tjsConfig(targetPath: string, frameworkInfo: HoudiniFrameworkInfo
if (frameworkInfo.framework === 'svelte') {
tjsConfig.compilerOptions.paths = {
...tjsConfig.compilerOptions.paths,
$houdini: ['./$houdini'],
'$houdini/*': ['./$houdini/*'],
$houdini: ['./.houdini/'],
'$houdini/*': ['./.houdini/*'],
}
}

Expand Down
15 changes: 8 additions & 7 deletions packages/houdini/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ export class Config {
localSchema: boolean
projectRoot: string
schema: graphql.GraphQLSchema
runtimeDir?: string
schemaPath?: string
persistedQueriesPath: string = './$houdini/persisted_queries.json'
persistedQueriesPath: string
exclude: string[]
scalars?: ConfigFile['scalars']
module: 'commonjs' | 'esm' = 'esm'
Expand Down Expand Up @@ -101,6 +102,7 @@ export class Config {
let {
schema,
schemaPath = './schema.graphql',
runtimeDir = '$houdini',
exclude = [],
module = 'esm',
scalars,
Expand Down Expand Up @@ -145,6 +147,7 @@ export class Config {
this.projectRoot = path.dirname(
projectDir ? path.join(process.cwd(), projectDir) : filepath
)
this.runtimeDir = runtimeDir
this.scalars = scalars
this.cacheBufferSize = cacheBufferSize
this.defaultCachePolicy = defaultCachePolicy
Expand All @@ -159,13 +162,11 @@ export class Config {
this.schemaPollInterval = watchSchema?.interval === undefined ? 2000 : watchSchema.interval
this.schemaPollTimeout = watchSchema?.timeout ?? 30000
this.schemaPollHeaders = watchSchema?.headers ?? {}
this.rootDir = path.join(this.projectRoot, '$houdini')
this.rootDir = path.join(this.projectRoot, this.runtimeDir)
this.persistedQueriesPath =
persistedQueriesPath ?? path.join(this.rootDir, 'persisted_queries.json')
this.#fragmentVariableMaps = {}

if (persistedQueriesPath) {
this.persistedQueriesPath = persistedQueriesPath
}

// hold onto the key config
if (defaultKeys) {
this.defaultKeys = defaultKeys
Expand Down Expand Up @@ -389,7 +390,7 @@ export class Config {
return path.join(this.rootDir, 'runtime')
}

// Default to => $houdini/graphql
// Default to => <rootDir>/graphql
get definitionsDirectory() {
return this.definitionsFolder
? path.join(this.projectRoot, this.definitionsFolder)
Expand Down
2 changes: 1 addition & 1 deletion packages/houdini/src/lib/router/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type Adapter = ((args: {
manifest: ProjectManifest
adapterPath: string
}) => void | Promise<void>) & {
includePaths?: Record<string, string>
includePaths?: Record<string, string> | ((args: { config: Config }) => Record<string, string>)
disableServer?: boolean
pre?: (args: {
config: Config
Expand Down
8 changes: 7 additions & 1 deletion packages/houdini/src/runtime/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export type ConfigFile = {
watchSchema?: WatchSchemaConfig

/**
* Specifies the the persisted queries path and file. (default: `./$houdini/persisted_queries.json`)
* Specifies the the persisted queries path and file. (default: `<rootDir>/persisted_queries.json`)
*/
persistedQueriesPath?: string

Expand All @@ -205,6 +205,12 @@ export type ConfigFile = {
*/
projectDir?: string

/**
* The relative path from your project directory pointing to your output directory.
* @default `$houdini`
*/
runtimeDir?: string

/**
* For now, the cache's imperative API is considered unstable. In order to suppress the warning,
* you must enable this flag.
Expand Down
5 changes: 3 additions & 2 deletions site/src/routes/api/config/+page.svx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ By default, your config file can contain the following values:
- `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
- `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 server will automatically regenerate your runtime. For more information see [Schema Polling](#schema-polling).
- `persistedQueriesPath` (optional, default: `./$houdini/persisted_queries.json`): Configure the path of the persisted queries file.
- `persistedQueriesPath` (optional, default: `<rootDir>/persisted_queries.json`): Configure the path of the persisted queries file.
- `module` (optional, default: `"esm"`): One of `"esm"` or `"commonjs"`. Used to tell the artifact generator what kind of modules to create.
- `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.
- `definitionsPath` (optional, default: `"<rootDir>/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).
- `cacheBufferSize` (optional, default: `10`): The number of queries that must occur before a value is removed from the cache. For more information, see the [Caching Guide](/guides/caching-data).
- `defaultCachePolicy` (optional, default: `"CacheOrNetwork"`): The default cache policy to use for queries. For a list of the policies or other information see the [Caching Guide](/guides/caching-data).
Expand Down Expand Up @@ -73,6 +73,7 @@ Here is a summary of the possible configuration values:
- `client` (optional, default: `"./src/client"`): a relative path (from houdini.config.js) to a file that exports your houdini client as its default.
- `defaultRouteBlocking` (optional, default: `false`): Specifies the default blocking behavior for client-side navigation. For more information, please visit [this section of the docs](https://houdinigraphql.com/api/query#loading-states).
- `projectDir` (optional, default: `process.cwd()`): an absolute path pointing to your SvelteKit project (useful for monorepos)
- `runtimeDir` (optional, default: `'$houdini`): The name of the directory used to output the generated Houdini runtime, relative to `projectDir`.
- `pageQueryFilename` (optional, default: `"+page.gql"`): The name of the file used to define page queries.
- `layoutQueryFilename` (optional, default: `"+layout.gql"`): The name of the file used to define layout queries.
- `quietQueryErrors` (optional, default: `false`): With this enabled, errors in your query will not be thrown as exceptions. You will have to handle error state in your route components or by hand in your load (or the onError hook)
Expand Down
Loading
Loading