Nextjs + Go Spike
https://github.com/zijizhu/next-go-ssr
Component Factory
TypeScript Interfaces
interface Document {
document_name: string
document_id: string
content: Element[]
}
type Element = Paragraph | Image
interface Paragraph {
type: 'paragraph'
align?: 'left' | 'right' | 'center'
children: Text[]
}
interface Image {
type: 'image'
url: string
}
interface Text extends TextStyle {
text: string
link?: string
}
export interface TextStyle {
bold?: boolean
italic?: boolean
underline?: boolean
}
Features
Feature type | Expected Format |
---|---|
Bold | boolean, belongs to text, eg: {
"text": "hello",
"bold": true
} |
Italic | boolean, belongs to text, eg: {
"text": "hello",
"bold": true,
"italic": true
} |
Underline | boolean, belongs to text, eg: {
"text": "hello",
"bold": true,
"italic": true,
"underline": true
} |
Text Align | union string, belongs to paragraph, eg: {
"type": "paragraph",
"align": "right",
"children": []
} |
Image/Gif (later) | string |
Video (later) | string |
Example JSON
[
{
"type": "paragraph",
"children": [
{
"text": "This is "
},
{
"text": "rich",
"bold": true
},
{
"text": " text, "
},
{
"text": "much",
"italic": true,
"underline": true,
"bold": true
},
{
"text": " better",
"italic": true,
"bold": true
},
{
"text": " than plain text!",
"bold": true
}
]
},
{
"type": "paragraph",
"align": "right",
"children": [
{
"text": "It is also "
},
{
"text": "server-side rendered",
"bold": true
},
{
"text": ", which means the server fetches the data and generates HTML for the client!"
}
]
},
{
"type": "paragraph",
"align": "center",
"children": [
{
"text": "Try it out for yourself!"
}
]
}
]
Implementation
Blog Pages renders a <Blog />
component, which takes an array of elements (of type Element
) and maps each of them to a <Block />
component:
const Blog = ({ elements }: { elements: Element[] }) => {
return (
<BlogContainer>
{elements.map((element, idx) => (
<Block key={idx} element={element} />
))}
</BlogContainer>
)
}
The <Block />
component takes a single element (of type Element
), renders either an image, an embeded video, or a paragraph.
It uses TypeScript type narrowing to determine what kind of element it receives. If the element is a Paragraph
, then the element should have a children
field, which is an array of Text
. It will then map the texts to <Text />
component:
const Block = ({ element }: { element: Element }) => {
if (element.type === 'image') {
return <ImagePlaceholder>{element.url}</ImagePlaceholder>
}
return (
<ParagraphBlock align={element.align}>
{element.children.map(({ text, link, ...textStyle }, idx) => (
<Text key={idx} {...textStyle}>
{text}
</Text>
))}
</ParagraphBlock>
)
}
Notes:
Slate.js has its in house TypeScript Definitions. They are not used since they are overcomplicated for just parsing.
Editor (and backend) team should choose the exact data structure since it’s relatively easy to parse the data as opposed to extract the data from editor.
Next.js & Server-side Rendering
SSR
Faster load speed
Better SEO
Next.js
styled-components needs some extra setup
Next.js maps page folder to routes: https://nextjs.org/docs/basic-features/pages
export a
getServerSideProps
function within a page file to enable SSR for that page: https://nextjs.org/docs/basic-features/data-fetching/overview
Related content
UNSW CSESoc