Skip to content

Commit

Permalink
generate component side of ssr fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
AlecAivazis committed Aug 3, 2022
1 parent 68201f5 commit f541db4
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 37 deletions.
12 changes: 2 additions & 10 deletions src/vite/transforms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ export default async function applyTransforms(
return { code: content }
}

// we need to apply the changes to the file. we'll do this by printing the mutated
// content as a string and then replacing everything between the appropriate
// script tags. the parser tells us the locations for the different tags so we
// just have to replace the indices it tells us to
const printedInstance = result.script ? (recast.print(result.script).code as string) : ''

// just copy the instance where it needs to go
return {
code: printedInstance,
}
// print the result
return recast.print(result.script)
}
99 changes: 87 additions & 12 deletions src/vite/transforms/kit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ describe('kit route processor', function () {

// make sure we added the right stuff
expect(route.component).toMatchInlineSnapshot(`
import { houdini_load } from "./+page.js";
import { browser } from "$app/env";
import { getHoudiniContext } from "$houdini/runtime/lib/context";
import { GQL_TestQuery } from "$houdini/stores/TestQuery";
$:
_houdini_inputs = $$props.data.inputs;
const _houdini_context_DO_NOT_USE = getHoudiniContext();
$:
browser && GQL_TestQuery.fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["TestQuery"]
});
const {
data
} = query(GQL_TestQuery);
Expand Down Expand Up @@ -106,17 +120,37 @@ describe('kit route processor', function () {

// make sure we added the right stuff
expect(route.component).toMatchInlineSnapshot(`
import { GQL_TestQuery2 } from "$houdini/stores/TestQuery2";
import { GQL_TestQuery1 } from "$houdini/stores/TestQuery1";
import { houdini_load } from "./+page.js";
import { browser } from "$app/env";
import { getHoudiniContext } from "$houdini/runtime/lib/context";
import { GQL_TestQuery2 } from "$houdini/stores/TestQuery2";
import { GQL_TestQuery1 } from "$houdini/stores/TestQuery1";
const {
data: data1
} = query(GQL_TestQuery1);
$:
_houdini_inputs = $$props.data.inputs;
const {
data: data2
} = query(GQL_TestQuery2);
`)
const _houdini_context_DO_NOT_USE = getHoudiniContext();
$:
browser && GQL_TestQuery1.fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["TestQuery1"]
});
$:
browser && GQL_TestQuery2.fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["TestQuery2"]
});
const {
data: data1
} = query(GQL_TestQuery1);
const {
data: data2
} = query(GQL_TestQuery2);
`)
expect(route.script).toMatchInlineSnapshot(`
import { RequestContext } from "$houdini/runtime/lib/network";
import { GQL_TestQuery2 } from "$houdini/stores/TestQuery2";
Expand Down Expand Up @@ -289,8 +323,34 @@ describe('kit route processor', function () {
})

expect(route.component).toMatchInlineSnapshot(`
import { houdini_load } from "./+page.js";
import { browser } from "$app/env";
import { getHoudiniContext } from "$houdini/runtime/lib/context";
import { GQL_TestQuery } from "$houdini/stores/TestQuery";
$:
_houdini_inputs = $$props.data.inputs;
const _houdini_context_DO_NOT_USE = getHoudiniContext();
$:
browser && GQL_TestQuery.fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["TestQuery"]
});
$:
browser && houdini_load[0].fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["MyQuery1"]
});
$:
browser && houdini_load[1].fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["MyQuery2"]
});
const {
data
} = query(GQL_TestQuery);
Expand Down Expand Up @@ -358,9 +418,24 @@ describe('kit route processor', function () {
`,
})

expect(route.component).toMatchInlineSnapshot(
`import { GQL_TestQuery } from "$houdini/stores/TestQuery";`
)
expect(route.component).toMatchInlineSnapshot(`
import { houdini_load } from "./+page.js";
import { browser } from "$app/env";
import { getHoudiniContext } from "$houdini/runtime/lib/context";
$:
_houdini_inputs = $$props.data.inputs;
const _houdini_context_DO_NOT_USE = getHoudiniContext();
$:
browser && GQL_TestQuery.fetch({
context: _houdini_context_DO_NOT_USE,
variables: _houdini_inputs["TestQuery"]
});
import { GQL_TestQuery } from "$houdini/stores/TestQuery";
`)
expect(route.script).toMatchInlineSnapshot(`
import { RequestContext } from "$houdini/runtime/lib/network";
import { GQL_TestQuery } from "$houdini/stores/TestQuery";
Expand Down
128 changes: 113 additions & 15 deletions src/vite/transforms/kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ export default async function svelteKitProcessor(config: Config, page: Transform
find_page_info(page),
])

// merge page and inline queries into a single list
const queries = inline_queries.concat(page_query ?? [])
for (const [i, target] of (page_info.load ?? []).entries()) {
queries.push({
name: target.name,
variables: target.variables,
store_id: AST.memberExpression(AST.identifier('houdini_load'), AST.literal(i)),
})
}

// if we are processing a route component (+page.svelte)
if (page.config.isRoute(page.filepath)) {
Expand All @@ -56,24 +62,124 @@ export default async function svelteKitProcessor(config: Config, page: Transform

async function process_component({
page,
queries: external_queries,
queries,
page_info,
}: {
page: TransformPage
queries: LoadTarget[]
page_info: PageScriptInfo
}) {
// find the first non import
let insert_index = page.script.body.findIndex(
(statement) => statement.type !== 'ImportDeclaration'
)
if (insert_index === -1) {
insert_index = 0
}

// add an import for the context utility
ensure_imports({
config: page.config,
script: page.script,
import: ['getHoudiniContext'],
sourceModule: '$houdini/runtime/lib/context',
})
insert_index++

// import the browser chec
ensure_imports({
config: page.config,
script: page.script,
import: ['browser'],
sourceModule: '$app/env',
})
insert_index++

// if the page contains a defined load, import it
if (page_info.load) {
ensure_imports({
config: page.config,
script: page.script,
import: ['houdini_load'],
sourceModule: './+page' + (page.config.typescript ? '.ts' : '.js'),
})
insert_index++
}

// the first thing we need to do is to define a local variable that
// will hold onto the values we get from props
const input_obj = AST.identifier('_houdini_inputs')
page.script.body.splice(
insert_index++,
0,
// @ts-ignore
AST.labeledStatement(
AST.identifier('$'),
AST.expressionStatement(
AST.assignmentExpression(
'=',
input_obj,
AST.memberExpression(
AST.memberExpression(AST.identifier('$$props'), AST.identifier('data')),
AST.identifier('inputs')
)
)
)
)
)

// create a context handler we can pass to the fetches
const houdini_context = AST.identifier('_houdini_context_DO_NOT_USE')
page.script.body.splice(
insert_index++,
0,
// @ts-ignore
AST.variableDeclaration('const', [
AST.variableDeclarator(
houdini_context,
AST.callExpression(AST.identifier('getHoudiniContext'), [])
),
])
)

// we need to add the client side fetches for every query that we ran into
page.script.body.splice(
insert_index++,
0,
// @ts-ignore
...queries.map((query) =>
AST.labeledStatement(
AST.identifier('$'),
AST.expressionStatement(
AST.logicalExpression(
'&&',
AST.identifier('browser'),
AST.callExpression(
AST.memberExpression(query.store_id, AST.identifier('fetch')),
[
AST.objectExpression([
AST.objectProperty(AST.identifier('context'), houdini_context),
AST.objectProperty(
AST.identifier('variables'),
AST.memberExpression(input_obj, AST.literal(query.name))
),
]),
]
)
)
)
)
)
)
}

function add_load({
page,
queries: external_queries,
queries,
page_info,
}: {
page: TransformPage
queries: LoadTarget[]
page: TransformPage
page_info: PageScriptInfo
}) {
// if there is already a load function defined, don't do anything
Expand All @@ -83,7 +189,7 @@ function add_load({

// let's verify that we have all of the variable functions we need before we mutate anything
let invalid = false
for (const query of (page_info.load ?? []).concat(external_queries)) {
for (const query of queries) {
const variable_fn = query_variable_fn(query.name)
// if the page doesn't export a function with the correct name, something is wrong
if (!page_info.exports.includes(variable_fn) && query.variables) {
Expand Down Expand Up @@ -118,14 +224,6 @@ could not find required variable function: ${variable_fn}. maybe its not exporte
const promise_list = AST.identifier('promises')

// build up a list of metadata for every store that we have to load
const load = external_queries
for (const [i, target] of (page_info.load ?? []).entries()) {
load.push({
name: target.name,
variables: target.variables,
store_id: AST.memberExpression(AST.identifier('houdini_load'), AST.literal(i)),
})
}

const preload_fn = AST.functionDeclaration(
AST.identifier('load'),
Expand Down Expand Up @@ -175,7 +273,7 @@ could not find required variable function: ${variable_fn}. maybe its not exporte
let insert_index = 3

// every query that we found needs to be triggered in this function
for (const query of load) {
for (const query of queries) {
preload_fn.body.body.splice(
insert_index++,
0,
Expand Down Expand Up @@ -257,7 +355,7 @@ could not find required variable function: ${variable_fn}. maybe its not exporte
])
)

let args = [request_context, page.config, load, input_obj, resolved_promises] as const
let args = [request_context, page.config, queries, input_obj, resolved_promises] as const

// add calls to user before/after load functions
if (before_load) {
Expand Down

0 comments on commit f541db4

Please sign in to comment.