From 5a07c614d5241b68ca13ecaf19aa8eb7ba773bf4 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 6 Apr 2022 12:36:51 +0900 Subject: [PATCH 01/20] init esbuild pkg --- .../editor-esbuild/fetch.plugin.ts | 78 +++++++++++ editor-packages/editor-esbuild/index.ts | 128 ++++++++++++++++++ editor-packages/editor-esbuild/package.json | 14 ++ .../editor-esbuild/unpkg-path.plugin.ts | 36 +++++ .../workers}/fetch-types.worker.js | 0 .../monaco-utils/register-typings.ts | 63 --------- .../code-editor/monaco-utils/register.ts | 8 -- yarn.lock | 14 +- 8 files changed, 269 insertions(+), 72 deletions(-) create mode 100644 editor-packages/editor-esbuild/fetch.plugin.ts create mode 100644 editor-packages/editor-esbuild/index.ts create mode 100644 editor-packages/editor-esbuild/package.json create mode 100644 editor-packages/editor-esbuild/unpkg-path.plugin.ts rename {editor/workers/fetch-types => editor-packages/editor-esbuild/workers}/fetch-types.worker.js (100%) delete mode 100644 editor/components/code-editor/monaco-utils/register-typings.ts diff --git a/editor-packages/editor-esbuild/fetch.plugin.ts b/editor-packages/editor-esbuild/fetch.plugin.ts new file mode 100644 index 00000000..7969f68b --- /dev/null +++ b/editor-packages/editor-esbuild/fetch.plugin.ts @@ -0,0 +1,78 @@ +import { OnLoadResult, PluginBuild } from "esbuild-wasm"; +import axios from "axios"; +import localforage from "localforage"; +import { normalizeCss } from "."; + +const fileCache = localforage.createInstance({ + name: "filecache", +}); + +export const fetchPlugin = ( + inputCode: string, + lang: OnLoadResult["loader"] +) => ({ + name: "fetch-plugin", + + setup(build: PluginBuild) { + build.onLoad({ filter: /^index\.js$/ }, () => { + return { + loader: lang, + contents: inputCode, + }; + }); + + build.onLoad({ filter: /.*/ }, async (args: any) => { + /** + * Check if module is already in filecache + * if yes? return it immediately + * + * if not, fetch it from unpkg and cache it + * and return the result + */ + const cachedResult = await fileCache.getItem(args.path); + + if (cachedResult) { + return cachedResult; + } + + return null; + }); + + build.onLoad({ filter: /.css$/ }, async (args: any) => { + const { data, request } = await axios.get(args.path); + + const contents = normalizeCss(data); + + const result: OnLoadResult = { + loader: "jsx", + contents, + resolveDir: new URL("./", request.responseURL).pathname, + }; + + await fileCache.setItem(args.path, result); + + return result; + }); + + build.onLoad({ filter: /.*/ }, async (args: any) => { + const { data, request } = await axios.get(args.path); + + const result: OnLoadResult = { + loader: "jsx", + contents: data, + resolveDir: new URL("./", request.responseURL).pathname, + }; + + await fileCache.setItem(args.path, result); + + return result; + }); + }, +}); + +// const libSource = ReactTypes.toString() + +// const libUri = "ts:filename/facts.d.ts"; +// monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri); + +// monaco.editor.createModel(libSource, "typescript", monaco.Uri.parse(libUri)); diff --git a/editor-packages/editor-esbuild/index.ts b/editor-packages/editor-esbuild/index.ts new file mode 100644 index 00000000..1dfe4c21 --- /dev/null +++ b/editor-packages/editor-esbuild/index.ts @@ -0,0 +1,128 @@ +import { Monaco } from "@monaco-editor/react"; +import { nanoid } from "nanoid"; +import { build, initialize, Loader } from "esbuild-wasm"; +import { fetchPlugin } from "./fetch.plugin"; +import { unpkgPathPlugin } from "./unpkg-path.plugin"; +// import store from "../../redux"; +// import { INIT_BUNDLER } from "../../redux/actions/bundler.actions"; +// import { PRINT_CONSOLE } from "../../redux/actions/editor.actions"; + +declare const window: { + monaco: Monaco; +}; + +let serviceLoaded: boolean | null = null; + +const bundler = async (rawCode: string, lang: Loader) => { + if (!serviceLoaded) { + await initialize({ + wasmURL: "https://unpkg.com/esbuild-wasm@0.13.14/esbuild.wasm", + worker: true, + }); + serviceLoaded = true; + // store.dispatch(INIT_BUNDLER()); + // store.dispatch( + // PRINT_CONSOLE({ + // method: "info", + // data: ["Bundler initialized...Happy coding ❤️"], + // }) + // ); + } + + try { + const result = await build({ + entryPoints: ["index.js"], + bundle: true, + write: false, + metafile: true, + legalComments: "none", + plugins: [unpkgPathPlugin(), fetchPlugin(rawCode, lang)], + define: { + "process.env.NODE_ENV": `"production"`, + global: "window", + }, + }); + + const imports = result.metafile?.inputs["a:index.js"].imports + .map((el) => el.path.replace("a:https://unpkg.com/", "")) + .filter((e) => !e.includes("/")); + + loadTypes(imports); + + return { code: result.outputFiles[0].text, err: null }; + } catch (error: any) { + console.error("error: ", error); + return { + code: "", + err: { method: "error", data: [error.message], id: nanoid() }, + }; + } +}; + +export const normalizeCss = (data: string) => { + /** + * Function to remove any new lines, quotes from imported css packages. + */ + const escaped = data + .replace(/\n/g, "") + .replace(/"/g, '\\"') + .replace(/'/g, "\\'"); + return `const style = document.createElement('style') + style.innerText = '${escaped}'; + document.head.appendChild(style)`; +}; + +export default bundler; + +let typesWorker; + +const loadTypes = (types) => { + const disposables: any = []; + const monaco = window && window.monaco; + + const dependencies = + types.map((e) => ({ name: e, version: "@latest" })) || []; + + if (!typesWorker) { + typesWorker = new Worker( + new URL("./workers/fetch-types.worker.js", import.meta.url) + ); + } + + dependencies.forEach((dep) => { + typesWorker.postMessage({ + name: dep.name, + version: dep.version, + }); + }); + + typesWorker.addEventListener("message", (event) => { + // name, + // version, + // typings: result, + const key = `node_modules/${event.data.name}/index.d.ts`; + const source = event.data.typings[key]; + + // const path = `${MONACO_LIB_PREFIX}${event.data.name}`; + const libUri = `file:///node_modules/@types/${event.data.name}/index.d.ts`; + + disposables.push( + monaco.languages.typescript.javascriptDefaults.addExtraLib(source, libUri) + ); + disposables.push( + monaco.languages.typescript.typescriptDefaults.addExtraLib(source, libUri) + ); + + // When resolving definitions and references, the editor will try to use created models. + // Creating a model for the library allows "peek definition/references" commands to work with the library. + }); + + return { + dispose() { + disposables.forEach((d) => d.dispose()); + if (typesWorker) { + typesWorker.terminate(); + } + }, + }; +}; diff --git a/editor-packages/editor-esbuild/package.json b/editor-packages/editor-esbuild/package.json new file mode 100644 index 00000000..12af2d4e --- /dev/null +++ b/editor-packages/editor-esbuild/package.json @@ -0,0 +1,14 @@ +{ + "name": "@code-editor/esbuild", + "version": "0.0.0", + "private": false, + "dependencies": { + "esbuild-wasm": "^0.14.31", + "localforage": "^1.10.0" + }, + "peerDependencies": { + "@monaco-editor/react": "^4.4.1", + "axios": "^0.26.1", + "nanoid": "^3.3.2" + } +} diff --git a/editor-packages/editor-esbuild/unpkg-path.plugin.ts b/editor-packages/editor-esbuild/unpkg-path.plugin.ts new file mode 100644 index 00000000..dbfbcbe7 --- /dev/null +++ b/editor-packages/editor-esbuild/unpkg-path.plugin.ts @@ -0,0 +1,36 @@ +import { PluginBuild } from "esbuild-wasm"; + +const unpkg_path = "https://unpkg.com"; + +export const unpkgPathPlugin = () => ({ + name: "unpkg-path-plugin", + setup(build: PluginBuild) { + /** + * Resolve the entry file eg. `index.js` + */ + build.onResolve({ filter: /^index\.js$/ }, (args: any) => { + return { path: args.path, namespace: "a" }; + }); + + /** + * Resolve relative modules imports + */ + build.onResolve({ filter: /^\.+\// }, (args: any) => { + const url = new URL(args.path, unpkg_path + args.resolveDir + "/").href; + return { + namespace: "a", + path: url, + }; + }); + + /** + * Resolve main module files + */ + build.onResolve({ filter: /.*/ }, async (args: any) => { + return { + namespace: "a", + path: new URL(args.path, unpkg_path + "/").href, + }; + }); + }, +}); diff --git a/editor/workers/fetch-types/fetch-types.worker.js b/editor-packages/editor-esbuild/workers/fetch-types.worker.js similarity index 100% rename from editor/workers/fetch-types/fetch-types.worker.js rename to editor-packages/editor-esbuild/workers/fetch-types.worker.js diff --git a/editor/components/code-editor/monaco-utils/register-typings.ts b/editor/components/code-editor/monaco-utils/register-typings.ts deleted file mode 100644 index 22cd7d45..00000000 --- a/editor/components/code-editor/monaco-utils/register-typings.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Monaco } from "@monaco-editor/react"; - -export function registerTypesWorker(monaco: Monaco) { - const disposables: any = []; - let typesWorker; - - const dependencies = { - react: "@latest", - "react-dom": "@latest", - axios: "@latest", - }; - - if (!typesWorker) { - typesWorker = new Worker( - new URL( - "../../../workers/fetch-types/fetch-types.worker.js", - import.meta.url - ) - ); - } - - Object.keys(dependencies).forEach((name) => { - typesWorker.postMessage({ - name, - version: dependencies[name], - }); - }); - - const createModule = (names) => { - const temp = names.map((el) => `export * from './${el}'`); - return temp.join("\n"); - }; - - typesWorker.addEventListener("message", (event) => { - // name, - // version, - // typings: result, - const key = `node_modules/${event.data.name}/index.d.ts`; - const source = event.data.typings[key]; - - // const path = `${MONACO_LIB_PREFIX}${event.data.name}`; - const libUri = `file:///node_modules/@types/${event.data.name}/index.d.ts`; - - disposables.push( - monaco.languages.typescript.javascriptDefaults.addExtraLib(source, libUri) - ); - disposables.push( - monaco.languages.typescript.typescriptDefaults.addExtraLib(source, libUri) - ); - - // When resolving definitions and references, the editor will try to use created models. - // Creating a model for the library allows "peek definition/references" commands to work with the library. - }); - - return { - dispose() { - disposables.forEach((d) => d.dispose()); - if (typesWorker) { - typesWorker.terminate(); - } - }, - }; -} diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts index 7123df48..63eadf3e 100644 --- a/editor/components/code-editor/monaco-utils/register.ts +++ b/editor/components/code-editor/monaco-utils/register.ts @@ -2,7 +2,6 @@ import * as monaco from "monaco-editor"; import { Monaco, OnMount } from "@monaco-editor/react"; import { registerDocumentPrettier } from "./register-prettier"; import { registerJsxHighlighter } from "./register-jsx"; -import { registerTypesWorker } from "./register-typings"; type CompilerOptions = monaco.languages.typescript.CompilerOptions; @@ -13,13 +12,6 @@ export const initEditor: OnMount = (editor, monaco) => { export const initMonaco = (monaco: Monaco) => { baseConfigure(monaco); - - const { dispose } = registerTypesWorker(monaco); - - // Dispose all disposables and terminate all workers - return () => { - dispose(); - }; }; const baseConfigure = (monaco: Monaco) => { diff --git a/yarn.lock b/yarn.lock index f53b4087..33b7727e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9025,6 +9025,11 @@ es6-shim@^0.35.5: resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" integrity sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA== +esbuild-wasm@^0.14.31: + version "0.14.31" + resolved "https://registry.yarnpkg.com/esbuild-wasm/-/esbuild-wasm-0.14.31.tgz#9827a10377369182833479fe2c6747dee6b612dc" + integrity sha512-1TBBAUa1WZHggxVYBFfwafolLimEunkcKmvNJ+sOaroabmq5And/CcXDy2LJKnUQyEF0sI/xhnMW9eESKQkZmg== + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -12242,6 +12247,13 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +localforage@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -12874,7 +12886,7 @@ nanoid@^2.1.0: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== -nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1: +nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1, nanoid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== From 68c22a51ecda9a6075d3cb23db9aabfa7a5bf0b2 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 6 Apr 2022 14:33:03 +0900 Subject: [PATCH 02/20] yarn --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 33b7727e..994dd684 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12886,7 +12886,7 @@ nanoid@^2.1.0: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== -nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1, nanoid@^3.3.2: +nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== From 2b50ccb1a42d5f1084039a5c7b43783bccaee95c Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 6 Apr 2022 17:02:08 +0900 Subject: [PATCH 03/20] rename pkg, add dev sandbox page --- .../editor-services-dart/package.json | 6 + .../fetch.plugin.ts | 0 .../index.ts | 2 +- .../package.json | 4 +- .../unpkg-path.plugin.ts | 0 .../workers/fetch-types.worker.js | 0 .../package.json | 9 + .../editor-services-prettier/package.json | 9 + .../app-runner/vanilla-app-runner.tsx | 69 +++--- editor/components/code-editor/code-editor.tsx | 1 + editor/pages/_development/sandbox/index.tsx | 231 ++++++++++++++++++ 11 files changed, 296 insertions(+), 35 deletions(-) create mode 100644 editor-packages/editor-services-dart/package.json rename editor-packages/{editor-esbuild => editor-services-esbuild}/fetch.plugin.ts (100%) rename editor-packages/{editor-esbuild => editor-services-esbuild}/index.ts (98%) rename editor-packages/{editor-esbuild => editor-services-esbuild}/package.json (84%) rename editor-packages/{editor-esbuild => editor-services-esbuild}/unpkg-path.plugin.ts (100%) rename editor-packages/{editor-esbuild => editor-services-esbuild}/workers/fetch-types.worker.js (100%) create mode 100644 editor-packages/editor-services-jsx-syntax-highlight/package.json create mode 100644 editor-packages/editor-services-prettier/package.json create mode 100644 editor/pages/_development/sandbox/index.tsx diff --git a/editor-packages/editor-services-dart/package.json b/editor-packages/editor-services-dart/package.json new file mode 100644 index 00000000..f1d7a29f --- /dev/null +++ b/editor-packages/editor-services-dart/package.json @@ -0,0 +1,6 @@ +{ + "name": "@code-editor/dart-services", + "description": "dart build services for flutter framework", + "version": "0.0.0", + "private": false +} \ No newline at end of file diff --git a/editor-packages/editor-esbuild/fetch.plugin.ts b/editor-packages/editor-services-esbuild/fetch.plugin.ts similarity index 100% rename from editor-packages/editor-esbuild/fetch.plugin.ts rename to editor-packages/editor-services-esbuild/fetch.plugin.ts diff --git a/editor-packages/editor-esbuild/index.ts b/editor-packages/editor-services-esbuild/index.ts similarity index 98% rename from editor-packages/editor-esbuild/index.ts rename to editor-packages/editor-services-esbuild/index.ts index 1dfe4c21..89d2b4c0 100644 --- a/editor-packages/editor-esbuild/index.ts +++ b/editor-packages/editor-services-esbuild/index.ts @@ -16,7 +16,7 @@ let serviceLoaded: boolean | null = null; const bundler = async (rawCode: string, lang: Loader) => { if (!serviceLoaded) { await initialize({ - wasmURL: "https://unpkg.com/esbuild-wasm@0.13.14/esbuild.wasm", + wasmURL: "https://unpkg.com/esbuild-wasm@0.14.31/esbuild.wasm", worker: true, }); serviceLoaded = true; diff --git a/editor-packages/editor-esbuild/package.json b/editor-packages/editor-services-esbuild/package.json similarity index 84% rename from editor-packages/editor-esbuild/package.json rename to editor-packages/editor-services-esbuild/package.json index 12af2d4e..e8f5ac42 100644 --- a/editor-packages/editor-esbuild/package.json +++ b/editor-packages/editor-services-esbuild/package.json @@ -1,5 +1,5 @@ { - "name": "@code-editor/esbuild", + "name": "@code-editor/esbuild-services", "version": "0.0.0", "private": false, "dependencies": { @@ -11,4 +11,4 @@ "axios": "^0.26.1", "nanoid": "^3.3.2" } -} +} \ No newline at end of file diff --git a/editor-packages/editor-esbuild/unpkg-path.plugin.ts b/editor-packages/editor-services-esbuild/unpkg-path.plugin.ts similarity index 100% rename from editor-packages/editor-esbuild/unpkg-path.plugin.ts rename to editor-packages/editor-services-esbuild/unpkg-path.plugin.ts diff --git a/editor-packages/editor-esbuild/workers/fetch-types.worker.js b/editor-packages/editor-services-esbuild/workers/fetch-types.worker.js similarity index 100% rename from editor-packages/editor-esbuild/workers/fetch-types.worker.js rename to editor-packages/editor-services-esbuild/workers/fetch-types.worker.js diff --git a/editor-packages/editor-services-jsx-syntax-highlight/package.json b/editor-packages/editor-services-jsx-syntax-highlight/package.json new file mode 100644 index 00000000..d9e4f53f --- /dev/null +++ b/editor-packages/editor-services-jsx-syntax-highlight/package.json @@ -0,0 +1,9 @@ +{ + "name": "@code-editor/jsx-syntax-highlight-services", + "version": "0.0.0", + "private": false, + "dependencies": {}, + "peerDependencies": { + "@monaco-editor/react": "^4.4.1" + } +} \ No newline at end of file diff --git a/editor-packages/editor-services-prettier/package.json b/editor-packages/editor-services-prettier/package.json new file mode 100644 index 00000000..3fed6809 --- /dev/null +++ b/editor-packages/editor-services-prettier/package.json @@ -0,0 +1,9 @@ +{ + "name": "@code-editor/prettier-services", + "version": "0.0.0", + "private": false, + "dependencies": {}, + "peerDependencies": { + "@monaco-editor/react": "^4.4.1" + } +} \ No newline at end of file diff --git a/editor/components/app-runner/vanilla-app-runner.tsx b/editor/components/app-runner/vanilla-app-runner.tsx index eb646acb..7a31398b 100644 --- a/editor/components/app-runner/vanilla-app-runner.tsx +++ b/editor/components/app-runner/vanilla-app-runner.tsx @@ -1,15 +1,17 @@ -import React, { useEffect, useRef } from "react"; +import React, { ReactEventHandler, useEffect, useRef } from "react"; export function VanillaRunner({ width, height, source, + onLoad, enableInspector = true, style, }: { width: string; height: string; source: string; + onLoad?: ReactEventHandler; componentName: string; enableInspector?: boolean; style?: React.CSSProperties; @@ -40,39 +42,41 @@ export function VanillaRunner({ }, [ref.current]); useEffect(() => { - if (ref.current && enableInspector) { - ref.current.onload = () => { - const matches = ref.current.contentDocument.querySelectorAll( - "div, span, img, image, svg" // button, input - disabled due to interaction testing (for users) - ); - matches.forEach((el) => { - const tint = "rgba(20, 0, 255, 0.2)"; - const tintl = "rgba(20, 0, 255, 0.5)"; - const originstyle = { - //@ts-ignore - ...el.style, - }; - - if (el.id.includes("RootWrapper")) { - } else { - el.addEventListener("mouseenter", (e) => { - //@ts-ignore - e.target.style.background = tint; - //@ts-ignore - e.target.style.outline = `${tintl} solid 1px`; - }); - el.addEventListener("mouseleave", (e) => { - //@ts-ignore - e.target.style.background = originstyle.background; + if (ref.current) { + ref.current.onload = (e) => { + if (enableInspector) { + const matches = ref.current.contentDocument.querySelectorAll( + "div, span, img, image, svg" // button, input - disabled due to interaction testing (for users) + ); + matches.forEach((el) => { + const tint = "rgba(20, 0, 255, 0.2)"; + const tintl = "rgba(20, 0, 255, 0.5)"; + const originstyle = { //@ts-ignore - e.target.style.outline = originstyle.outline; - }); - } - }); + ...el.style, + }; + + if (el.id.includes("RootWrapper")) { + } else { + el.addEventListener("mouseenter", (e) => { + //@ts-ignore + e.target.style.background = tint; + //@ts-ignore + e.target.style.outline = `${tintl} solid 1px`; + }); + el.addEventListener("mouseleave", (e) => { + //@ts-ignore + e.target.style.background = originstyle.background; + //@ts-ignore + e.target.style.outline = originstyle.outline; + }); + } + }); - ref.current.contentWindow.addEventListener("click", (e) => { - console.log("click", e); - }); + ref.current.contentWindow.addEventListener("click", (e) => { + console.log("click", e); + }); + } }; } }, [ref.current, enableInspector]); @@ -81,6 +85,7 @@ export function VanillaRunner({ return (