From 00232de4a7e8b01478fce241766d929595544dbb Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 11 Mar 2024 14:08:57 +0000 Subject: [PATCH] Made the editor load only when visible on the page --- .../components/code-editor/code-editor.tsx | 26 ++--- .../code-editor/lazy-loaded-editor.tsx | 68 +++++------- .../src/components/code-editor/mdx-editor.tsx | 86 ++++++++++++++ .../code-editor/transpile-preview.tsx | 39 ------- .../src/components/mdx/index.tsx | 2 +- .../src/pages/editor-test.tsx | 105 ------------------ 6 files changed, 121 insertions(+), 205 deletions(-) create mode 100644 apps/total-typescript/src/components/code-editor/mdx-editor.tsx delete mode 100644 apps/total-typescript/src/components/code-editor/transpile-preview.tsx delete mode 100644 apps/total-typescript/src/pages/editor-test.tsx diff --git a/apps/total-typescript/src/components/code-editor/code-editor.tsx b/apps/total-typescript/src/components/code-editor/code-editor.tsx index 40f31a83c6..0cf02b0e3f 100644 --- a/apps/total-typescript/src/components/code-editor/code-editor.tsx +++ b/apps/total-typescript/src/components/code-editor/code-editor.tsx @@ -50,10 +50,6 @@ export type CodeEditorProps = { onEmittedJavaScript?: (code: string) => void } -const getHeight = (code: string) => { - return code.split('\n').length * 24 -} - let incrementable = 0 /** @@ -86,14 +82,18 @@ export const EagerlyLoadedEditor = (props: CodeEditorProps) => { return } - const worker = - await monacoRef.current.languages.typescript.getTypeScriptWorker() + try { + const worker = + await monacoRef.current.languages.typescript.getTypeScriptWorker() - const client = await worker(uri) + const client = await worker(uri) - const emitOutput = await client.getEmitOutput(uri.toString()) + const emitOutput = await client.getEmitOutput(uri.toString()) - props.onEmittedJavaScript(emitOutput.outputFiles[0].text) + props.onEmittedJavaScript(emitOutput.outputFiles[0].text) + } catch (e) { + console.error('Getting emitted JavaScript failed', e) + } } return ( @@ -177,11 +177,3 @@ export const EagerlyLoadedEditor = (props: CodeEditorProps) => { /> ) } - -export const EagerlyLoadedFullWidthEditor = (props: CodeEditorProps) => { - return ( -
- -
- ) -} diff --git a/apps/total-typescript/src/components/code-editor/lazy-loaded-editor.tsx b/apps/total-typescript/src/components/code-editor/lazy-loaded-editor.tsx index 105ba1821a..73c1b7777a 100644 --- a/apps/total-typescript/src/components/code-editor/lazy-loaded-editor.tsx +++ b/apps/total-typescript/src/components/code-editor/lazy-loaded-editor.tsx @@ -1,60 +1,42 @@ -import React from 'react' -import type {Language} from './code-editor' +import React, {useLayoutEffect} from 'react' +import type {CodeEditorProps} from './code-editor' -export const LazyLoadedFullWidthEditor = React.lazy(() => +const _LazyLoadedEditor = React.lazy(() => import('./code-editor').then((res) => { return { - default: res.EagerlyLoadedFullWidthEditor, + default: res.EagerlyLoadedEditor, } }), ) -export const LazyLoadedTranspilePreview = React.lazy(() => - import('./transpile-preview').then((res) => { - return { - default: res.EagerlyLoadedTranspilePreview, - } - }), -) +const LoadWhenVisible = (props: {children: React.ReactNode}) => { + const [isVisible, setIsVisible] = React.useState(false) -export const MDXEditor = (props: {children?: any}) => { - // Yes, we're diving into React's internals to grab the - // code from the
 element
-  const code = props.children?.props?.children?.props?.children
+  const ref = React.useRef(null)
 
-  if (!code) {
-    return null
-  }
+  React.useEffect(() => {
+    const observer = new IntersectionObserver(([entry]) => {
+      setIsVisible(entry.isIntersecting)
+    })
 
-  let language = props.children?.props?.children?.props?.className
-
-  if (language) {
-    language = language.replace('language-', '') as Language
-  }
-
-  return 
-}
+    observer.observe(ref.current!)
 
-export const MDXTranspilePreview = (props: {children?: any}) => {
-  // Yes, we're diving into React's internals to grab the
-  // code from the 
 element
-  const code = props.children?.props?.children?.props?.children
-
-  if (!code) {
-    return null
-  }
-
-  let language = props.children?.props?.children?.props?.className
-
-  if (language) {
-    language = language.replace('language-', '') as Language
-  }
+    return () => {
+      observer.disconnect()
+    }
+  }, [])
 
-  return 
+  return (
+    
+ {isVisible ? props.children : null} +
+ ) } -export const EditorTest = () => { +export const LazyLoadedEditor = (props: CodeEditorProps) => { return ( - {}`} /> + + <_LazyLoadedEditor {...props} /> + ) } diff --git a/apps/total-typescript/src/components/code-editor/mdx-editor.tsx b/apps/total-typescript/src/components/code-editor/mdx-editor.tsx new file mode 100644 index 0000000000..54fa641f1a --- /dev/null +++ b/apps/total-typescript/src/components/code-editor/mdx-editor.tsx @@ -0,0 +1,86 @@ +import Image from 'next/image' +import {useState} from 'react' +import type {CodeEditorProps, Language} from './code-editor' +import {LazyLoadedEditor} from './lazy-loaded-editor' +import tsSvg from './ts-logo.svg' +import jsSvg from './js-logo.svg' + +const getHeight = (code: string) => { + return (code.split('\n').length + 3) * 24 +} + +const extractCodeAndLanguage = (props: {children?: any}) => { + const code = props.children?.props?.children?.props?.children + let language = props.children?.props?.children?.props?.className + + if (!code || !language) { + return null + } + + language = language.replace('language-', '') as Language + + return {code, language} +} + +export const MDXEditor = (props: {children?: any}) => { + // Yes, we're diving into React's internals to grab the + // code from the
 element
+  const extracted = extractCodeAndLanguage(props)
+
+  if (!extracted) {
+    return null
+  }
+
+  const {code, language} = extracted
+
+  return (
+    
+ +
+ ) +} + +export const MDXTranspilePreview = (props: {children?: any}) => { + const extracted = extractCodeAndLanguage(props) + const [jsCode, setJsCode] = useState(undefined) + + if (!extracted) { + return null + } + + const {code, language} = extracted + + return ( +
+
+ +
+ TypeScript Logo + TypeScript Code +
+
+
+ +
+ JavaScript Logo + Emitted JavaScript +
+
+
+ ) +} diff --git a/apps/total-typescript/src/components/code-editor/transpile-preview.tsx b/apps/total-typescript/src/components/code-editor/transpile-preview.tsx deleted file mode 100644 index 0fbd23b811..0000000000 --- a/apps/total-typescript/src/components/code-editor/transpile-preview.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import {useState} from 'react' -import {CodeEditorProps, EagerlyLoadedEditor} from './code-editor' -import tsSvg from './ts-logo.svg' -import jsSvg from './js-logo.svg' -import Image from 'next/image' - -export const EagerlyLoadedTranspilePreview = ( - props: Omit, -) => { - const [code, setCode] = useState(undefined) - - return ( -
-
- -
- TypeScript Logo - TypeScript Code -
-
-
- -
- JavaScript Logo - Emitted JavaScript -
-
-
- ) -} diff --git a/apps/total-typescript/src/components/mdx/index.tsx b/apps/total-typescript/src/components/mdx/index.tsx index f592949d3d..a4e10bafd7 100644 --- a/apps/total-typescript/src/components/mdx/index.tsx +++ b/apps/total-typescript/src/components/mdx/index.tsx @@ -10,7 +10,7 @@ import toast from 'react-hot-toast' import {useCopyToClipboard} from 'react-use' import Balancer from 'react-wrap-balancer' import {twMerge} from 'tailwind-merge' -import {MDXEditor, MDXTranspilePreview} from '../code-editor/lazy-loaded-editor' +import {MDXEditor, MDXTranspilePreview} from '../code-editor/mdx-editor' export const MDXComponents = { TypeError: (props) => , diff --git a/apps/total-typescript/src/pages/editor-test.tsx b/apps/total-typescript/src/pages/editor-test.tsx deleted file mode 100644 index fab3d1484c..0000000000 --- a/apps/total-typescript/src/pages/editor-test.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import Layout from '@/components/app/layout' -import {EditorTest} from '@/components/code-editor/lazy-loaded-editor' - -import {cn} from '@skillrecordings/ui/utils/cn' -import Image from 'next/image' - -const title = 'How to use TypeScript with React' - -const config = { - author: 'Matt Pocock', - authorBio: 'Frontend Engineer, TypeScript Enthusiast', -} - -const isBookTeaser = true - -const ArticleTemplate: React.FC = () => { - return ( - -
-
-

- {title} -

-
-
-
- Matt Pocock -
-
- {config.author} - - {config.authorBio} - -
-
-
-
- {isBookTeaser && ( -
- -
- )} - {/* {image && !isBookTeaser && ( -
- - -
- )} */} -
-
-
- -
- Matt's signature -
-
-
-
- ) -} - -export default ArticleTemplate