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

Feat: Gql fragments support for prerender. Clean up crwa templates #9594

Merged
merged 60 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
65a4fe8
WIP to load possible types
dthyresson Nov 20, 2023
f9468ac
Vite plugin to setup possible types for apollo client cache config
dthyresson Nov 28, 2023
bfb2945
Build codegen files if needed for fragment/doc support
dthyresson Nov 28, 2023
5ca49c5
client present silences output
dthyresson Nov 28, 2023
60794b2
Doc typos
dthyresson Nov 30, 2023
2e7d678
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Nov 30, 2023
fb9aea7
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 1, 2023
64e499e
Fix failing test to ensure graphql config is set
dthyresson Dec 1, 2023
a0ece41
CRWA JS template needed to be rebuilt
dthyresson Dec 1, 2023
ad5acab
Updated test project
dthyresson Dec 1, 2023
8f7d0c3
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Dec 9, 2023
64be78c
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 11, 2023
f431b00
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 12, 2023
a007bcd
Removes possible types from crwa and test fixture
dthyresson Dec 12, 2023
7bc0ec5
Fixes CRWA template tests to remove possible types
dthyresson Dec 12, 2023
b944d55
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Dec 13, 2023
38636e9
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Dec 13, 2023
562e1e9
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 19, 2023
bc1bbe8
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Dec 20, 2023
8e2e674
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Dec 20, 2023
6337e97
Use a virtual module for possibleTypes
Tobbe Dec 20, 2023
a48a6b2
Update vite plugin doc comment
Tobbe Dec 20, 2023
0faee42
Respect toml config for trustedDocuments on/off
Tobbe Dec 20, 2023
67c92c4
Stop using rwConfig for perf reasons
Tobbe Dec 20, 2023
7773afe
Webpack support
Tobbe Dec 20, 2023
ca64fae
Use getConfigPath to benefit from caching
Tobbe Dec 20, 2023
2dc90a5
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 27, 2023
7bd553c
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Dec 27, 2023
a09f5d9
Copy the possible types to dist to mimic virtual module when prerende…
dthyresson Dec 27, 2023
af359da
typo in graphql fragments
dthyresson Dec 27, 2023
9615b5c
Updates test fixtures
dthyresson Dec 28, 2023
00404f0
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 3, 2024
f80abdd
Merge branch 'main' into dt-possible-types-dynamic
dthyresson Jan 3, 2024
323f716
the virtual possible types needs to be cjs when not using fragments a…
dthyresson Jan 3, 2024
1b2f980
rebuild test project fixture
Tobbe Jan 3, 2024
5b4bbe3
Remove comment
Tobbe Jan 3, 2024
a64e681
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 3, 2024
a6063ee
Don't create new files in node_modules
Tobbe Jan 4, 2024
e2e27e4
prerender: Monkeypatch require to handle virtual-possibleTypes
Tobbe Jan 4, 2024
42b0296
storybook: possibleTypes
Tobbe Jan 4, 2024
0a4f0f1
add missing file
Tobbe Jan 4, 2024
25a9cd1
add vite plugin to RSC config
Tobbe Jan 4, 2024
f7180b4
jest
Tobbe Jan 4, 2024
f849b4b
Generate fragments test project
Tobbe Jan 5, 2024
4eb85f2
Update test-project fixture
Tobbe Jan 5, 2024
4eb3aed
Fragments smoke-test
Tobbe Jan 5, 2024
19220a9
Windows... (corepack issue)
Tobbe Jan 5, 2024
e363b31
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 5, 2024
8cf1c9a
Run with test-project tasks with node
Tobbe Jan 5, 2024
6746a00
TS add-gql-fragments
Tobbe Jan 6, 2024
b3a56f9
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 6, 2024
f4f6434
Script to rebuild fragments test project fixture
Tobbe Jan 6, 2024
7a547d8
Generate new fragment-test-project
Tobbe Jan 6, 2024
1671888
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 6, 2024
0ee6b5f
Enable fragments for prerendering
Tobbe Jan 6, 2024
d0d51c6
web tests: map virtual-possibleTypes
Tobbe Jan 6, 2024
c1330ef
Try vite ssr noExternal for virtual-possibleTypes
Tobbe Jan 6, 2024
aa5c03f
Add virtual-possibleType support for SSR
Tobbe Jan 7, 2024
de8923f
Merge branch 'main' into dt-possible-types-dynamic
Tobbe Jan 7, 2024
fb35854
Remove virtual possibleTypes module
Tobbe Jan 8, 2024
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
4 changes: 2 additions & 2 deletions __fixtures__/test-project/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FatalErrorBoundary, RedwoodProvider } from '@redwoodjs/web'
import { RedwoodApolloProvider } from '@redwoodjs/web/apollo'

import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'

