Skip to content

Commit

Permalink
feat(gatsby-theme-minimal-blog): Lazy load code component (#167)
Browse files Browse the repository at this point in the history
* add loadable to code component of minimal blog

* add bundle analyser to example

* chore(deps): update dependency @types/theme-ui to ^0.2.5 (#161)

* chore(deps): update dependency lerna to ^3.19.0 (#163)

* chore(deps): update dependency ts-jest to ^24.2.0 (#164)

* chore(deps): update linting & formatting + typescript (#165)

* fix(deps): update gatsby (#166)


Co-authored-by: null <29139614+renovate[bot]@users.noreply.github.com>
  • Loading branch information
LekoArts and renovate[bot] authored Nov 25, 2019
1 parent 8b5cd32 commit fbfedee
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 20 deletions.
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

0 comments on commit fbfedee

Please sign in to comment.