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

Fix plugin runtime search #1226

Merged
merged 3 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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
Loading