From 335bd8372cd005d9abcc556088d76d2b988b5ce6 Mon Sep 17 00:00:00 2001 From: Chris Laplante Date: Sat, 11 May 2024 16:41:09 -0400 Subject: [PATCH] use a hook instead of a component to load Pyodide --- src/components/App.tsx | 31 ++++++++++++++++--------------- src/components/PyodideLoader.tsx | 30 ------------------------------ src/usePyodide.ts | 27 +++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 45 deletions(-) delete mode 100644 src/components/PyodideLoader.tsx create mode 100644 src/usePyodide.ts diff --git a/src/components/App.tsx b/src/components/App.tsx index 4f612b7..d7ebca3 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,11 +1,11 @@ import React, {useEffect, useState} from "react"; -import { MantineProvider, createTheme, MantineColorsTuple } from '@mantine/core'; +import {createTheme, MantineColorsTuple, MantineProvider} from '@mantine/core'; import FetchWithProgress from "./FetchWithProgress"; -import PyodideLoader from "./PyodideLoader"; -import pyodide from "pyodide"; import AceEditor from "react-ace"; +import "ace-builds/src-noconflict/mode-jsx"; +import {usePyodide} from "../usePyodide"; const myColor: MantineColorsTuple = [ '#e4f8ff', @@ -28,22 +28,24 @@ const theme = createTheme({ const Inner: React.FC = () => { const [data, setData] = useState(null); - const [pyodideModule, setPyodideModule] = useState(null); + + const pyodide = usePyodide(); + const [ran, setRan] = useState(false); useEffect(() => { const go = async () => { - if (data && pyodideModule && !ran) { + if (data && !ran) { setRan(true); console.warn("LOADING SQLITE"); - await pyodideModule.loadPackage("sqlite3"); + await pyodide.loadPackage("sqlite3"); console.warn("LOADED!"); - pyodideModule.unpackArchive(data, "zip", { + pyodide.unpackArchive(data, "zip", { extractDir: "bb" }); - pyodideModule.runPython(` + pyodide.runPython(` import os.path import sys from importlib.abc import Loader, MetaPathFinder @@ -153,16 +155,16 @@ sys.meta_path.append(BuiltinImporterShim()) print(sys.meta_path) `) - const file = pyodideModule.FS.readdir("./bb"); + const file = pyodide.FS.readdir("./bb"); console.log(file); - pyodideModule.runPython(` + pyodide.runPython(` import sys sys.path.insert(0, "./bb/bitbake-2.8.0/lib/") from bb.data_smart import DataSmart `) - const DataSmart = pyodideModule.globals.get('DataSmart'); + const DataSmart = pyodide.globals.get('DataSmart'); const d = DataSmart(); d.setVar("A", "B"); @@ -175,16 +177,15 @@ print(sys.meta_path) DataSmart.destroy(); } else { - console.warn(`data = ${!!data}, p = ${!!pyodideModule}`); + console.warn(`data = ${!!data}, p = ${!!pyodide}`); } } go(); - }, [data, pyodideModule, ran, setRan]); + }, [data, pyodide, ran, setRan]); return <> - ; } @@ -197,7 +198,7 @@ export const App: React.FC = () => { mode="java" theme="github" name="UNIQUE_ID_OF_DIV" - editorProps={{ $blockScrolling: true }} + editorProps={{$blockScrolling: true}} /> diff --git a/src/components/PyodideLoader.tsx b/src/components/PyodideLoader.tsx deleted file mode 100644 index 72f09dd..0000000 --- a/src/components/PyodideLoader.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useEffect } from 'react'; - -import pyodide from "pyodide"; - -interface Props { - pyodide: pyodide | null; - setPyodide: (value: pyodide) => void; -} - -const PyodideLoader: React.FC = (props: Props) => { - useEffect(() => { - async function loadPyodide() { - // noinspection TypeScriptCheckImport - const { loadPyodide: loadPyodideModule } = await import("https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.mjs"); - const pyodideInstance: pyodide = await loadPyodideModule(); - console.log("set pyodide"); - props.setPyodide(pyodideInstance); - } - - loadPyodide(); - }); - - return ( -
- {props.pyodide ? 'Pyodide Loaded!' : 'Loading Pyodide...'} -
- ); -}; - -export default PyodideLoader; diff --git a/src/usePyodide.ts b/src/usePyodide.ts new file mode 100644 index 0000000..cc972f0 --- /dev/null +++ b/src/usePyodide.ts @@ -0,0 +1,27 @@ +import React, { useEffect, useState } from 'react'; + +export const usePyodide = () => { + const [pyodide, setPyodide] = useState(null); + + useEffect(() => { + let isActive = true; + + const loadPyodide = async () => { + if (!window.pyodide) { + const { loadPyodide: loadPyodideModule } = await import("https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.mjs"); + window.pyodide = await loadPyodideModule(); + } + if (isActive) { + setPyodide(window.pyodide); + } + }; + + loadPyodide(); + + return () => { + isActive = false; + }; + }, []); + + return pyodide; +};