diff --git a/CHANGELOG.md b/CHANGELOG.md index 447ca81ce..c6f649d54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.26](https://github.com/codesandbox/sandpack/compare/v2.0.25...v2.0.26) (2023-03-02) + + +### Bug Fixes + +* **preview:** add stdout for long process ([#792](https://github.com/codesandbox/sandpack/issues/792)) ([4da4d99](https://github.com/codesandbox/sandpack/commit/4da4d997b54beb408d3ec2f15d027090d05879c7)) + + + + + ## [2.0.25](https://github.com/codesandbox/sandpack/compare/v2.0.24...v2.0.25) (2023-03-02) diff --git a/lerna.json b/lerna.json index 42f7dee47..7ecb8c35b 100644 --- a/lerna.json +++ b/lerna.json @@ -21,5 +21,5 @@ "message": "chore: [skip ci] bump packages" } }, - "version": "2.0.25" + "version": "2.0.26" } diff --git a/package.json b/package.json index 6db0e8787..63bb32784 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "test": "turbo run test --filter=\"@codesandbox/**\"", "build": "turbo run build --filter=\"@codesandbox/**\" --filter=\"codesandbox-theme-docs\"", "build:client": "turbo run build --filter=\"@codesandbox/sandpack-client\"", + "build:react": "turbo run build --filter=\"@codesandbox/sandpack-react\"", "typecheck": "turbo run typecheck --filter=\"@codesandbox/**\"", "lint": "turbo run lint --filter=\"@codesandbox/**\"", "format": "turbo run format --filter=\"@codesandbox/**\"", diff --git a/sandpack-client/CHANGELOG.md b/sandpack-client/CHANGELOG.md index fa9f3272c..13aa40dca 100644 --- a/sandpack-client/CHANGELOG.md +++ b/sandpack-client/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.26](https://github.com/codesandbox/sandpack/compare/v2.0.25...v2.0.26) (2023-03-02) + + +### Bug Fixes + +* **preview:** add stdout for long process ([#792](https://github.com/codesandbox/sandpack/issues/792)) ([4da4d99](https://github.com/codesandbox/sandpack/commit/4da4d997b54beb408d3ec2f15d027090d05879c7)) + + + + + ## [2.0.25](https://github.com/codesandbox/sandpack/compare/v2.0.24...v2.0.25) (2023-03-02) diff --git a/sandpack-client/package.json b/sandpack-client/package.json index 05a84d05c..38861c4ee 100644 --- a/sandpack-client/package.json +++ b/sandpack-client/package.json @@ -1,6 +1,6 @@ { "name": "@codesandbox/sandpack-client", - "version": "2.0.25", + "version": "2.0.26", "description": "", "keywords": [], "repository": { diff --git a/sandpack-client/src/clients/node/iframe.utils.ts b/sandpack-client/src/clients/node/iframe.utils.ts index 7e010ad3f..5d5c456dc 100644 --- a/sandpack-client/src/clients/node/iframe.utils.ts +++ b/sandpack-client/src/clients/node/iframe.utils.ts @@ -34,8 +34,7 @@ export async function loadPreviewIframe( return; } - iframe.contentWindow?.location.replace("about:blank"); - iframe.contentWindow?.location.replace(url!); + iframe.setAttribute("src", url); timeout = setTimeout(() => { triesToSetUrl(); diff --git a/sandpack-client/src/clients/node/index.ts b/sandpack-client/src/clients/node/index.ts index ee0bbe09f..852280cfd 100644 --- a/sandpack-client/src/clients/node/index.ts +++ b/sandpack-client/src/clients/node/index.ts @@ -353,7 +353,7 @@ export class SandpackNode extends SandpackClient { // 2. Exit shell await this.emulatorShellProcess.kill(); - this.iframe?.contentWindow?.location.replace("about:blank"); + this.iframe?.removeAttribute("attr"); // 3. new Nodebox instance this.createNodebox(); @@ -431,6 +431,7 @@ export class SandpackNode extends SandpackClient { } public destroy(): void { + this.emulatorIframe.remove(); this.emitter.cleanup(); } } diff --git a/sandpack-react/CHANGELOG.md b/sandpack-react/CHANGELOG.md index 67dc55baf..be5981c09 100644 --- a/sandpack-react/CHANGELOG.md +++ b/sandpack-react/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.26](https://github.com/codesandbox/sandpack/compare/v2.0.25...v2.0.26) (2023-03-02) + + +### Bug Fixes + +* **preview:** add stdout for long process ([#792](https://github.com/codesandbox/sandpack/issues/792)) ([4da4d99](https://github.com/codesandbox/sandpack/commit/4da4d997b54beb408d3ec2f15d027090d05879c7)) + + + + + ## [2.0.25](https://github.com/codesandbox/sandpack/compare/v2.0.24...v2.0.25) (2023-03-02) diff --git a/sandpack-react/package.json b/sandpack-react/package.json index 43fc77a59..f20517a77 100644 --- a/sandpack-react/package.json +++ b/sandpack-react/package.json @@ -1,6 +1,6 @@ { "name": "@codesandbox/sandpack-react", - "version": "2.0.25", + "version": "2.0.26", "description": "", "keywords": [], "repository": { @@ -44,7 +44,7 @@ "@codemirror/language": "^6.3.2", "@codemirror/state": "^6.2.0", "@codemirror/view": "^6.7.1", - "@codesandbox/sandpack-client": "^2.0.25", + "@codesandbox/sandpack-client": "^2.0.26", "@lezer/highlight": "^1.1.3", "@react-hook/intersection-observer": "^3.1.1", "@stitches/core": "^1.2.6", diff --git a/sandpack-react/src/components/Console/SandpackConsole.tsx b/sandpack-react/src/components/Console/SandpackConsole.tsx index 359069123..54d856811 100644 --- a/sandpack-react/src/components/Console/SandpackConsole.tsx +++ b/sandpack-react/src/components/Console/SandpackConsole.tsx @@ -4,7 +4,6 @@ import { useSandpack, useSandpackShell } from "../.."; import { useSandpackShellStdout } from "../../hooks/useSandpackShellStdout"; import { css, THEME_PREFIX } from "../../styles"; import { classNames } from "../../utils/classNames"; -import { PreviewProgress } from "../Preview/PreviewProgress"; import { SandpackStack } from "../common"; import { RoundedButton } from "../common/RoundedButton"; import { CleanIcon, RestartIcon } from "../icons"; @@ -106,8 +105,6 @@ export const SandpackConsole = React.forwardRef< )} {...props} > - {showSetupProgress && } - {(showHeader || isNodeEnvironment) && (
- - {showSandpackErrorOverlay && } {children} diff --git a/sandpack-react/src/components/common/LoadingOverlay.tsx b/sandpack-react/src/components/common/LoadingOverlay.tsx index ffe9af094..22ea98969 100644 --- a/sandpack-react/src/components/common/LoadingOverlay.tsx +++ b/sandpack-react/src/components/common/LoadingOverlay.tsx @@ -6,16 +6,20 @@ import { useLoadingOverlayState, FADE_ANIMATION_DURATION, } from "../../hooks/useLoadingOverlayState"; +import { usePreviewProgress } from "../../hooks/usePreviewProgress"; +import { useSandpackShellStdout } from "../../hooks/useSandpackShellStdout"; import { css, THEME_PREFIX } from "../../styles"; import { absoluteClassName, buttonClassName, errorBundlerClassName, errorMessageClassName, + fadeIn, iconStandaloneClassName, roundedButtonClassName, } from "../../styles/shared"; import { classNames } from "../../utils/classNames"; +import { StdoutList } from "../Console/StdoutList"; import { RestartIcon } from "../icons"; import { Loading } from "./Loading"; @@ -45,11 +49,30 @@ export const LoadingOverlay = ({ ...props }: LoadingOverlayProps & React.HTMLAttributes): JSX.Element | null => { - const loadingOverlayState = useLoadingOverlayState(clientId, loading); const c = useClasser(THEME_PREFIX); const { sandpack: { runSandpack, environment }, } = useSandpack(); + const [shouldShowStdout, setShouldShowStdout] = React.useState(false); + + const loadingOverlayState = useLoadingOverlayState(clientId, loading); + const progressMessage = usePreviewProgress(); + const { logs: stdoutData } = useSandpackShellStdout({}); + + React.useEffect(() => { + let timer: NodeJS.Timer; + if (progressMessage?.includes("Running")) { + timer = setTimeout(() => { + setShouldShowStdout(true); + }, 3_000); + } + + return () => { + if (timer) { + clearTimeout(timer); + } + }; + }, [progressMessage]); if (loadingOverlayState === "HIDDEN") { return null; @@ -118,21 +141,62 @@ export const LoadingOverlay = ({ loadingOverlayState === "LOADING" || loadingOverlayState === "PRE_FADING"; return ( -
+
+ {shouldShowStdout && ( +
+ +
+ )} + +
+ + {progressMessage && ( +
+

{progressMessage}

+
)} - style={{ - ...style, - opacity: stillLoading ? 1 : 0, - transition: `opacity ${FADE_ANIMATION_DURATION}ms ease-out`, - }} - {...props} - > - -
+ ); }; + +const stdoutPreview = css({ + position: "absolute", + left: 0, + right: 0, + bottom: "$space$8", + overflow: "auto", + opacity: 0.5, + overflowX: "hidden", +}); + +const wrapperClassName = css({ + position: "absolute", + left: "$space$5", + bottom: "$space$4", + zIndex: "$top", + color: "$colors$clickable", + animation: `${fadeIn} 150ms ease`, + fontFamily: "$font$mono", + fontSize: ".8em", + width: "75%", + p: { + whiteSpace: "nowrap", + margin: 0, + textOverflow: "ellipsis", + overflow: "hidden", + }, +}); diff --git a/sandpack-react/src/contexts/utils/useClient.ts b/sandpack-react/src/contexts/utils/useClient.ts index 647590807..95f505015 100644 --- a/sandpack-react/src/contexts/utils/useClient.ts +++ b/sandpack-react/src/contexts/utils/useClient.ts @@ -23,7 +23,7 @@ import { generateRandomId } from "../../utils/stringUtils"; import type { FilesState } from "./useFiles"; type SandpackClientType = InstanceType; -const BUNDLER_TIMEOUT = 30000; // 30 seconds timeout for the bundler to respond. +const BUNDLER_TIMEOUT = 40_000; interface SandpackConfigState { reactDevTools?: ReactDevToolsMode; @@ -85,7 +85,6 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { */ const intersectionObserver = useRef(null); const lazyAnchorRef = useRef(null); - const initializeSandpackIframeHook = useRef(null); const preregisteredIframes = useRef>({}); const clients = useRef>({}); const timeoutHook = useRef(null); @@ -119,6 +118,7 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { } timeoutHook.current = setTimeout(() => { + unregisterAllClients(); setState((prev) => ({ ...prev, status: "timeout" })); }, timeOut); @@ -235,10 +235,7 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { // If any component registerd a lazy anchor ref component, use that for the intersection observer intersectionObserver.current = new IntersectionObserver((entries) => { if (entries.some((entry) => entry.isIntersecting)) { - // Delay a cycle so all hooks register the refs for the sub-components (open in csb, loading, error overlay) - initializeSandpackIframeHook.current = setTimeout(() => { - runSandpack(); - }, 50); + runSandpack(); if (lazyAnchorRef.current) { intersectionObserver.current?.unobserve(lazyAnchorRef.current); @@ -250,15 +247,8 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { } else if (lazyAnchorRef.current && state.initMode === "user-visible") { intersectionObserver.current = new IntersectionObserver((entries) => { if (entries.some((entry) => entry.isIntersecting)) { - // Delay a cycle so all hooks register the refs for the sub-components (open in csb, loading, error overlay) - initializeSandpackIframeHook.current = setTimeout(() => { - runSandpack(); - }, 50); + runSandpack(); } else { - if (initializeSandpackIframeHook.current) { - clearTimeout(initializeSandpackIframeHook.current); - } - Object.keys(clients.current).map(unregisterBundler); unregisterAllClients(); } @@ -266,11 +256,7 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { intersectionObserver.current.observe(lazyAnchorRef.current); } else { - // else run the sandpack on mount, with a slight delay to allow all subcomponents to mount/register components - initializeSandpackIframeHook.current = setTimeout( - () => runSandpack(), - 50 - ); + runSandpack(); } }, [ options?.autorun, @@ -323,13 +309,13 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { }; const handleMessage = (msg: SandpackMessage): void => { - if (timeoutHook.current) { - clearTimeout(timeoutHook.current); - } - if (msg.type === "state") { setState((prev) => ({ ...prev, bundlerState: msg.state })); } else if (msg.type === "done" && !msg.compilatonError) { + if (timeoutHook.current) { + clearTimeout(timeoutHook.current); + } + setState((prev) => ({ ...prev, error: null })); } else if (msg.type === "action" && msg.action === "show-error") { setState((prev) => ({ ...prev, error: extractErrorDetails(msg) })); @@ -524,10 +510,6 @@ export const useClient: UseClient = ({ options, customSetup }, filesState) => { clearTimeout(debounceHook.current); } - if (initializeSandpackIframeHook.current) { - clearTimeout(initializeSandpackIframeHook.current); - } - if (intersectionObserver.current) { intersectionObserver.current.disconnect(); } diff --git a/sandpack-react/src/components/Preview/PreviewProgress.tsx b/sandpack-react/src/hooks/usePreviewProgress.ts similarity index 70% rename from sandpack-react/src/components/Preview/PreviewProgress.tsx rename to sandpack-react/src/hooks/usePreviewProgress.ts index 1e17e1881..eb7d92597 100644 --- a/sandpack-react/src/components/Preview/PreviewProgress.tsx +++ b/sandpack-react/src/hooks/usePreviewProgress.ts @@ -1,27 +1,7 @@ import type { WorkerStatusUpdate } from "@codesandbox/nodebox"; import * as React from "react"; -import { useSandpack } from "../.."; -import { css } from "../../styles"; -import { fadeIn } from "../../styles/shared"; - -const wrapperClassName = css({ - position: "absolute", - left: "$space$5", - bottom: "$space$4", - zIndex: "$top", - color: "$colors$clickable", - animation: `${fadeIn} 150ms ease`, - fontFamily: "$font$mono", - fontSize: ".8em", - width: "75%", - p: { - whiteSpace: "nowrap", - margin: 0, - textOverflow: "ellipsis", - overflow: "hidden", - }, -}); +import { useSandpack } from ".."; const mapProgressMessage = ( originalMessage: WorkerStatusUpdate & { command?: string }, @@ -44,14 +24,13 @@ const mapProgressMessage = ( } }; -export const PreviewProgress: React.FC<{ - clientId?: string; -}> = ({ clientId }) => { +export const usePreviewProgress = () => { const [isReady, setIsReady] = React.useState(false); const [totalDependencies, setTotalDependencies] = React.useState(); const [loadingMessage, setLoadingMessage] = React.useState( null ); + const { listen } = useSandpack(); React.useEffect(() => { @@ -78,7 +57,7 @@ export const PreviewProgress: React.FC<{ setIsReady(true); clearTimeout(timer); } - }, clientId); + }); return (): void => { if (timer) { @@ -86,13 +65,7 @@ export const PreviewProgress: React.FC<{ } unsubscribe(); }; - }, [clientId, isReady, totalDependencies]); + }, [isReady, totalDependencies]); - if (!loadingMessage) return null; - - return ( -
-

{loadingMessage}

-
- ); + return loadingMessage; }; diff --git a/sandpack-react/src/hooks/useSandpackShellStdout.ts b/sandpack-react/src/hooks/useSandpackShellStdout.ts index a716fcbc1..f3531a764 100644 --- a/sandpack-react/src/hooks/useSandpackShellStdout.ts +++ b/sandpack-react/src/hooks/useSandpackShellStdout.ts @@ -13,7 +13,7 @@ export const useSandpackShellStdout = ({ }: { clientId?: string; maxMessageCount?: number; - resetOnPreviewRestart: boolean; + resetOnPreviewRestart?: boolean; }): { logs: Array<{ id: string; data: string }>; reset: () => void; diff --git a/website/docs/src/components/SelectorList.jsx b/website/docs/src/components/SelectorList.jsx index 278b05a09..aecac9b43 100644 --- a/website/docs/src/components/SelectorList.jsx +++ b/website/docs/src/components/SelectorList.jsx @@ -10,12 +10,7 @@ export const SelectorListButton = ({ children, onClick, active }) => { } nx-bg-black/[.03] dark:nx-bg-gray-50/10`; return ( - ); diff --git a/website/docs/src/components/ThemesList.jsx b/website/docs/src/components/ThemesList.jsx index 47ec6028c..0b8c3f2fe 100644 --- a/website/docs/src/components/ThemesList.jsx +++ b/website/docs/src/components/ThemesList.jsx @@ -4,16 +4,13 @@ import { SelectorList, SelectorListButton } from "./SelectorList"; import styles from "./SelectorList.module.css"; export const ThemesList = ({ current, setCurrent, list }) => { - return ( - - {["auto", "dark", "light", ...Object.keys(themes)].map((themeName) => { - if ( - typeof themeName === "object" && - !themes[themeName]?.colors?.surface1 - ) { - return null; - } + const data = ["auto", "dark", "light", ...Object.keys(themes)].filter( + (e) => e !== "default" + ); + return ( + + {data.map((themeName) => { return ( { ) : themeName === "auto" ? (