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(gatsby-theme-minimal-blog): Lazy load code component #167

Merged
merged 8 commits into from
Nov 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions examples/minimal-blog/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ module.exports = {
},
`gatsby-plugin-offline`,
`gatsby-plugin-netlify`,
// `gatsby-plugin-webpack-bundle-analyser-v2`,
],
}
3 changes: 2 additions & 1 deletion examples/minimal-blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react-dom": "^16.9.0"
},
"devDependencies": {
"cross-env": "^5.2.0"
"cross-env": "^5.2.0",
"gatsby-plugin-webpack-bundle-analyser-v2": "^1.1.8"
}
}
1 change: 1 addition & 0 deletions themes/gatsby-theme-minimal-blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@emotion/core": "^10.0.22",
"@lekoarts/gatsby-theme-minimal-blog-core": "^1.0.1",
"@loadable/component": "^5.10.3",
"@mdx-js/react": "^1.1.5",
"@theme-ui/color": "^0.2.49",
"@theme-ui/components": "^0.2.49",
Expand Down
40 changes: 27 additions & 13 deletions themes/gatsby-theme-minimal-blog/src/components/code.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint react/destructuring-assignment: 0 */
import React from "react"
import Highlight, { defaultProps, Language } from "prism-react-renderer"
import theme from "prism-react-renderer/themes/nightOwl"
import { LiveProvider, LiveEditor, LiveError, LivePreview } from "react-live"
import loadable from "@loadable/component"
import useSiteMetadata from "../hooks/use-site-metadata"
import { HighlightInnerProps, Language } from "../types"

type CodeProps = {
codeString: string
Expand All @@ -13,6 +12,27 @@ type CodeProps = {
[key: string]: any
}

const LazyHighlight = loadable(async () => {
const Module = await import(`prism-react-renderer`)
const Highlight = Module.default
const { defaultProps } = Module
return (props: any) => <Highlight {...defaultProps} {...props} />
})

const LazyLiveProvider = loadable(async () => {
const Module = await import(`react-live`)
const { LiveProvider, LiveEditor, LiveError, LivePreview } = Module
return (props: any) => (
<LiveProvider {...props}>
<LiveEditor data-name="live-editor" />
<LiveError />
<LivePreview data-name="live-preview" />
</LiveProvider>
)
})

const theme = loadable(() => import(`prism-react-renderer/themes/nightOwl`))

function getParams(className = ``) {
const [lang = ``, params = ``] = className.split(`:`)

Expand Down Expand Up @@ -67,17 +87,11 @@ const Code = ({
const hasLineNumbers = !noLineNumbers && language !== `noLineNumbers` && showLineNumbers

if (props[`react-live`]) {
return (
<LiveProvider code={codeString} noInline theme={theme}>
<LiveEditor data-name="live-editor" />
<LiveError />
<LivePreview data-name="live-preview" />
</LiveProvider>
)
return <LazyLiveProvider code={codeString} noInline theme={theme} />
}
return (
<Highlight {...defaultProps} code={codeString} language={language} theme={theme}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<LazyHighlight code={codeString} language={language} theme={theme}>
{({ className, style, tokens, getLineProps, getTokenProps }: HighlightInnerProps) => (
<React.Fragment>
{title && (
<div className="code-title">
Expand Down Expand Up @@ -106,7 +120,7 @@ const Code = ({
</div>
</React.Fragment>
)}
</Highlight>
</LazyHighlight>
)
}

Expand Down
3 changes: 2 additions & 1 deletion themes/gatsby-theme-minimal-blog/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
declare module "@theme-ui/components"
declare module "@theme-ui/color"
declare module "lodash.kebabcase"
declare module "lodash.kebabcase"
declare module "@loadable/component"
149 changes: 149 additions & 0 deletions themes/gatsby-theme-minimal-blog/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import * as React from "react"

export type Language =
| "markup"
| "bash"
| "clike"
| "c"
| "cpp"
| "css"
| "javascript"
| "jsx"
| "coffeescript"
| "actionscript"
| "css-extr"
| "diff"
| "git"
| "go"
| "graphql"
| "handlebars"
| "json"
| "less"
| "makefile"
| "markdown"
| "objectivec"
| "ocaml"
| "python"
| "reason"
| "sass"
| "scss"
| "sql"
| "stylus"
| "tsx"
| "typescript"
| "wasm"
| "yaml"

type Token = {
types: string[]
content: string
empty?: boolean
}

type PrismGrammar = {
[key: string]: any
}

type LanguageDict = { [lang in Language]: PrismGrammar }

type PrismLib = {
languages: LanguageDict
tokenize: (code: string, grammar: PrismGrammar, language: Language) => PrismToken[] | string[]
highlight: (code: string, grammar: PrismGrammar, language: Language) => string
}

type PrismThemeEntry = {
color?: string
backgroundColor?: string
fontStyle?: "normal" | "italic"
fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900"
textDecorationLine?: "none" | "underline" | "line-through" | "underline line-through"
opacity?: number
[styleKey: string]: string | number | void
}

type PrismTheme = {
plain: PrismThemeEntry
styles: Array<{
types: string[]
style: PrismThemeEntry
languages?: Language[]
}>
}

type ThemeDict = {
root: StyleObj
plain: StyleObj
[type: string]: StyleObj
}

type PrismToken = {
type: string
content: Array<PrismToken | string> | string
}

type StyleObj = {
[key: string]: string | number | null
}

type LineInputProps = {
key?: React.Key
style?: StyleObj
className?: string
line: Token[]
[otherProp: string]: any
}

type LineOutputProps = {
key?: React.Key
style?: StyleObj
className: string
[otherProps: string]: any
}

type TokenInputProps = {
key?: React.Key
style?: StyleObj
className?: string
token: Token
[otherProp: string]: any
}

type TokenOutputProps = {
key?: React.Key
style?: StyleObj
className: string
children: string
[otherProp: string]: any
}

type RenderProps = {
tokens: Token[][]
className: string
style: StyleObj
getLineProps: (input: LineInputProps) => LineOutputProps
getTokenProps: (input: TokenInputProps) => TokenOutputProps
}

type DefaultProps = {
Prism: PrismLib
theme: PrismTheme
}

interface HighlightProps {
Prism: PrismLib
theme?: PrismTheme
language: Language
code: string
children: (props: RenderProps) => React.ReactNode
}

export interface HighlightInnerProps {
className: string
style: StyleObj
tokens: Token[][]
themeDict: ThemeDict
getLineProps: (lineInputProps: LineInputProps) => LineOutputProps
getStyleForToken: (token: Token) => { [inlineStyle: string]: string }
getTokenProps: (tokenInputPropsL: TokenInputProps) => TokenOutputProps
}
Loading