Skip to content

Commit 1572433

Browse files
author
Mustaqim Arifin
committed
Fix::
1 - Replaced `KY` with `GOT` to address looping issues in NextJS 2 - Replaced `React-Lazy-Images` wtih Native Image Component
1 parent 9ee2d93 commit 1572433

File tree

18 files changed

+583
-332
lines changed

18 files changed

+583
-332
lines changed

examples/full/pages/_app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'katex/dist/katex.min.css'
33
// used for code syntax highlighting (optional)
44
import 'prismjs/themes/prism-tomorrow.css'
55
// core styles shared by all of react-notion-x (required)
6-
import 'react-notion-x/src/styles.css'
6+
//import 'react-notion-x/src/styles.css'
77
// app styles
88
import '../styles/globals.css'
99

examples/minimal/next.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default {
1+
const nextConfig = {
22
staticPageGenerationTimeout: 300,
33
images: {
44
domains: [
@@ -10,3 +10,5 @@ export default {
1010
formats: ['image/avif', 'image/webp']
1111
}
1212
}
13+
14+
export default nextConfig

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"dev": "turbo dev --concurrency 50 --continue --filter='./packages/*'",
1717
"clean": "turbo clean",
1818
"test": "turbo test",
19-
"test:format": "prettier --check \"**/*.{js,ts,tsx}\"",
19+
"test:format": "prettier --check \"**/*.{js,ts,tsx}\" --write",
2020
"test:lint": "turbo test:lint",
2121
"test:typecheck": "turbo test:typecheck",
2222
"test:unit": "turbo test:unit",
@@ -32,6 +32,7 @@
3232
"bumpp": "catalog:",
3333
"del-cli": "catalog:",
3434
"eslint": "catalog:",
35+
"got": "catalog:",
3536
"npm-run-all2": "catalog:",
3637
"prettier": "catalog:",
3738
"react": "catalog:",

packages/notion-client/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@
2222
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
2323
"clean": "del build",
2424
"test": "run-s test:*",
25-
"test:lint": "eslint .",
25+
"test:lint": "eslint . --fix",
2626
"test:typecheck": "tsc --noEmit",
2727
"test:unit": "vitest run"
2828
},
2929
"dependencies": {
3030
"ky": "catalog:",
31+
"got": "catalog:",
3132
"notion-types": "workspace:*",
3233
"notion-utils": "workspace:*",
3334
"p-map": "catalog:"

packages/notion-client/src/notion-api.ts

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// import { promises as fs } from 'fs'
21
import type * as notion from 'notion-types'
3-
import ky, { type Options as KyOptions } from 'ky'
2+
import got, { type OptionsOfJSONResponseBody as Got_Options } from 'got'
43
import {
54
getBlockCollectionId,
65
getPageContentBlockIds,
@@ -19,7 +18,7 @@ export class NotionAPI {
1918
private readonly _authToken?: string
2019
private readonly _activeUser?: string
2120
private readonly _userTimeZone: string
22-
private readonly _kyOptions?: KyOptions
21+
private readonly _kyOptions?: Got_Options
2322

2423
constructor({
2524
apiBaseUrl = 'https://www.notion.so/api/v3',
@@ -33,7 +32,7 @@ export class NotionAPI {
3332
userLocale?: string
3433
userTimeZone?: string
3534
activeUser?: string
36-
kyOptions?: KyOptions
35+
kyOptions?: Got_Options
3736
} = {}) {
3837
this._apiBaseUrl = apiBaseUrl
3938
this._authToken = authToken
@@ -65,7 +64,7 @@ export class NotionAPI {
6564
throwOnCollectionErrors?: boolean
6665
collectionReducerLimit?: number
6766
fetchRelationPages?: boolean
68-
kyOptions?: KyOptions
67+
kyOptions?: Got_Options
6968
} = {}
7069
): Promise<notion.ExtendedRecordMap> {
7170
const page = await this.getPageRaw(pageId, {
@@ -232,7 +231,7 @@ export class NotionAPI {
232231

233232
fetchRelationPages = async (
234233
recordMap: notion.ExtendedRecordMap,
235-
kyOptions: KyOptions | undefined
234+
kyOptions: Got_Options | undefined
236235
): Promise<notion.BlockMap> => {
237236
const maxIterations = 10
238237

@@ -320,7 +319,7 @@ export class NotionAPI {
320319
}: {
321320
recordMap: notion.ExtendedRecordMap
322321
contentBlockIds?: string[]
323-
kyOptions?: KyOptions
322+
kyOptions?: Got_Options
324323
}) {
325324
recordMap.signed_urls = {}
326325

@@ -401,7 +400,7 @@ export class NotionAPI {
401400
}: {
402401
chunkLimit?: number
403402
chunkNumber?: number
404-
kyOptions?: KyOptions
403+
kyOptions?: Got_Options
405404
} = {}
406405
) {
407406
const parsedPageId = parsePageId(pageId)
@@ -442,7 +441,7 @@ export class NotionAPI {
442441
userTimeZone?: string
443442
userLocale?: string
444443
loadContentCover?: boolean
445-
kyOptions?: KyOptions
444+
kyOptions?: Got_Options
446445
} = {}
447446
) {
448447
const type = collectionView?.type
@@ -620,7 +619,9 @@ export class NotionAPI {
620619
loader
621620
},
622621
kyOptions: {
623-
timeout: 60_000,
622+
timeout: {
623+
request: 60_000
624+
},
624625
...kyOptions,
625626
searchParams: {
626627
// TODO: spread kyOptions?.searchParams
@@ -630,7 +631,7 @@ export class NotionAPI {
630631
})
631632
}
632633

633-
public async getUsers(userIds: string[], kyOptions?: KyOptions) {
634+
public async getUsers(userIds: string[], kyOptions?: Got_Options) {
634635
return this.fetch<notion.RecordValues<notion.User>>({
635636
endpoint: 'getRecordValues',
636637
body: {
@@ -640,7 +641,7 @@ export class NotionAPI {
640641
})
641642
}
642643

643-
public async getBlocks(blockIds: string[], kyOptions?: KyOptions) {
644+
public async getBlocks(blockIds: string[], kyOptions?: Got_Options) {
644645
return this.fetch<notion.PageChunk>({
645646
endpoint: 'syncRecordValues',
646647
body: {
@@ -657,7 +658,7 @@ export class NotionAPI {
657658

658659
public async getSignedFileUrls(
659660
urls: types.SignedUrlRequest[],
660-
kyOptions?: KyOptions
661+
kyOptions?: Got_Options
661662
) {
662663
return this.fetch<types.SignedUrlResponse>({
663664
endpoint: 'getSignedFileUrls',
@@ -668,7 +669,7 @@ export class NotionAPI {
668669
})
669670
}
670671

671-
public async search(params: notion.SearchParams, kyOptions?: KyOptions) {
672+
public async search(params: notion.SearchParams, kyOptions?: Got_Options) {
672673
const body = {
673674
type: 'BlocksInAncestor',
674675
source: 'quick_find_public',
@@ -708,7 +709,7 @@ export class NotionAPI {
708709
}: {
709710
endpoint: string
710711
body: object
711-
kyOptions?: KyOptions
712+
kyOptions?: Got_Options
712713
headers?: any
713714
}): Promise<T> {
714715
const headers: any = {
@@ -728,21 +729,12 @@ export class NotionAPI {
728729

729730
const url = `${this._apiBaseUrl}/${endpoint}`
730731

731-
const res = await ky.post(url, {
732-
mode: 'no-cors',
733-
...this._kyOptions,
734-
...kyOptions,
735-
json: body,
736-
headers
737-
})
738-
739-
// TODO: we're awaiting the first fetch and then separately awaiting
740-
// `res.json()` because there seems to be some weird error which repros
741-
// sporadically when loading collections where the body is already used.
742-
// No idea why, but from my testing, separating these into two separate
743-
// steps seems to fix the issue locally for me...
744-
// console.log(endpoint, { bodyUsed: res.bodyUsed })
745-
746-
return res.json<T>()
732+
return got
733+
.post(url, {
734+
...kyOptions,
735+
json: body,
736+
headers
737+
})
738+
.json()
747739
}
748740
}

packages/notion-compat/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
2323
"clean": "del build",
2424
"test": "run-s test:*",
25-
"test:lint": "eslint .",
25+
"test:lint": "eslint . --fix",
2626
"test:typecheck": "tsc --noEmit",
2727
"test:unit": "vitest run"
2828
},

packages/notion-utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
2929
"clean": "del build",
3030
"test": "run-s test:*",
31-
"test:lint": "eslint .",
31+
"test:lint": "eslint . --fix",
3232
"test:typecheck": "tsc --noEmit",
3333
"test:unit": "vitest run"
3434
},

packages/react-notion-x/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"main": "./build/index.js",
1010
"module": "./build/index.js",
1111
"types": "./build/index.d.ts",
12-
"sideEffects": false,
12+
"sideEffects": ["src/styles.css"],
1313
"exports": {
1414
".": {
1515
"types": "./build/index.d.ts",
@@ -51,7 +51,7 @@
5151
"watch": "tsup --watch --silent --onSuccess 'echo build successful'",
5252
"clean": "del build",
5353
"test": "run-s test:*",
54-
"test:lint": "eslint .",
54+
"test:lint": "eslint . --fix",
5555
"test:typecheck": "tsc --noEmit"
5656
},
5757
"dependencies": {
@@ -78,7 +78,7 @@
7878
"lodash.throttle": "catalog:",
7979
"react": "catalog:",
8080
"react-dom": "catalog:",
81-
"react-pdf": "^9.1.1"
81+
"react-pdf": "^9.1.1", "lightningcss": "catalog:"
8282
},
8383
"peerDependencies": {
8484
"react": ">=18",

packages/react-notion-x/src/components/lazy-image.tsx

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { normalizeUrl } from 'notion-utils'
22
import React from 'react'
3-
import { ImageState, LazyImageFull } from 'react-lazy-images'
43

54
import { useNotionContext } from '../context'
65
import { cs } from '../utils'
@@ -59,6 +58,23 @@ export function LazyImage({
5958
[zoomable, attachZoom]
6059
)
6160

61+
const [isLazyLoaded, setIsLazyLoaded] = React.useState(false)
62+
const onLoadLazy = React.useCallback(() => {
63+
setIsLazyLoaded(true)
64+
}, [])
65+
66+
const lazyImageRef = React.useCallback(
67+
(image: HTMLImageElement) => {
68+
attachZoomRef?.(image)
69+
70+
// if the image is cached, we can trigger the onLoadLazy immediately
71+
if (image.complete) {
72+
onLoadLazy()
73+
}
74+
},
75+
[attachZoomRef, onLoadLazy]
76+
)
77+
6278
if (previewImage) {
6379
const aspectRatio = previewImage.originalHeight / previewImage.originalWidth
6480

@@ -81,60 +97,54 @@ export function LazyImage({
8197
)
8298
}
8399

84-
return (
85-
// @ts-expect-error LazyImage types are out-of-date.
86-
<LazyImageFull src={src!} {...rest} experimentalDecode={true}>
87-
{({ imageState, ref }) => {
88-
const isLoaded = imageState === ImageState.LoadSuccess
89-
const wrapperStyle: React.CSSProperties = {
90-
width: '100%'
91-
}
92-
const imgStyle: React.CSSProperties = {}
93-
94-
if (height) {
95-
wrapperStyle.height = height
96-
} else {
97-
imgStyle.position = 'absolute'
98-
wrapperStyle.paddingBottom = `${aspectRatio * 100}%`
99-
}
100-
101-
return (
102-
<div
103-
className={cs(
104-
'lazy-image-wrapper',
105-
isLoaded && 'lazy-image-loaded',
106-
className
107-
)}
108-
style={wrapperStyle}
109-
>
110-
<img
111-
className='lazy-image-preview'
112-
src={previewImage.dataURIBase64}
113-
alt={alt}
114-
ref={ref}
115-
style={style}
116-
decoding='async'
117-
/>
118-
119-
<img
120-
className='lazy-image-real'
121-
src={src}
122-
alt={alt}
123-
ref={attachZoomRef}
124-
style={{
125-
...style,
126-
...imgStyle
127-
}}
128-
width={previewImage.originalWidth}
129-
height={previewImage.originalHeight}
130-
decoding='async'
131-
loading='lazy'
132-
/>
133-
</div>
134-
)
135-
}}
136-
</LazyImageFull>
137-
)
100+
return (() => {
101+
const wrapperStyle: React.CSSProperties = {
102+
width: '100%'
103+
}
104+
const imgStyle: React.CSSProperties = {}
105+
106+
if (height) {
107+
wrapperStyle.height = height
108+
} else {
109+
imgStyle.position = 'absolute'
110+
wrapperStyle.paddingBottom = `${aspectRatio * 100}%`
111+
}
112+
113+
return (
114+
<div
115+
className={cs(
116+
'lazy-image-wrapper',
117+
isLazyLoaded && 'lazy-image-loaded',
118+
className
119+
)}
120+
style={wrapperStyle}
121+
>
122+
<img
123+
className='lazy-image-preview'
124+
src={previewImage.dataURIBase64}
125+
alt={alt}
126+
style={style}
127+
decoding='async'
128+
/>
129+
130+
<img
131+
className='lazy-image-real'
132+
src={src}
133+
alt={alt}
134+
ref={lazyImageRef}
135+
style={{
136+
...style,
137+
...imgStyle
138+
}}
139+
width={previewImage.originalWidth}
140+
height={previewImage.originalHeight}
141+
decoding='async'
142+
loading='lazy'
143+
onLoad={onLoadLazy}
144+
/>
145+
</div>
146+
)
147+
})()
138148
} else {
139149
// TODO: GracefulImage doesn't seem to support refs, but we'd like to prevent
140150
// invalid images from loading as error states

0 commit comments

Comments
 (0)