Skip to content

Commit

Permalink
React type root (#1087)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlecAivazis committed May 15, 2023
1 parent 4a30b1a commit 580554b
Show file tree
Hide file tree
Showing 17 changed files with 317 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Link } from '$houdini'

export default function ({ HelloRouter, children }) {
import type { LayoutProps } from './$types'

export default function ({ HelloRouter, children }: LayoutProps) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
message: {HelloRouter.message}
Expand Down
5 changes: 0 additions & 5 deletions e2e/router/src/routes/+page.jsx

This file was deleted.

5 changes: 5 additions & 0 deletions e2e/router/src/routes/+page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { PageProps } from './$types'

export default function ({ HelloRouter }: PageProps) {
return <div>{HelloRouter.message}!</div>
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { PendingValue, isPending } from '$houdini'
import { isPending } from '$houdini'
import React from 'react'

export default function ({ UserInfo }) {
import type { PageProps } from './$types'

export default function ({ UserInfo }: PageProps) {
const { user } = UserInfo

// if we are loading the user render the loading state
Expand Down
24 changes: 1 addition & 23 deletions e2e/router/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,3 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"paths": {
"$houdini": ["./$houdini"],
"$houdini/*": ["./$houdini/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
"extends": "./$houdini/tsconfig.json"
}
9 changes: 0 additions & 9 deletions e2e/router/tsconfig.node.json

This file was deleted.

8 changes: 0 additions & 8 deletions e2e/router/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import react from '@vitejs/plugin-react'
import houdini from 'houdini/vite'
import path from 'path'
import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [houdini(), react({ fastRefresh: false })],
// TODO: the vite plugin should do this
resolve: {
alias: {
$houdini: path.resolve('.', '/$houdini'),
'$houdini/*': path.resolve('.', '/$houdini', '*'),
},
},
})
7 changes: 6 additions & 1 deletion packages/houdini-react/src/plugin/codegen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { GenerateHookInput } from 'houdini'
import { generate_entries } from './entries'
import type { ProjectManifest } from './manifest'
import { generate_renders } from './render'
import { generate_type_root } from './typeRoot'

/**
* The router is fundamentally a component that knows how to render
Expand All @@ -18,5 +19,9 @@ export default async function routerCodegen({
manifest,
}: GenerateHookInput & { manifest: ProjectManifest }) {
// use the manifest to generate all of the necessary project files
await Promise.all([generate_entries({ config, manifest }), generate_renders(config)])
await Promise.all([
generate_entries({ config, manifest }),
generate_renders(config),
generate_type_root({ config, manifest }),
])
}
56 changes: 46 additions & 10 deletions packages/houdini-react/src/plugin/codegen/manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ test('route groups', async function () {
"_0",
"_0_3subRoute_4"
],
"path": "(subRoute)/nested/+page.tsx"
"path": "src/routes/(subRoute)/nested/+page.tsx",
"query_options": [
"RootQuery",
"FinalQuery"
]
}
},
"layouts": {
Expand All @@ -69,7 +73,8 @@ test('route groups', async function () {
"queries": [],
"url": "/",
"layouts": [],
"path": "+layout.tsx"
"path": "src/routes/+layout.tsx",
"query_options": []
},
"_0_3subRoute_4": {
"id": "_0_3subRoute_4",
Expand All @@ -80,7 +85,10 @@ test('route groups', async function () {
"layouts": [
"_0"
],
"path": "(subRoute)/+layout.tsx"
"path": "src/routes/(subRoute)/+layout.tsx",
"query_options": [
"RootQuery"
]
}
},
"page_queries": {
Expand Down Expand Up @@ -146,7 +154,10 @@ test('nested route structure happy path', async function () {
"layouts": [
"_0"
],
"path": "+page.tsx"
"path": "src/routes/+page.tsx",
"query_options": [
"RootQuery"
]
},
"_0subRoute": {
"id": "_0subRoute",
Expand All @@ -159,7 +170,11 @@ test('nested route structure happy path', async function () {
"_0",
"_0subRoute"
],
"path": "subRoute/+page.jsx"
"path": "src/routes/subRoute/+page.jsx",
"query_options": [
"RootQuery",
"SubQuery"
]
},
"_0another": {
"id": "_0another",
Expand All @@ -172,7 +187,12 @@ test('nested route structure happy path', async function () {
"_0",
"_0another"
],
"path": "another/+page.tsx"
"path": "src/routes/another/+page.tsx",
"query_options": [
"RootQuery",
"MyLayoutQuery",
"MyQuery"
]
},
"_0subRoute_0nested": {
"id": "_0subRoute_0nested",
Expand All @@ -184,7 +204,12 @@ test('nested route structure happy path', async function () {
"_0",
"_0subRoute"
],
"path": "subRoute/nested/+page.tsx"
"path": "src/routes/subRoute/nested/+page.tsx",
"query_options": [
"RootQuery",
"SubQuery",
"FinalQuery"
]
}
},
"layouts": {
Expand All @@ -193,7 +218,10 @@ test('nested route structure happy path', async function () {
"queries": [],
"url": "/",
"layouts": [],
"path": "+layout.tsx"
"path": "src/routes/+layout.tsx",
"query_options": [
"RootQuery"
]
},
"_0another": {
"id": "_0another",
Expand All @@ -204,7 +232,11 @@ test('nested route structure happy path', async function () {
"layouts": [
"_0"
],
"path": "another/+layout.tsx"
"path": "src/routes/another/+layout.tsx",
"query_options": [
"RootQuery",
"MyLayoutQuery"
]
},
"_0subRoute": {
"id": "_0subRoute",
Expand All @@ -215,7 +247,11 @@ test('nested route structure happy path', async function () {
"layouts": [
"_0"
],
"path": "subRoute/+layout.tsx"
"path": "src/routes/subRoute/+layout.tsx",
"query_options": [
"RootQuery",
"SubQuery"
]
}
},
"page_queries": {
Expand Down
7 changes: 5 additions & 2 deletions packages/houdini-react/src/plugin/codegen/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ async function add_view(args: {
queries,
url: args.url,
layouts: args.layouts,
path: path.relative(args.config.routesDir, args.path),
path: path.relative(args.config.projectRoot, args.path),
query_options: args.queries,
}

return target[id]
Expand Down Expand Up @@ -219,7 +220,7 @@ async function add_query(args: {
}

export async function extractQueries(source: string): Promise<string[]> {
const ast = await parseJS(source, { plugins: ['jsx'] })
const ast = parseJS(source, { plugins: ['jsx'] })

let defaultExportNode: t.Node | null = null
let defaultExportIdentifier: string | null = null
Expand Down Expand Up @@ -319,6 +320,8 @@ export type PageManifest = {
id: string
/** the name of every query that the page depends on */
queries: string[]
/** the list of queries that this page could potentially ask for */
query_options: string[]
/** the full url pattern of the page */
url: string
/** the ids of layouts that wrap this page */
Expand Down
50 changes: 50 additions & 0 deletions packages/houdini-react/src/plugin/codegen/typeRoot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { fs } from 'houdini'
import { test, expect } from 'vitest'

import { test_config } from '../config'
import { load_manifest } from './manifest'
import { generate_type_root } from './typeRoot'

test('generates type files for pages', async function () {
const config = await test_config()

// create the mock filesystem
await fs.mock({
[config.routesDir]: {
'+layout.gql': mockQuery('LayoutQuery'),
'+page.tsx': mockView(['LayoutQuery']),
'(subRoute)': {
'+page.tsx': mockView(['FinalQuery']),
'+page.gql': mockQuery('FinalQuery', true),
'+layout.gql': mockQuery('RootQuery'),
},
},
})

const manifest = await load_manifest({
config,
})

// generate the type rot
await generate_type_root({ config, manifest })

// make sure we generated the right thing
expect(fs.snapshot(config.typeRootDir)).toMatchInlineSnapshot(`
{
"/src/routes/(subRoute)/$types.d.ts": "\\nimport { DocumentHandle } from '../../../../plugins/houdini-react/runtime'\\nimport React from 'react'\\n\\nimport type { LayoutQuery$result, LayoutQuery$artifact, LayoutQuery$input } from '../../../../artifacts/LayoutQuery'\\nimport type { RootQuery$result, RootQuery$artifact, RootQuery$input } from '../../../../artifacts/RootQuery'\\nimport type { FinalQuery$result, FinalQuery$artifact, FinalQuery$input } from '../../../../artifacts/FinalQuery'\\n\\n\\nexport type PageProps = {\\n LayoutQuery: LayoutQuery$result,\\n LayoutQuery$handle: DocumentHandle<LayoutQuery$artifact, LayoutQuery$result, LayoutQuery$input>,\\n RootQuery: RootQuery$result,\\n RootQuery$handle: DocumentHandle<RootQuery$artifact, RootQuery$result, RootQuery$input>,\\n FinalQuery: FinalQuery$result,\\n FinalQuery$handle: DocumentHandle<FinalQuery$artifact, FinalQuery$result, FinalQuery$input>,\\n}\\n\\n\\n\\n",
"/src/routes/$types.d.ts": "\\nimport { DocumentHandle } from '../../../plugins/houdini-react/runtime'\\nimport React from 'react'\\n\\nimport type { LayoutQuery$result, LayoutQuery$artifact, LayoutQuery$input } from '../../../artifacts/LayoutQuery'\\n\\n\\nexport type PageProps = {\\n LayoutQuery: LayoutQuery$result,\\n LayoutQuery$handle: DocumentHandle<LayoutQuery$artifact, LayoutQuery$result, LayoutQuery$input>,\\n}\\n\\n\\n\\n"
}
`)
})

function mockView(deps: string[]) {
return `export default ({ ${deps.join(', ')} }) => <div>hello</div>`
}

function mockQuery(name: string, loading?: boolean) {
return `
query ${name} ${loading ? '@loading' : ''}{
id
}
`
}
Loading

0 comments on commit 580554b

Please sign in to comment.