Skip to content

Commit

Permalink
Fix plugin runtime search (#1226)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlecAivazis committed Nov 5, 2023
1 parent 6e7cc7b commit 1a736fc
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 93 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-bees-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'houdini': patch
---

Fix bug causing inifinite loops in vite dev server
2 changes: 1 addition & 1 deletion .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
push:
branches:
- next
- component-fields
- plugin-runtime-search

env:
CI: true
Expand Down
6 changes: 0 additions & 6 deletions packages/houdini-react/src/runtime/routing/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,11 @@ function usePageData({
last_variables.set(artifact, variables)
}

console.log('loading query', artifact.name)

// TODO: AbortController on send()
// TODO: we can read from cache here before making an asynchronous network call

// if there is a pending request and we were asked to load, don't do anything
if (ssr_signals.has(id)) {
console.log('using ssr signal', id)
return ssr_signals.get(id)!
}

Expand All @@ -187,15 +184,13 @@ function usePageData({
resolve = res
reject = rej

console.log('sending query', id, variables)
observer
.send({
variables: variables,
cacheParams: { disableSubscriptions: true },
session,
})
.then(() => {
console.log('resolved query', id, variables)
data_cache.set(id, observer)

// if we are building up a stream (on the server), we want to add something
Expand Down Expand Up @@ -255,7 +250,6 @@ function usePageData({
}
console.log('clearing ssr signal', artifactName)
// trigger the signal
window.__houdini__nav_caches__.ssr_signals.get(artifactName).resolve()
window.__houdini__nav_caches__.ssr_signals.delete(artifactName)
Expand Down
86 changes: 8 additions & 78 deletions packages/houdini/src/codegen/generators/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { exportDefault, exportStarFrom, importDefaultFrom } from '../../../codegen/utils'
import type { Config, Document } from '../../../lib'
import { siteURL as SITE_URL, fs, HoudiniError, path, houdini_mode } from '../../../lib'
import { siteURL as SITE_URL, fs, path } from '../../../lib'
import generateGraphqlReturnTypes from './graphqlFunction'
import injectPlugins from './injectPlugins'
import { generatePluginIndex } from './pluginIndex'
import { generatePluginRuntimes } from './pluginRuntime'
import { injectConfig } from './runtimeConfig'

export default async function runtimeGenerator(config: Config, docs: Document[]) {
Expand Down Expand Up @@ -40,89 +41,18 @@ ${exportStatement('config')}
content
) => injectPlugins({ config, content, importStatement, exportStatement }),
}),
transformPluginRuntimes({ config, docs }),

generatePluginRuntimes({
config,
docs,
}),
generatePluginIndex({ config, exportStatement: exportStar }),
])

await generateGraphqlReturnTypes(config, docs)
}

export async function generatePluginRuntimes({ config }: { config: Config }) {
await Promise.all(
config.plugins
.filter((plugin) => plugin.includeRuntime)
.map(async (plugin) => {
if (houdini_mode.is_testing || !plugin.includeRuntime) {
return
}

// a plugin has told us to include a runtime then the path is relative to the plugin file
const runtime_path = path.join(
path.dirname(plugin.filepath),
typeof plugin.includeRuntime === 'string'
? plugin.includeRuntime
: plugin.includeRuntime[config.module]
)

try {
await fs.stat(runtime_path)
} catch {
throw new HoudiniError({
message: 'Cannot find runtime to generate for ' + plugin.name,
description: 'Maybe it was bundled?',
})
}

// copy the runtime
const pluginDir = config.pluginRuntimeDirectory(plugin.name)

await fs.mkdirp(pluginDir)
await fs.recursiveCopy(runtime_path, pluginDir)
})
)
}

async function transformPluginRuntimes({ config, docs }: { config: Config; docs: Document[] }) {
const { importStatement, exportDefaultStatement, exportStarStatement } = moduleStatments(config)

await Promise.all(
config.plugins
.filter((plugin) => plugin.includeRuntime)
.map(async (plugin) => {
// the transform map holds a map of files to transform functions
let transformMap = plugin.transformRuntime ?? {}
if (transformMap && typeof transformMap === 'function') {
transformMap = transformMap(docs, { config })
}

// the keys of the transform map are the files we have to transform
for (const [target, transform] of Object.entries(transformMap)) {
// the path to the file we're transforming
const targetPath = path.join(config.pluginRuntimeDirectory(plugin.name), target)

// read the file
const content = await fs.readFile(targetPath)
if (!content) {
return
}

// transform the file
const transformed = transform({
config,
content,
importStatement,
exportDefaultStatement: exportDefaultStatement,
exportStarStatement: exportStarStatement,
})

// write the file back out
await fs.writeFile(targetPath, transformed)
}
})
)
}

function moduleStatments(config: Config) {
export function moduleStatments(config: Config) {
const importStatement =
config.module === 'commonjs'
? importDefaultFrom
Expand Down
67 changes: 67 additions & 0 deletions packages/houdini/src/codegen/generators/runtime/pluginRuntime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { moduleStatments } from '.'
import type { Config, Document } from '../../../lib'
import { fs, HoudiniError, path, houdini_mode } from '../../../lib'

export async function generatePluginRuntimes({
config,
docs,
}: {
config: Config
docs: Document[]
}) {
if (houdini_mode.is_testing) {
return
}

// generate the import statements
const { importStatement, exportDefaultStatement, exportStarStatement } = moduleStatments(config)

// generate the runtime for each plugin
await Promise.all(
config.plugins
.filter((plugin) => plugin.includeRuntime)
.map(async (plugin) => {
// a plugin has told us to include a runtime then the path is relative to the plugin file
const runtime_path = config.pluginRuntimeSource(plugin)
if (!runtime_path) {
return
}

// make sure the source file exists
try {
await fs.stat(runtime_path)
} catch {
throw new HoudiniError({
message: 'Cannot find runtime to generate for ' + plugin.name,
description: 'Maybe it was bundled?',
})
}

// copy the runtime
const pluginDir = config.pluginRuntimeDirectory(plugin.name)
let transformMap = plugin.transformRuntime ?? {}
if (transformMap && typeof transformMap === 'function') {
transformMap = transformMap(docs, { config })
}

await fs.mkdirp(pluginDir)
await fs.recursiveCopy(
runtime_path,
pluginDir,
Object.fromEntries(
Object.entries(transformMap).map(([key, value]) => [
path.join(runtime_path, key),
(content) =>
value({
config,
content,
importStatement,
exportDefaultStatement,
exportStarStatement,
}),
])
)
)
})
)
}
5 changes: 0 additions & 5 deletions packages/houdini/src/codegen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@ import type { Config, PluginHooks, Document, LogLevels } from '../lib'
import { runPipeline as run, LogLevel, find_graphql, parseJS, HoudiniError, fs, path } from '../lib'
import { ArtifactKind, type ArtifactKinds } from '../runtime/lib/types'
import * as generators from './generators'
import { generatePluginRuntimes } from './generators/runtime'
import * as transforms from './transforms'
import * as validators from './validators'

// the main entry point of the compile script
export default async function compile(config: Config) {
// before we collect the documents, we need to generate the plugin runtimes
// so that they can include documents in the user's project
await generatePluginRuntimes({ config })

// grab the graphql documents
const documents = await collectDocuments(config)

Expand Down
5 changes: 4 additions & 1 deletion packages/houdini/src/lib/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ test('Config.include includes plugin runtimes', () => {
]

// make sure we are including the plugin runtime
const includePath = path.relative(config.projectRoot, config.pluginDirectory('test-plugin'))
const includePath = path.relative(
config.projectRoot,
config.pluginRuntimeSource(config.plugins[0])!
)
expect(config.include.some((path) => path.includes(includePath))).toBeTruthy()
})
19 changes: 17 additions & 2 deletions packages/houdini/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,15 @@ export class Config {
// if any of the plugins specify included runtimes then their paths might have
// documents
for (const plugin of this.plugins) {
const runtimeDir = this.pluginRuntimeSource(plugin)

// skip plugins that dont' include runtimes
if (!plugin.includeRuntime) {
if (!runtimeDir) {
continue
}

// the include path is relative to root of the vite project
const includePath = path.relative(this.projectRoot, this.pluginDirectory(plugin.name))
const includePath = path.relative(this.projectRoot, runtimeDir)

// add the plugin's directory to the include pile
include.push(`${includePath}/**/*{${extensions.join(',')}}`)
Expand Down Expand Up @@ -280,6 +282,19 @@ export class Config {
return headers
}

pluginRuntimeSource(plugin: PluginMeta) {
if (!plugin.includeRuntime) {
return null
}

return path.join(
path.dirname(plugin.filepath),
typeof plugin.includeRuntime === 'string'
? plugin.includeRuntime
: plugin.includeRuntime?.[this.module]
)
}

async sourceFiles() {
return [
...new Set(
Expand Down

0 comments on commit 1a736fc

Please sign in to comment.