@graphcommerce/docs 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +4 -0
- package/CHANGELOG.md +160 -0
- package/components/Layout/LayoutFull.tsx +85 -0
- package/components/Layout/Logo.tsx +19 -0
- package/components/Layout/graphcommerce.svg +34 -0
- package/components/Search.tsx +37 -0
- package/components/SearchForm.tsx +110 -0
- package/components/SidebarMenu/index.tsx +101 -0
- package/components/prism.css +274 -0
- package/components/rehype-prism-plus.css +49 -0
- package/components/theme.ts +410 -0
- package/content/framework/deployment.md +56 -0
- package/content/framework/environment-variables.md +61 -0
- package/content/framework/favicon.md +38 -0
- package/content/framework/graphcms.md +66 -0
- package/content/framework/icons.md +255 -0
- package/content/framework/readme.md +79 -0
- package/content/framework/seo.md +64 -0
- package/content/framework/static-file-serving.md +44 -0
- package/content/framework/static-generation.md +221 -0
- package/content/framework/theming.md +258 -0
- package/content/framework/translations.md +112 -0
- package/content/framework/troubleshooting.md +67 -0
- package/content/framework/typography.md +143 -0
- package/content/getting-started/create.md +152 -0
- package/content/getting-started/graphcms-component.md +240 -0
- package/content/getting-started/header.md +224 -0
- package/content/getting-started/pages.md +290 -0
- package/content/getting-started/readme.md +294 -0
- package/content/getting-started/start-building.md +160 -0
- package/content/getting-started/vscode.md +48 -0
- package/content/readme.md +124 -0
- package/content/roadmap.md +31 -0
- package/lib/DocumentIndexer.ts +59 -0
- package/lib/files.ts +168 -0
- package/lib/instantSearch.ts +26 -0
- package/lib/typesense/IndexerHandler.ts +47 -0
- package/lib/typesense/Leaves.ts +37 -0
- package/lib/typesense/SearchIndexer.ts +64 -0
- package/lib/typesense/batchInterable.ts +13 -0
- package/lib/typesense/createInstantSearchProps.ts +36 -0
- package/lib/typesense/typesenseClientConf.ts +23 -0
- package/lib/typesense/typesenseIndexerHandler.ts +23 -0
- package/next-env.d.ts +5 -0
- package/next.config.js +21 -0
- package/package.json +56 -0
- package/pages/[[...url]].tsx +391 -0
- package/pages/_app.tsx +26 -0
- package/pages/_document.tsx +22 -0
- package/pages/api/reindex.ts +4 -0
- package/pages/menu/[[...url]].tsx +69 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +12 -0
- package/public/link.svg +4 -0
- package/public/manifest/favicon-192.png +0 -0
- package/public/manifest/favicon-512.png +0 -0
- package/public/manifest.webmanifest +20 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
menu: 3. Build a custom header
|
|
3
|
+
metaTitle: Build a custom header
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Developer preview**
|
|
7
|
+
> This is a developer preview of GraphCommerce. The documentation will be
|
|
8
|
+
> updated as GraphCommerce introduces
|
|
9
|
+
> [new features and refines existing functionality](https://github.com/ho-nl/m2-pwa/releases).
|
|
10
|
+
|
|
11
|
+
# Build a custom header in GraphCommerce
|
|
12
|
+
|
|
13
|
+
Previously, you created a GraphCommerce app and started building your custom
|
|
14
|
+
storefront with GraphCommerce. You're now ready to build a custom header for
|
|
15
|
+
your app.
|
|
16
|
+
|
|
17
|
+
In this tutorial, you'll accomplish a series of tasks to add some specific
|
|
18
|
+
functionality to your app. Your final app will be simple, but you'll learn where
|
|
19
|
+
to find resources to build more complex features on your own.
|
|
20
|
+
|
|
21
|
+
### After you've finished this tutorial, you'll have accomplished the following:
|
|
22
|
+
|
|
23
|
+
- Edited the layout component to remove components
|
|
24
|
+
- Add a simplified search Icon button
|
|
25
|
+
- Make a local copy of the MenuFab component and update its imports
|
|
26
|
+
- Change the Menu component's styling to a fullscreen overlay
|
|
27
|
+
|
|
28
|
+
### Requirements
|
|
29
|
+
|
|
30
|
+
You've familiarized yourself with
|
|
31
|
+
[React ↗](https://reactjs.org/docs/getting-started.html),
|
|
32
|
+
[Next.js ↗](https://nextjs.org/docs/getting-started), and
|
|
33
|
+
[Mui ↗](https://mui.com/getting-started/installation/). GraphCommerce is a
|
|
34
|
+
frontend React framework that uses Next.js for server-side rendering.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<figure>
|
|
39
|
+
|
|
40
|
+
https://user-images.githubusercontent.com/1251986/154978614-8d2eaee1-d64b-4bae-a7d7-cfee2e9175d3.mp4
|
|
41
|
+
|
|
42
|
+
<video width="100%" controls autoPlay loop muted>
|
|
43
|
+
<source src="https://user-images.githubusercontent.com/1251986/154978614-8d2eaee1-d64b-4bae-a7d7-cfee2e9175d3.mp4" type="video/mp4"/>
|
|
44
|
+
</video>
|
|
45
|
+
|
|
46
|
+
<figcaption>Before customization of the header</figcaption>
|
|
47
|
+
</figure>
|
|
48
|
+
|
|
49
|
+
<figure>
|
|
50
|
+
|
|
51
|
+
https://user-images.githubusercontent.com/1251986/154979091-89c72d68-c62f-451c-af49-6f36f3fa6609.mp4
|
|
52
|
+
|
|
53
|
+
<video width="100%" controls autoPlay loop muted>
|
|
54
|
+
<source src="https://user-images.githubusercontent.com/1251986/154979091-89c72d68-c62f-451c-af49-6f36f3fa6609.mp4" type="video/mp4"/>
|
|
55
|
+
</video>
|
|
56
|
+
|
|
57
|
+
<figcaption>After customization of the header</figcaption>
|
|
58
|
+
</figure>
|
|
59
|
+
|
|
60
|
+
### Move and justify the logo
|
|
61
|
+
|
|
62
|
+
- In /components/Layout/LayoutFull.tsx, move `<Logo />` after
|
|
63
|
+
`<DesktopNavBar>...</DesktopNavBar>`
|
|
64
|
+
- Wrap the `<Logo />` component in a `<Box>` component:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<Box
|
|
68
|
+
sx={{
|
|
69
|
+
display: 'flex',
|
|
70
|
+
justifyContent: 'center',
|
|
71
|
+
flexGrow: 1,
|
|
72
|
+
pointerEvents: 'none',
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<Logo />
|
|
76
|
+
</Box>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Add the import of 'Box' to the list of the `'@mui/material'` imports at the
|
|
80
|
+
top of the file
|
|
81
|
+
- Save the file to see your changes updated in real-time
|
|
82
|
+
|
|
83
|
+
<figure>
|
|
84
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/v0jqud" />
|
|
85
|
+
<figcaption>Reorder components</figcaption>
|
|
86
|
+
</figure>
|
|
87
|
+
|
|
88
|
+
### Remove DesktopNavBar
|
|
89
|
+
|
|
90
|
+
- In /components/Layout/LayoutFull.tsx, remove the
|
|
91
|
+
`<DesktopNavBar>...</DesktopNavBar>` component.
|
|
92
|
+
|
|
93
|
+
<figure>
|
|
94
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/S1BIyc" />
|
|
95
|
+
<figcaption>Remove navigation</figcaption>
|
|
96
|
+
</figure>
|
|
97
|
+
|
|
98
|
+
### Replace Search input with Search Fab
|
|
99
|
+
|
|
100
|
+
- In /components/Layout/LayoutFull.tsx, replace
|
|
101
|
+
`<SearchButton onClick={onSearchStart} label=' ' />` with:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<PageLink href='/search' passHref>
|
|
105
|
+
<Fab aria-label={t`Search`} size='large' color='inherit'>
|
|
106
|
+
<IconSvg src={iconSearch} size='large' />
|
|
107
|
+
</Fab>
|
|
108
|
+
</PageLink>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- Add `iconSearch` to the existing imports from `'@graphcommerce/next-ui'` at
|
|
112
|
+
the top of the file
|
|
113
|
+
|
|
114
|
+
### Remove Customer Service Fab
|
|
115
|
+
|
|
116
|
+
- In /components/Layout/LayoutFull.tsx, remove the Customer Service floating
|
|
117
|
+
action button by removing it completely:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<PageLink href='/service' passHref>
|
|
121
|
+
<Fab aria-label={t`Account`} size='large' color='inherit'>
|
|
122
|
+
<IconSvg src={iconCustomerService} size='large' />
|
|
123
|
+
</Fab>
|
|
124
|
+
</PageLink>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
<figure>
|
|
128
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/7eadNI" />
|
|
129
|
+
<figcaption>Replace search input with Search Fab, remove Customer Service Fab</figcaption>
|
|
130
|
+
</figure>
|
|
131
|
+
|
|
132
|
+
### Make a local copy of the MenuFab component
|
|
133
|
+
|
|
134
|
+
- In /components/Layout/LayoutFull.tsx, remove `MenuFab` from the
|
|
135
|
+
`'@graphcommerce/next-ui'` import
|
|
136
|
+
- Add `import { MenuFab } from './MenuFab'` to the list of imports at the top of
|
|
137
|
+
the file
|
|
138
|
+
|
|
139
|
+
- Make a copy of /node_modules/@graphcommerce/next-ui/LayoutParts/MenuFab.tsx
|
|
140
|
+
and move it to the directory /components/Layout/MenuFab.tsx
|
|
141
|
+
- In /components/Layout/MenuFab.tsx, change
|
|
142
|
+
`const MotionDiv = styled(m.div)({})` to:
|
|
143
|
+
```ts
|
|
144
|
+
const MotionDiv = styled('div')({})
|
|
145
|
+
```
|
|
146
|
+
- Remove the `style={{...}}` prop from both the `<MotionDiv>` components to
|
|
147
|
+
remove the Fab scroll animation
|
|
148
|
+
- Remove `const { opacity, scale, shadowOpacity } = useFabAnimation()`
|
|
149
|
+
|
|
150
|
+
- Update all imports:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import {
|
|
154
|
+
extendableComponent,
|
|
155
|
+
responsiveVal,
|
|
156
|
+
iconClose,
|
|
157
|
+
iconMenu,
|
|
158
|
+
IconSvg,
|
|
159
|
+
} from '@graphcommerce/next-ui'
|
|
160
|
+
import { styled, Box, Fab, Menu, ListItem, Divider, alpha } from '@mui/material'
|
|
161
|
+
import { useRouter } from 'next/router'
|
|
162
|
+
import React, { useEffect } from 'react'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
<figure>
|
|
166
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/O1iBQ4" />
|
|
167
|
+
<figcaption>Local copy of the MenuFab component with Fab scroll animation removed</figcaption>
|
|
168
|
+
</figure>
|
|
169
|
+
|
|
170
|
+
### Change the Menu component's styling
|
|
171
|
+
|
|
172
|
+
- In /components/Layout/MenuFab.tsx, change the `<Menu>` component's PaperProps
|
|
173
|
+
prop to:
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
PaperProps={{
|
|
177
|
+
sx: (theme) => ({
|
|
178
|
+
width: '100vw',
|
|
179
|
+
height: '100vh',
|
|
180
|
+
maxWidth: '100vw',
|
|
181
|
+
maxHeight: '100vh',
|
|
182
|
+
backgroundColor: alpha(theme.palette.text.primary, 0.95),
|
|
183
|
+
color: theme.palette.background.paper,
|
|
184
|
+
display: 'flex',
|
|
185
|
+
justifyContent: 'center',
|
|
186
|
+
alignItems: 'center',
|
|
187
|
+
borderRadius: 0,
|
|
188
|
+
'& svg': {
|
|
189
|
+
color: theme.palette.background.paper,
|
|
190
|
+
},
|
|
191
|
+
}),
|
|
192
|
+
}}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- Remove the `<Menu>` component's prop 'disableScrollLock`
|
|
196
|
+
- Add a two props to the `<Menu>` component:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
marginThreshold={0}
|
|
200
|
+
TransitionComponent={Fade}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
- Add the import of 'Fade' to the list of the `'@mui/material'` imports at the
|
|
204
|
+
top of the file
|
|
205
|
+
- Remove the search component by removing:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
search ? (
|
|
209
|
+
<ListItem key='search' dense sx={{ mb: '6px', borderColor: 'red' }}>
|
|
210
|
+
{search}
|
|
211
|
+
</ListItem>
|
|
212
|
+
) : null,
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
<figure>
|
|
216
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/RyXlBV" />
|
|
217
|
+
<figcaption>Menu component with custom styling</figcaption>
|
|
218
|
+
</figure>
|
|
219
|
+
|
|
220
|
+
## Next steps
|
|
221
|
+
|
|
222
|
+
- Learn how to [build pages](../getting-started/pages.md) in GraphCommerce
|
|
223
|
+
- Learn more about creating
|
|
224
|
+
[styled components with the styled() utility](../framework/theming.md)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
---
|
|
2
|
+
menu: 4. Build pages
|
|
3
|
+
metaTitle: Build pages
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Developer preview**
|
|
7
|
+
> This is a developer preview of GraphCommerce. The documentation will be
|
|
8
|
+
> updated as GraphCommerce introduces
|
|
9
|
+
> [new features and refines existing functionality](https://github.com/ho-nl/m2-pwa/releases).
|
|
10
|
+
|
|
11
|
+
# Build pages in GraphCommerce
|
|
12
|
+
|
|
13
|
+
Previously, you created a custom storefront and started customizing your
|
|
14
|
+
storefront in GraphCommerce. You're now ready to build pages in your
|
|
15
|
+
GraphCommerce app.
|
|
16
|
+
|
|
17
|
+
In this tutorial, you'll accomplish a series of tasks to add some specific
|
|
18
|
+
functionality to your custom storefront. The result will be simple, but you'll
|
|
19
|
+
learn where to find resources to build more complex features on your own.
|
|
20
|
+
|
|
21
|
+
## What you'll learn
|
|
22
|
+
|
|
23
|
+
- Create a new route
|
|
24
|
+
- Add the page GraphQL queries required to render the layout (header, footer)
|
|
25
|
+
- Use getStaticProps to fetch GraphCMS data
|
|
26
|
+
- Use getStaticPaths to provide a list of all URLs to pre-render
|
|
27
|
+
|
|
28
|
+
### Requirements
|
|
29
|
+
|
|
30
|
+
You've familiarized yourself with
|
|
31
|
+
[React ↗](https://reactjs.org/docs/getting-started.html),
|
|
32
|
+
[Next.js ↗](https://nextjs.org/docs/getting-started), and
|
|
33
|
+
[Mui ↗](https://mui.com/getting-started/installation/). GraphCommerce is a
|
|
34
|
+
frontend React framework that uses Next.js for server-side rendering.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
### Create the route
|
|
39
|
+
|
|
40
|
+
- Create a new file, /about/about-us.tsx:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
export default function AboutUs() {
|
|
44
|
+
return <>About Us</>
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- Visit the page: http://localhost:3000/about/about-us
|
|
49
|
+
|
|
50
|
+
### Add GraphQL query
|
|
51
|
+
|
|
52
|
+
- In /about/about-us.tsx, replace the previous code with the following:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { PageOptions } from '@graphcommerce/framer-next-pages'
|
|
56
|
+
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
|
57
|
+
import { GetStaticProps } from '@graphcommerce/next-ui'
|
|
58
|
+
import { Container } from '@mui/material'
|
|
59
|
+
import { GetStaticPaths } from 'next'
|
|
60
|
+
import { LayoutFull, LayoutFullProps } from '../../components'
|
|
61
|
+
import {
|
|
62
|
+
DefaultPageDocument,
|
|
63
|
+
DefaultPageQuery,
|
|
64
|
+
} from '../../graphql/DefaultPage.gql'
|
|
65
|
+
import { PagesStaticPathsDocument } from '../../graphql/PagesStaticPaths.gql'
|
|
66
|
+
import {
|
|
67
|
+
graphqlSsrClient,
|
|
68
|
+
graphqlSharedClient,
|
|
69
|
+
} from '../../lib/graphql/graphqlSsrClient'
|
|
70
|
+
|
|
71
|
+
type Props = DefaultPageQuery
|
|
72
|
+
type RouteProps = { url: string }
|
|
73
|
+
type GetPageStaticPaths = GetStaticPaths<RouteProps>
|
|
74
|
+
type GetPageStaticProps = GetStaticProps<LayoutFullProps, Props, RouteProps>
|
|
75
|
+
|
|
76
|
+
function AboutUs() {
|
|
77
|
+
return <Container>About Us</Container>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
AboutUs.pageOptions = {
|
|
81
|
+
Layout: LayoutFull,
|
|
82
|
+
} as PageOptions
|
|
83
|
+
|
|
84
|
+
export default AboutUs
|
|
85
|
+
|
|
86
|
+
export const getStaticProps: GetPageStaticProps = async (context) => {
|
|
87
|
+
const { locale } = context
|
|
88
|
+
const client = graphqlSharedClient(locale)
|
|
89
|
+
const staticClient = graphqlSsrClient(locale)
|
|
90
|
+
|
|
91
|
+
const conf = client.query({ query: StoreConfigDocument })
|
|
92
|
+
const page = staticClient.query({
|
|
93
|
+
query: DefaultPageDocument,
|
|
94
|
+
variables: {
|
|
95
|
+
url: '',
|
|
96
|
+
rootCategory: (await conf).data.storeConfig?.root_category_uid ?? '',
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
// if (!(await page).data.pages?.[0]) return { notFound: true }
|
|
100
|
+
return {
|
|
101
|
+
props: {
|
|
102
|
+
...(await page).data,
|
|
103
|
+
apolloState: await conf.then(() => client.cache.extract()),
|
|
104
|
+
},
|
|
105
|
+
revalidate: 60 * 20,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- Visiting http://localhost:3000/about/about-us will output:
|
|
111
|
+
|
|
112
|
+
<figure>
|
|
113
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/xdI9be" />
|
|
114
|
+
<figcaption>Page with page layout (header, footer)</figcaption>
|
|
115
|
+
</figure>
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
// Example from /graphql/DefaultPage.graphql (DefaultPageDocument)
|
|
119
|
+
|
|
120
|
+
query DefaultPage($url: String!, $rootCategory: String!) {
|
|
121
|
+
...MenuQueryFragment
|
|
122
|
+
...FooterQueryFragment
|
|
123
|
+
...PageContentQueryFragment
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
In the `getStaticProps` function, the query `StoreConfigDocument` is used to
|
|
128
|
+
fetch information about the Magento storeview. Then, the query
|
|
129
|
+
`DefaultPageDocument` is used to fetch the data required to render the menu,
|
|
130
|
+
footer and page content.
|
|
131
|
+
|
|
132
|
+
In this example, the URL variable is empty. As a result, the
|
|
133
|
+
`...PageContentQueryFragment` will have no result when trying to fetch a
|
|
134
|
+
GraphCMS page with URL `''`.
|
|
135
|
+
|
|
136
|
+
The function `getStaticProps` is used to fetch data, meaning content is rendered
|
|
137
|
+
on the server. Review the page's source code and search for `About Us` to
|
|
138
|
+
validate that this string (currently hard-coded) is part of the source code.
|
|
139
|
+
|
|
140
|
+
### Add GraphCMS content to the page
|
|
141
|
+
|
|
142
|
+
- Login to GraphCMS, navigate to Content and add a new Page entry with URL:
|
|
143
|
+
about/about-us
|
|
144
|
+
- In /about/about-us.tsx, make the following change to `getStaticProps`:
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
const page = staticClient.query({
|
|
148
|
+
query: DefaultPageDocument,
|
|
149
|
+
variables: {
|
|
150
|
+
url: 'about/about-us',
|
|
151
|
+
rootCategory: (await conf).data.storeConfig?.root_category_uid ?? '',
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
And replace the previous AboutUs function with the following:
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
function AboutUs({ pages }: Props) {
|
|
160
|
+
const title = pages?.[0].title ?? ''
|
|
161
|
+
|
|
162
|
+
return <Container>{title}</Container>
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
<figure>
|
|
167
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/PIOjzB" />
|
|
168
|
+
<figcaption>Fetch page content from GraphCMS</figcaption>
|
|
169
|
+
</figure>
|
|
170
|
+
|
|
171
|
+
<figure>
|
|
172
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/XKo4ut" />
|
|
173
|
+
<figcaption>GraphCMS entry</figcaption>
|
|
174
|
+
</figure>
|
|
175
|
+
|
|
176
|
+
### Add pre-rendering with getStaticPaths
|
|
177
|
+
|
|
178
|
+
- Rename `/about/about-us.tsx` to `/about/[url].tsx`
|
|
179
|
+
- In /about/[url].tsx, replace the getStaticProps function with the following:
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
export const getStaticPaths: GetPageStaticPaths = (context) => ({
|
|
183
|
+
paths: [],
|
|
184
|
+
fallback: 'blocking',
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
export const getStaticProps: GetPageStaticProps = async (context) => {
|
|
188
|
+
const { locale, params } = context
|
|
189
|
+
const client = graphqlSharedClient(locale)
|
|
190
|
+
const staticClient = graphqlSsrClient(locale)
|
|
191
|
+
|
|
192
|
+
const conf = client.query({ query: StoreConfigDocument })
|
|
193
|
+
const page = staticClient.query({
|
|
194
|
+
query: DefaultPageDocument,
|
|
195
|
+
variables: {
|
|
196
|
+
url: `about/${params?.url}`,
|
|
197
|
+
rootCategory: (await conf).data.storeConfig?.root_category_uid ?? '',
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
// if (!(await page).data.pages?.[0]) return { notFound: true }
|
|
201
|
+
return {
|
|
202
|
+
props: {
|
|
203
|
+
...(await page).data,
|
|
204
|
+
apolloState: await conf.then(() => client.cache.extract()),
|
|
205
|
+
},
|
|
206
|
+
revalidate: 60 * 20,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
By renaming the file to `/about/[url].tsx`, all routes starting with /about/
|
|
212
|
+
will be handled by the file (dynamic routing). Pages that have dynamic routes
|
|
213
|
+
need a list of paths to be statically generated.
|
|
214
|
+
|
|
215
|
+
All paths specified by a function called `getStaticPaths` will be statically
|
|
216
|
+
pre-rendered at build-time.
|
|
217
|
+
|
|
218
|
+
In the example above, the array with paths is empty. The required getStaticPaths
|
|
219
|
+
function is there, but no URLs are pre-rendered. Because getStaticPaths has the
|
|
220
|
+
option `fallback: 'blocking'`, the paths that have not been pre-rendered at
|
|
221
|
+
built-time will not result in a 404:
|
|
222
|
+
|
|
223
|
+
> From the
|
|
224
|
+
> [getStaticPaths API reference ↗](https://nextjs.org/docs/api-reference/data-fetching/get-static-paths):
|
|
225
|
+
> If fallback is 'blocking', new paths not returned by getStaticPaths will wait
|
|
226
|
+
> for the HTML to be generated, identical to SSR (hence why blocking), and then
|
|
227
|
+
> be cached for future requests so it only happens once per path.
|
|
228
|
+
|
|
229
|
+
### Pre-render all /about/ pages from GraphCMS
|
|
230
|
+
|
|
231
|
+
- In /about/[url].tsx, replace the getStaticPaths function with the following:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
export const getStaticPaths: GetPageStaticPaths = async (context) => {
|
|
235
|
+
const { locales = [] } = context
|
|
236
|
+
// if (process.env.NODE_ENV === 'development') return { paths: [], fallback: 'blocking' }
|
|
237
|
+
|
|
238
|
+
const path = async (locale: string) => {
|
|
239
|
+
const client = graphqlSharedClient(locale)
|
|
240
|
+
const { data } = await client.query({
|
|
241
|
+
query: PagesStaticPathsDocument,
|
|
242
|
+
variables: {
|
|
243
|
+
first: 10,
|
|
244
|
+
urlStartsWith: 'about',
|
|
245
|
+
},
|
|
246
|
+
})
|
|
247
|
+
return data.pages.map((page) => ({
|
|
248
|
+
params: { url: page.url.split('/').slice(1)[0] },
|
|
249
|
+
locale,
|
|
250
|
+
}))
|
|
251
|
+
}
|
|
252
|
+
const paths = (await Promise.all(locales.map(path))).flat(1)
|
|
253
|
+
// console.log(paths)
|
|
254
|
+
return { paths, fallback: 'blocking' }
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The PagesStaticPathsDocument query is used to fetch all pages from GraphCMS that
|
|
259
|
+
have a URL starting with 'about'. The locale options from the context object are
|
|
260
|
+
used to create an array:
|
|
261
|
+
|
|
262
|
+
```txt
|
|
263
|
+
// Terminal output for console.log(paths), upon refreshing the page
|
|
264
|
+
|
|
265
|
+
[
|
|
266
|
+
{ params: { url: 'about-us' }, locale: 'en-us' },
|
|
267
|
+
{ params: { url: 'about-us' }, locale: 'nl' },
|
|
268
|
+
{ params: { url: 'about-us' }, locale: 'fr-be' },
|
|
269
|
+
{ params: { url: 'about-us' }, locale: 'nl-be' },
|
|
270
|
+
{ params: { url: 'about-us' }, locale: 'en-gb' },
|
|
271
|
+
{ params: { url: 'about-us' }, locale: 'en-ca' },
|
|
272
|
+
]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Build your local environment
|
|
276
|
+
|
|
277
|
+
You can test the static build process by running it locally:
|
|
278
|
+
|
|
279
|
+
- `cd /examples/magento-graphcms/` Navigate to the project directory
|
|
280
|
+
- `yarn build` Start static build process
|
|
281
|
+
|
|
282
|
+
<figure>
|
|
283
|
+
<img src="https://cdn-std.droplr.net/files/acc_857465/AAOnX2" />
|
|
284
|
+
<figcaption>Successful pre-render of the about/about-us page</figcaption>
|
|
285
|
+
</figure>
|
|
286
|
+
|
|
287
|
+
## Next steps
|
|
288
|
+
|
|
289
|
+
- Learn how to
|
|
290
|
+
[build a custom GraphCMS component](../getting-started/graphcms-component.md)
|