From 9974311344dd22ab6a5aeae942dba1695cea0d4f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 29 Dec 2023 00:55:14 +0100 Subject: [PATCH] better repl init + a bit of ssr for main repl --- website/src/docs/MiniRepl.jsx | 29 +++++++++++------------------ website/src/pages/index.astro | 2 +- website/src/repl/Header.jsx | 2 +- website/src/repl/Repl.jsx | 32 ++++++++++---------------------- website/src/repl/panel/Panel.jsx | 16 ++++++++++++---- website/src/useClient.mjs | 9 +++++++++ 6 files changed, 44 insertions(+), 46 deletions(-) create mode 100644 website/src/useClient.mjs diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index aab37fd2..5e915641 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -1,4 +1,4 @@ -import { useState, useRef, useCallback, useMemo, useEffect, useLayoutEffect } from 'react'; +import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Icon } from './Icon'; import { silence, getPunchcardPainter, noteToMidi } from '@strudel.cycles/core'; import { transpiler } from '@strudel.cycles/transpiler'; @@ -8,9 +8,7 @@ import { StrudelMirror } from '@strudel/codemirror'; import { prebake } from '../repl/prebake.mjs'; import { loadModules } from '../repl/util.mjs'; import Claviature from '@components/Claviature'; - -// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85 -export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; +import useClient from '@src/useClient.mjs'; let prebaked, modulesLoading; if (typeof window !== 'undefined') { @@ -91,19 +89,7 @@ export function MiniRepl({ const { started, isDirty, error } = replState; const editorRef = useRef(); const containerRef = useRef(); - const [client, setClient] = useState(false); - - useIsomorphicLayoutEffect(() => { - setClient(true); - if (!editorRef.current) { - setTimeout(() => { - init({ code, shouldDraw }); - }); - } - return () => { - editorRef.current?.clear(); - }; - }, []); + const client = useClient(); if (!client) { return
{code}
; @@ -136,7 +122,14 @@ export function MiniRepl({ )}
-
+
{ + if (!editorRef.current) { + containerRef.current = el; + init({ code, shouldDraw }); + } + }} + >
{error &&
{error.message}
}
{shouldShowCanvas && ( diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index 6630ef32..53a522e8 100644 --- a/website/src/pages/index.astro +++ b/website/src/pages/index.astro @@ -9,6 +9,6 @@ import { Repl } from '../repl/Repl'; Strudel REPL - + diff --git a/website/src/repl/Header.jsx b/website/src/repl/Header.jsx index 9af54b12..774d0142 100644 --- a/website/src/repl/Header.jsx +++ b/website/src/repl/Header.jsx @@ -23,7 +23,7 @@ export function Header({ context }) { handleShuffle, handleShare, } = context; - const isEmbedded = embedded || window.location !== window.parent.location; + const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location); const { isZen } = useSettings(); return ( diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 4a350d55..0ab201a1 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -35,19 +35,15 @@ export const ReplContext = createContext(null); const { latestCode } = settingsMap.get(); -initAudioOnFirstClick(); - -const modulesLoading = loadModules(); -const presets = prebake(); - -let drawContext, clearCanvas; +let modulesLoading, presets, drawContext, clearCanvas; if (typeof window !== 'undefined') { + initAudioOnFirstClick(); + modulesLoading = loadModules(); + presets = prebake(); drawContext = getDrawContext(); clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width); } -// const getTime = () => getAudioContext().currentTime; - export function Repl({ embedded = false }) { //const isEmbedded = embedded || window.location !== window.parent.location; const isEmbedded = false; @@ -116,19 +112,6 @@ export function Repl({ embedded = false }) { const { started, isDirty, error, activeCode } = replState; const editorRef = useRef(); const containerRef = useRef(); - const [client, setClient] = useState(false); - useEffect(() => { - setClient(true); - if (!editorRef.current) { - setTimeout(() => { - init({ shouldDraw }); - }); - } - return () => { - editorRef.current?.clear(); - delete editorRef.current; - }; - }, []); // this can be simplified once SettingsTab has been refactored to change codemirrorSettings directly! // this will be the case when the main repl is being replaced @@ -217,7 +200,12 @@ export function Repl({ embedded = false }) {
{ + containerRef.current = el; + if (!editorRef.current) { + init({ shouldDraw }); + } + }} >
{panelPosition === 'right' && !isEmbedded && } diff --git a/website/src/repl/panel/Panel.jsx b/website/src/repl/panel/Panel.jsx index c2dbd443..8d824d26 100644 --- a/website/src/repl/panel/Panel.jsx +++ b/website/src/repl/panel/Panel.jsx @@ -3,7 +3,7 @@ import { logger } from '@strudel.cycles/core'; import useEvent from '@src/useEvent.mjs'; import cx from '@src/cx.mjs'; import { nanoid } from 'nanoid'; -import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'; +import { useCallback, useLayoutEffect, useEffect, useRef, useState } from 'react'; import { setActiveFooter, useSettings } from '../../settings.mjs'; import { ConsoleTab } from './ConsoleTab'; import { FilesTab } from './FilesTab'; @@ -12,21 +12,25 @@ import { SettingsTab } from './SettingsTab'; import { SoundsTab } from './SoundsTab'; import { WelcomeTab } from './WelcomeTab'; import { PatternsTab } from './PatternsTab'; +import useClient from '@src/useClient.mjs'; -const TAURI = window.__TAURI__; +// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85 +export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; + +const TAURI = typeof window !== 'undefined' && window.__TAURI__; export function Panel({ context }) { const footerContent = useRef(); const [log, setLog] = useState([]); const { activeFooter, isZen, panelPosition } = useSettings(); - useLayoutEffect(() => { + useIsomorphicLayoutEffect(() => { if (footerContent.current && activeFooter === 'console') { // scroll log box to bottom when log changes footerContent.current.scrollTop = footerContent.current?.scrollHeight; } }, [log, activeFooter]); - useLayoutEffect(() => { + useIsomorphicLayoutEffect(() => { if (!footerContent.current) { } else if (activeFooter === 'console') { footerContent.current.scrollTop = footerContent.current?.scrollHeight; @@ -80,6 +84,10 @@ export function Panel({ context }) { right: cx('max-w-full flex-grow-0 flex-none overflow-hidden', isActive ? 'w-[600px] h-full' : 'absolute right-0'), bottom: cx('relative', isActive ? 'h-[360px] min-h-[360px]' : ''), }; + const client = useClient(); + if (!client) { + return null; + } return (