Expand All @@ -12,8 +13,7 @@ const App = () => (
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider titleTemplate="%PageTitle | %AppTitle">
<AuthProvider>
<RedwoodApolloProvider
useAuth={useAuth}>
<RedwoodApolloProvider useAuth={useAuth}>
<Routes />
</RedwoodApolloProvider>
</AuthProvider>
Expand Down
11 changes: 11 additions & 0 deletions __fixtures__/test-project/web/src/graphql/possibleTypes.ts
Tobbe marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface PossibleTypesResultData {
possibleTypes: {
[key: string]: string[]
}
}

const result: PossibleTypesResultData = {
possibleTypes: {},
}

export default result
4 changes: 2 additions & 2 deletions docs/docs/graphql/fragments.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ import possibleTypes from 'src/graphql/possibleTypes'

To generate the `src/graphql/possibleTypes`, configure the `redwood.toml`:

```toml title=redwood.roml
```toml title=redwood.toml
[graphql]
fragments=true
fragments = true
```
19 changes: 19 additions & 0 deletions packages/cli/src/commands/buildHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import terminalLink from 'terminal-link'

import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { buildApi } from '@redwoodjs/internal/dist/build/api'
import { generate } from '@redwoodjs/internal/dist/generate/generate'
import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema'
import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection'
import { timedTelemetry } from '@redwoodjs/telemetry'
Expand All @@ -32,7 +33,12 @@ export const handler = async ({
prisma,
prerender,
})

const rwjsPaths = getPaths()
const rwjsConfig = getConfig()
const useGraphQL = rwjsConfig.graphql
const useFragments = useGraphQL && useGraphQL.fragments
const useTrustedDocuments = useGraphQL && useGraphQL.trustedDocuments

if (performance) {
console.log('Measuring Web Build Performance...')
Expand Down Expand Up @@ -75,6 +81,19 @@ export const handler = async ({
})
},
},
// If using GraphQL Fragments or Trusted Documents, then we need use coden to generate the types
// needed for possible types and the trusted document store hashes
(useFragments || useTrustedDocuments) && {
title: `Generating types needed for ${[
useFragments && 'GraphQL Fragments',
useTrustedDocuments && 'Trusted Documents',
]
.filter(Boolean)
.join(' and ')} support...`,
task: async () => {
await generate()
},
},
side.includes('api') && {
title: 'Verifying graphql schema...',
task: loadAndValidateSdls,
Expand Down
9 changes: 1 addition & 8 deletions packages/create-redwood-app/templates/js/web/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FatalErrorBoundary, RedwoodProvider } from '@redwoodjs/web'
import { RedwoodApolloProvider } from '@redwoodjs/web/apollo'

import possibleTypes from 'src/graphql/possibleTypes'
import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'

Expand All @@ -10,13 +9,7 @@ import './index.css'
const App = () => (
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider titleTemplate="%PageTitle | %AppTitle">
<RedwoodApolloProvider
graphQLClientConfig={{
cacheConfig: {
...possibleTypes,
},
}}
>
<RedwoodApolloProvider>
<Routes />
</RedwoodApolloProvider>
</RedwoodProvider>
Expand Down
9 changes: 1 addition & 8 deletions packages/create-redwood-app/templates/ts/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FatalErrorBoundary, RedwoodProvider } from '@redwoodjs/web'
import { RedwoodApolloProvider } from '@redwoodjs/web/apollo'

import possibleTypes from 'src/graphql/possibleTypes'
import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'

Expand All @@ -10,13 +9,7 @@ import './index.css'
const App = () => (
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider titleTemplate="%PageTitle | %AppTitle">
<RedwoodApolloProvider
graphQLClientConfig={{
cacheConfig: {
...possibleTypes,
},
}}
>
<RedwoodApolloProvider>
<Routes />
</RedwoodApolloProvider>
</RedwoodProvider>
Expand Down
1 change: 1 addition & 0 deletions packages/internal/src/generate/clientPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const generateClientPreset = async () => {
const config: CodegenConfig = {
schema: getPaths().generated.schema,
documents: documentsGlob,
silent: true, // Plays nicely with cli task output
generates: {
// should be graphql.d.ts
[`${getPaths().web.base}/types/types.d.ts`]: {
Expand Down
4 changes: 3 additions & 1 deletion packages/vite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { normalizePath } from 'vite'
import { getWebSideDefaultBabelConfig } from '@redwoodjs/babel-config'
import { getConfig, getPaths } from '@redwoodjs/project-config'

import configureGraphQLFragments from './plugins/vite-plugin-configure-graphql-fragments'
import handleJsAsJsx from './plugins/vite-plugin-jsx-loader'
import removeFromBundle from './plugins/vite-plugin-remove-from-bundle'
import swapApolloProvider from './plugins/vite-plugin-swap-apollo-provider'
Expand Down Expand Up @@ -268,7 +269,8 @@ export default function redwoodPluginVite(): PluginOption[] {
},
// We can remove when streaming is stable
rwConfig.experimental.streamingSsr.enabled && swapApolloProvider(),
// -----------------
// When using GraphQL Fragments, handle possible types for Apollo Client Cache
configureGraphQLFragments(),
handleJsAsJsx(),
// Remove the splash-page from the bundle.
removeFromBundle([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import fs from 'fs'
import path from 'path'

import { transformWithEsbuild } from 'vite'
import type { PluginOption } from 'vite'

import { getConfig, getPaths } from '@redwoodjs/project-config'

const DEFAULT_POSSIBLE_TYPES_FILE_CONTENTS = `export interface PossibleTypesResultData {
possibleTypes: {
[key: string]: string[]
}
}

const result: PossibleTypesResultData = {
possibleTypes: {},
}

export default result
`

/**
*
* This is a vite plugin to support GraphQL Fragments by either
* creating a default possible types file to be used when configuring Apollo Client Cache config
* or, allowing Apollo Client to use the possibleTypes file that is generated by the GraphQL Code Generator
*
* This plugin handles both build and dev (aka serve) modes
*
* When building, a transform hook is used to replace the import of the possibleTypes
* file with the actual contents of the file
*
* See:
*
* packages/web/src/apollo/index.ts -> import possibleTypes from './possibleTypes'
* packages/web/src/apollo/possibleTypes.ts
*
*/
export default function configureGraphQLFragments(): PluginOption {
const rwConfig = getConfig()

const possibleTypesFilePath = path.join(
getPaths().web.graphql,
'possibleTypes.ts'
)

const useFragments = rwConfig.graphql.fragments
const existsPossibleTypesFile = fs.existsSync(possibleTypesFilePath)

return {
name: 'configure-graphql-fragments',
configureServer() {
return () => {
// if a RedwoodJS project isn't configured to use fragments, then
// create the default possibleTypes file (but, don't overwrite it)
if (!useFragments && !existsPossibleTypesFile) {
const dirname = path.dirname(possibleTypesFilePath)
if (!fs.existsSync(dirname)) {
fs.mkdirSync(dirname, { recursive: true })
}
fs.writeFileSync(
possibleTypesFilePath,
DEFAULT_POSSIBLE_TYPES_FILE_CONTENTS
)
}
}
},
async transform(_code: string, id: string) {
if (/@redwoodjs\/web\/dist\/apollo\/possibleTypes/.test(id)) {
if (existsPossibleTypesFile) {
const possibleTypeFile = fs.readFileSync(
possibleTypesFilePath,
'utf8'
)

const result = await transformWithEsbuild(
possibleTypeFile,
possibleTypesFilePath,
{
loader: 'ts',
}
)

return {
code: result.code,
}
}
}

return null
},
}
}
3 changes: 3 additions & 0 deletions packages/web/src/apollo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries'
import { getMainDefinition } from '@apollo/client/utilities'
import { fetch as crossFetch } from '@whatwg-node/fetch'
import { print } from 'graphql/language/printer'

// Note: Importing directly from `apollo/client` doesn't work properly in Storybook.
const {
ApolloProvider,
Expand Down Expand Up @@ -40,6 +41,7 @@ import {
registerFragment,
registerFragments,
} from './fragmentRegistry'
import possibleTypes from './possibleTypes'
import { SSELink } from './sseLink'
import { useCache } from './useCache'

Expand Down Expand Up @@ -364,6 +366,7 @@ export const RedwoodApolloProvider: React.FunctionComponent<{

const cache = new InMemoryCache({
fragments: fragmentRegistry,
possibleTypes: cacheConfig?.possibleTypes ?? possibleTypes.possibleTypes,
...cacheConfig,
}).restore(globalThis?.__REDWOOD__APOLLO_STATE ?? {})

Expand Down
33 changes: 33 additions & 0 deletions packages/web/src/apollo/possibleTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Imported by Apollo Client to configure the cache with any possible types needed for
* union and interface types.
*
* If there is a possibleTypes file generated by GraphQL Code Generator in the project, then use that
*
* If not, then use the default possibleTypes file that is created by the configure-graphql-fragments vite plugin
*
* This ensures that the required possibleTypes are always available to Apollo Client and the try/catch won't fail
*
*/
interface PossibleTypesResultData {
possibleTypes: {
[key: string]: string[]
}
}

let file: PossibleTypesResultData = { possibleTypes: {} }

// TODO: Since the vite plugin ensures that the possibleTypes file exists, we can remove this check?
if (process.env.NODE_ENV === 'development') {
try {
file = require('web/src/graphql/possibleTypes').default
} catch (e) {
// eat the error
}
}

const result: PossibleTypesResultData = {
possibleTypes: file.possibleTypes,
}

export default result
Loading