Skip to content

Commit

Permalink
refactor: Use standard lazy loading for repl runner & editor (#1223)
Browse files Browse the repository at this point in the history
  • Loading branch information
rschristian authored Jan 12, 2025
1 parent b4f3adc commit 6b99d15
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 131 deletions.
6 changes: 3 additions & 3 deletions src/components/content-region/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import style from './style.module.css';
import { useTranslation } from '../../lib/i18n';
import { TocContext } from '../table-of-contents';
import { prefetchContent } from '../../lib/use-content';
import { preloadRepl } from '../../lib/use-repl';
import { Repl, TutorialPage } from '../routes';
import { preloadRepl } from '../../lib/repl';
import { ReplPage, TutorialPage } from '../routes';

const COMPONENTS = {
...widgets,
Expand All @@ -16,7 +16,7 @@ const COMPONENTS = {

props.onMouseOver = () => {
if (props.href.startsWith('/repl?code')) {
Repl.preload();
ReplPage.preload();
preloadRepl();
} else if (props.href.startsWith('/tutorial')) {
TutorialPage.preload();
Expand Down
64 changes: 32 additions & 32 deletions src/components/controllers/repl/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState, useEffect } from 'preact/hooks';
import { useLocation, useRoute } from 'preact-iso';
import { useLocation, useRoute, ErrorBoundary } from 'preact-iso';
import { Splitter } from '../../splitter';
import { textToBase64 } from './query-encode.js';
import { ErrorOverlay } from './error-overlay';
import { EXAMPLES, fetchExample } from './examples';
import { useStoredValue } from '../../../lib/localstorage';
import { useRepl } from '../../../lib/use-repl';
import { Repl as _Repl } from '../../../lib/repl.js';
import { parseStackTrace } from './errors';
import style from './style.module.css';
import REPL_CSS from './examples/style.css?raw';
Expand All @@ -26,8 +26,6 @@ export function Repl({ code }) {
// TODO: Needs some work for prerendering to not cause pop-in
if (typeof window === 'undefined') return null;

const { CodeEditor, Runner } = useRepl();

const applyExample = (e) => {
const slug = e.target.value;
fetchExample(slug)
Expand Down Expand Up @@ -112,35 +110,37 @@ export function Repl({ code }) {
</button>
</header>
<div class={style.replWrapper}>
<Splitter
orientation="horizontal"
other={
<div class={style.output}>
{error && (
<ErrorOverlay
name={error.name}
message={error.message}
stack={parseStackTrace(error)}
<ErrorBoundary>
<Splitter
orientation="horizontal"
other={
<div class={style.output}>
{error && (
<ErrorOverlay
name={error.name}
message={error.message}
stack={parseStackTrace(error)}
/>
)}
<_Repl.Runner
onRealm={onRealm}
onError={setError}
onSuccess={() => setError(null)}
css={REPL_CSS}
code={runnerCode}
/>
)}
<Runner
onRealm={onRealm}
onError={setError}
onSuccess={() => setError(null)}
css={REPL_CSS}
code={runnerCode}
/>
</div>
}
>
<CodeEditor
class={style.code}
value={editorCode}
error={error}
slug={query.example}
onInput={onEditorInput}
/>
</Splitter>
</div>
}
>
<_Repl.CodeEditor
class={style.code}
value={editorCode}
error={error}
slug={query.example}
onInput={onEditorInput}
/>
</Splitter>
</ErrorBoundary>
</div>
</>
);
Expand Down
136 changes: 68 additions & 68 deletions src/components/controllers/tutorial/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
useMemo,
useCallback
} from 'preact/hooks';
import { useLocation } from 'preact-iso';
import { ErrorBoundary, useLocation } from 'preact-iso';
import { TutorialContext, SolutionContext } from './contexts';
import { ErrorOverlay } from '../repl/error-overlay';
import { parseStackTrace } from '../repl/errors';
import cx from '../../../lib/cx';
import { useRepl } from '../../../lib/use-repl';
import { Repl } from '../../../lib/repl';
import { useLanguage } from '../../../lib/i18n';
import { Splitter } from '../../splitter';
import config from '../../../config.json';
Expand Down Expand Up @@ -61,8 +61,6 @@ export function Tutorial({ html, meta }) {
// TODO: Needs some work for prerendering to not cause pop-in
if (typeof window === 'undefined') return null;

const { CodeEditor, Runner } = useRepl();

useEffect(() => {
if (meta.tutorial?.initial && editorCode !== meta.tutorial.initial) {
setEditorCode(meta.tutorial.initial);
Expand Down Expand Up @@ -145,74 +143,76 @@ export function Tutorial({ html, meta }) {
showCode && style.showCode
)}
>
<Splitter
orientation="horizontal"
force={!showCode ? '100%' : undefined}
other={
<Splitter
orientation="vertical"
other={
<>
<div class={style.output}>
{error && (
<ErrorOverlay
name={error.name}
message={error.message}
stack={parseStackTrace(error)}
<ErrorBoundary>
<Splitter
orientation="horizontal"
force={!showCode ? '100%' : undefined}
other={
<Splitter
orientation="vertical"
other={
<>
<div class={style.output}>
{error && (
<ErrorOverlay
name={error.name}
message={error.message}
stack={parseStackTrace(error)}
/>
)}
<Repl.Runner
ref={runner}
onSuccess={onSuccess}
onRealm={onRealm}
onError={onError}
code={runnerCode}
/>
</div>
{hasCode && (
<button
class={style.toggleCode}
title="Toggle Code"
onClick={toggleCode}
>
<span>Toggle Code</span>
</button>
)}
<Runner
ref={runner}
onSuccess={onSuccess}
onRealm={onRealm}
onError={onError}
code={runnerCode}
/>
</div>
{hasCode && (
<button
class={style.toggleCode}
title="Toggle Code"
onClick={toggleCode}
>
<span>Toggle Code</span>
</button>
)}
</>
}
>
<div class={style.codeWindow}>
<CodeEditor
class={style.code}
value={editorCode}
error={error}
slug={url}
onInput={setEditorCode}
/>
</div>
</Splitter>
}
>
<div class={style.tutorialWindow} ref={content}>
<MarkdownRegion
html={html}
meta={meta}
components={TUTORIAL_COMPONENTS}
/>

{meta.tutorial?.setup &&
<TutorialSetupBlock
code={meta.tutorial.setup}
runner={runner}
useResult={useResult}
useRealm={useRealm}
useError={useError}
/>
</>
}
>
<div class={style.codeWindow}>
<Repl.CodeEditor
class={style.code}
value={editorCode}
error={error}
slug={url}
onInput={setEditorCode}
/>
</div>
</Splitter>
}
>
<div class={style.tutorialWindow} ref={content}>
<MarkdownRegion
html={html}
meta={meta}
components={TUTORIAL_COMPONENTS}
/>

{meta.tutorial?.setup &&
<TutorialSetupBlock
code={meta.tutorial.setup}
runner={runner}
useResult={useResult}
useRealm={useRealm}
useError={useError}
/>
}

<ButtonContainer meta={meta} showCode={showCode} help={help} />
</div>
</Splitter>
<ButtonContainer meta={meta} showCode={showCode} help={help} />
</div>
</Splitter>
</ErrorBoundary>
</div>
</TutorialContext.Provider>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/header/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { useOverlayToggle } from '../../lib/toggle-overlay';
import { useLocation } from 'preact-iso';
import { useLanguage } from '../../lib/i18n';
import { prefetchContent } from '../../lib/use-content';
import { preloadRepl } from '../../lib/use-repl';
import { Repl, TutorialPage } from '../routes';
import { preloadRepl } from '../../lib/repl';
import { ReplPage, TutorialPage } from '../routes';

const LINK_FLAIR = {
logo: InvertedLogo
Expand Down Expand Up @@ -224,7 +224,7 @@ const NavLink = ({ to, isOpen, route, ...props }) => {

const onMouseOver = () => {
if (prefetchHref.startsWith('/repl')) {
Repl.preload();
ReplPage.preload();
preloadRepl();
} else if (prefetchHref.startsWith('/tutorial')) {
TutorialPage.preload();
Expand Down
4 changes: 2 additions & 2 deletions src/components/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DocPage } from './controllers/doc-page';
import { NotFound } from './controllers/not-found';
import { navRoutes } from '../lib/route-utils';

export const Repl = lazy(() => import('./controllers/repl-page'));
export const ReplPage = lazy(() => import('./controllers/repl-page'));
export const BlogPage = lazy(() => import('./controllers/blog-page'));
export const TutorialPage = lazy(() => import('./controllers/tutorial-page'));

Expand All @@ -26,7 +26,7 @@ export default function Routes() {
.filter(route => !route.startsWith('/guide'))
.filter(route => !route.startsWith('/tutorial'))
.map(route => {
const component = route === '/repl' ? Repl : Page;
const component = route === '/repl' ? ReplPage : Page;
return <Route key={route} path={route} component={component} />;
})}
<Route path="/tutorial/:step?" component={TutorialPage} />
Expand Down
30 changes: 30 additions & 0 deletions src/lib/repl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { options } from 'preact';
import { lazy } from 'preact-iso';

const CodeEditor = lazy(() => import('../components/code-editor'));
const Runner = lazy(() => import('../components/controllers/repl/runner'));

// `preact-iso` doesn't forward refs to lazy-loaded components (should we?)
// so we need to manually do it here to support the tutorial which reads the runner ref
const oldDiff = options.__b;
options.__b = (vnode) => {
if (vnode.type === Runner && vnode.ref) {
vnode.props.ref = vnode.ref;
vnode.ref = null;
}

if (oldDiff) oldDiff(vnode);
};

/**
* @returns {void}
*/
export function preloadRepl() {
CodeEditor.preload();
Runner.preload();
}

export const Repl = {
CodeEditor,
Runner
};
23 changes: 0 additions & 23 deletions src/lib/use-repl.js

This file was deleted.

0 comments on commit 6b99d15

Please sign in to comment.