mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
Merge pull request #198 from kremalicious/feature/code-splitting
code splitting
This commit is contained in:
commit
5426c3b646
18
package-lock.json
generated
18
package-lock.json
generated
@ -1841,6 +1841,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@loadable/component": {
|
||||
"version": "5.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@loadable/component/-/component-5.10.3.tgz",
|
||||
"integrity": "sha512-/aSO+tXw4vFMwZ6fgLaNQgLuEa7bgTpoBE4PxNzf08/ewAjymrCS3J7v3SbGE7IjGmmKL6vVwkpb7S3cYrk+ag==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.6.0",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@mapbox/hast-util-table-cell-style": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz",
|
||||
@ -2382,6 +2391,15 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz",
|
||||
"integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A=="
|
||||
},
|
||||
"@types/loadable__component": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/loadable__component/-/loadable__component-5.10.0.tgz",
|
||||
"integrity": "sha512-AaDP1VxV3p7CdPOtOTl3ALgQ6ES4AxJKO9UGj9vJonq/w2yERxwdzFiWNQFh9fEDXEzjxujBlM2RmSJtHV1/pA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/lunr": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.2.tgz",
|
||||
|
@ -29,6 +29,7 @@
|
||||
"not op_mini all"
|
||||
],
|
||||
"dependencies": {
|
||||
"@loadable/component": "^5.10.3",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^2.8.1",
|
||||
"dms2dec": "^1.1.0",
|
||||
@ -92,6 +93,7 @@
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/jest": "^24.0.21",
|
||||
"@types/loadable__component": "^5.10.0",
|
||||
"@types/lunr": "^2.3.2",
|
||||
"@types/node": "^12.12.11",
|
||||
"@types/react": "^16.9.11",
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React from 'react'
|
||||
import Clipboard from 'react-clipboard.js'
|
||||
|
||||
import loadable from '@loadable/component'
|
||||
import styles from './Copy.module.scss'
|
||||
import Icon from './Icon'
|
||||
|
||||
const Clipboard = loadable(() => import('react-clipboard.js'))
|
||||
|
||||
const onCopySuccess = (e: any) => {
|
||||
e.trigger.classList.add(styles.copied)
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from '@testing-library/react'
|
||||
import React, { Suspense } from 'react'
|
||||
import { render, fireEvent, waitForElement } from '@testing-library/react'
|
||||
|
||||
import Qr from './Qr'
|
||||
|
||||
describe('Qr', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Qr address="xxx" />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
test('renders lazy', async () => {
|
||||
const { container } = render(
|
||||
<Suspense fallback="test loading">
|
||||
<Qr address="xxx" />
|
||||
</Suspense>
|
||||
)
|
||||
const lazyElement = await waitForElement(() =>
|
||||
container.querySelector('button')
|
||||
)
|
||||
expect(lazyElement).toBeInTheDocument()
|
||||
fireEvent.click(container.querySelector('button'))
|
||||
})
|
||||
})
|
||||
|
@ -1,9 +1,16 @@
|
||||
import React from 'react'
|
||||
// import { render } from '@testing-library/react'
|
||||
import testRender from '../../../jest/testRender'
|
||||
import React, { Suspense } from 'react'
|
||||
import { render, waitForElement } from '@testing-library/react'
|
||||
|
||||
import Time from './Time'
|
||||
|
||||
describe('Time', () => {
|
||||
testRender(<Time date="2017/12/23" />)
|
||||
test('renders lazy', async () => {
|
||||
const { getByText } = render(
|
||||
<Suspense fallback="test loading">
|
||||
<Time date="2017/12/23" />
|
||||
</Suspense>
|
||||
)
|
||||
const lazyElement = await waitForElement(() => getByText(/years ago/i))
|
||||
expect(lazyElement).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
@ -1,15 +1,41 @@
|
||||
import React from 'react'
|
||||
import { format, formatDistance } from 'date-fns'
|
||||
import loadable from '@loadable/component'
|
||||
|
||||
const LazyDate = loadable.lib(() => import('date-fns'))
|
||||
|
||||
function TimeMarkup({
|
||||
date,
|
||||
format,
|
||||
formatDistance
|
||||
}: {
|
||||
date: Date
|
||||
format?: any
|
||||
formatDistance?: any
|
||||
}) {
|
||||
const dateIso = date.toISOString()
|
||||
|
||||
return (
|
||||
<time
|
||||
title={format ? format(date, 'yyyy/MM/dd HH:mm') : dateIso}
|
||||
dateTime={dateIso}
|
||||
>
|
||||
{format ? formatDistance(date, Date.now(), { addSuffix: true }) : dateIso}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Time({ date }: { date: string }) {
|
||||
const dateNew = new Date(date)
|
||||
|
||||
return (
|
||||
<time
|
||||
title={format(dateNew, 'yyyy/MM/dd HH:mm')}
|
||||
dateTime={dateNew.toISOString()}
|
||||
>
|
||||
{formatDistance(dateNew, Date.now(), { addSuffix: true })}
|
||||
</time>
|
||||
<LazyDate fallback={<TimeMarkup date={dateNew} />}>
|
||||
{({ format, formatDistance }) => (
|
||||
<TimeMarkup
|
||||
date={dateNew}
|
||||
format={format}
|
||||
formatDistance={formatDistance}
|
||||
/>
|
||||
)}
|
||||
</LazyDate>
|
||||
)
|
||||
}
|
||||
|
@ -12,10 +12,8 @@ const SearchResultsEmpty = ({
|
||||
<div className={styles.empty}>
|
||||
<header className={styles.emptyMessage}>
|
||||
<p className={styles.emptyMessageText}>
|
||||
{searchQuery.length > 1 && results.length === 0
|
||||
{searchQuery.length > 0 && results.length === 0
|
||||
? 'No results found'
|
||||
: searchQuery.length === 1
|
||||
? 'Just one more character'
|
||||
: 'Awaiting your input'}
|
||||
</p>
|
||||
</header>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { CSSTransition } from 'react-transition-group'
|
||||
import SearchInput from './SearchInput'
|
||||
@ -7,30 +7,30 @@ import SearchResults from './SearchResults'
|
||||
|
||||
import styles from './index.module.scss'
|
||||
|
||||
function getSearchResults(query: string, lng: string) {
|
||||
if (!query || !window.__LUNR__) return []
|
||||
const lunrIndex = window.__LUNR__[lng]
|
||||
const results = lunrIndex.index.search(query)
|
||||
return results.map(({ ref }: { ref: string }) => lunrIndex.store[ref])
|
||||
}
|
||||
|
||||
export default function Search({ lng }: { lng: string }) {
|
||||
export default function Search() {
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
const [query, setQuery] = useState('')
|
||||
const [results, setResults] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
if (!query || !window.__LUNR__) {
|
||||
setResults([])
|
||||
return
|
||||
}
|
||||
|
||||
const lunrIndex = window.__LUNR__['en']
|
||||
const searchResults = lunrIndex.index.search(query)
|
||||
setResults(
|
||||
searchResults.map(({ ref }) => {
|
||||
return lunrIndex.store[ref]
|
||||
})
|
||||
)
|
||||
}, [query])
|
||||
|
||||
const toggleSearch = () => {
|
||||
setSearchOpen(!searchOpen)
|
||||
}
|
||||
|
||||
const search = (event: any) => {
|
||||
const query = event.target.value
|
||||
// wildcard search https://lunrjs.com/guides/searching.html#wildcards
|
||||
const results = query.length > 1 ? getSearchResults(`${query}*`, lng) : []
|
||||
setQuery(query)
|
||||
setResults(results)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchButton onClick={toggleSearch} />
|
||||
@ -50,7 +50,7 @@ export default function Search({ lng }: { lng: string }) {
|
||||
<section className={styles.search}>
|
||||
<SearchInput
|
||||
value={query}
|
||||
onChange={(e: Event) => search(e)}
|
||||
onChange={(e: any) => setQuery(e.target.value)}
|
||||
onToggle={toggleSearch}
|
||||
/>
|
||||
</section>
|
||||
|
@ -20,7 +20,7 @@ export default class Header extends PureComponent {
|
||||
</h1>
|
||||
|
||||
<nav role="navigation" className={styles.nav}>
|
||||
<Search lng="en" />
|
||||
<Search />
|
||||
<Menu />
|
||||
</nav>
|
||||
</div>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
import React from 'react'
|
||||
import loadable from '@loadable/component'
|
||||
import shortid from 'shortid'
|
||||
import Helmet from 'react-helmet'
|
||||
import { Author } from '../@types/Site'
|
||||
@ -7,7 +8,9 @@ import Qr from '../components/atoms/Qr'
|
||||
import Icon from '../components/atoms/Icon'
|
||||
import styles from './thanks.module.scss'
|
||||
|
||||
const Web3Donation = lazy(() => import('../components/molecules/Web3Donation'))
|
||||
const Web3Donation = loadable(() =>
|
||||
import('../components/molecules/Web3Donation')
|
||||
)
|
||||
|
||||
const Coin = ({ address, author }: { address: string; author: Author }) => (
|
||||
<div className={styles.coin}>
|
||||
@ -29,7 +32,6 @@ export default function Thanks() {
|
||||
const coins = Object.keys(author).filter(
|
||||
key => key === 'bitcoin' || key === 'ether'
|
||||
)
|
||||
const isSSR = typeof window === 'undefined'
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -43,26 +45,22 @@ export default function Thanks() {
|
||||
<header>
|
||||
<h1 className={styles.title}>Say Thanks</h1>
|
||||
</header>
|
||||
{!isSSR && (
|
||||
<Suspense fallback={<div className={styles.loading}>Loading...</div>}>
|
||||
<Web3Donation address={author.ether} />
|
||||
|
||||
<div className={styles.coins}>
|
||||
<header>
|
||||
<h4>Any other wallets</h4>
|
||||
<p>Send Bitcoin or Ether from any wallet.</p>
|
||||
</header>
|
||||
<Web3Donation
|
||||
fallback={<div className={styles.loading}>Loading...</div>}
|
||||
address={author.ether}
|
||||
/>
|
||||
|
||||
{coins.map((address: string) => (
|
||||
<Coin
|
||||
key={shortid.generate()}
|
||||
address={address}
|
||||
author={author}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Suspense>
|
||||
)}
|
||||
<div className={styles.coins}>
|
||||
<header>
|
||||
<h4>Any other wallets</h4>
|
||||
<p>Send Bitcoin or Ether from any wallet.</p>
|
||||
</header>
|
||||
|
||||
{coins.map((address: string) => (
|
||||
<Coin key={shortid.generate()} address={address} author={author} />
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
</>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user