From 309d5892c74470ec1c16e5f6a1d71bd3dfe2e326 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Wed, 10 Jan 2024 23:00:30 +0800 Subject: [PATCH] Optimize Transform --- .../Playground/CodeEditor/Editor/index.tsx | 2 +- .../Playground/CodeEditor/index.tsx | 2 +- src/components/Playground/Preview/index.tsx | 78 ------------------- src/components/Playground/Transform/index.tsx | 77 ++++++++++++++++++ src/components/Playground/compiler.ts | 4 +- src/components/Playground/files.ts | 40 +++++----- src/pages/OnlineEditor.tsx | 15 ++-- 7 files changed, 111 insertions(+), 107 deletions(-) delete mode 100644 src/components/Playground/Preview/index.tsx create mode 100644 src/components/Playground/Transform/index.tsx diff --git a/src/components/Playground/CodeEditor/Editor/index.tsx b/src/components/Playground/CodeEditor/Editor/index.tsx index 96e5a54..35ba545 100644 --- a/src/components/Playground/CodeEditor/Editor/index.tsx +++ b/src/components/Playground/CodeEditor/Editor/index.tsx @@ -37,7 +37,7 @@ const Editor: React.FC = ({ dispose: () => undefined }) const { total, finished, onWatch } = useTypesProgress() - const file = files[selectedFileName] ?? { name: 'Untitled' } + const file = files[selectedFileName] || { name: 'Untitled' } const handleOnEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => { editorRef.current = editor diff --git a/src/components/Playground/CodeEditor/index.tsx b/src/components/Playground/CodeEditor/index.tsx index 6014a5a..ea269e3 100644 --- a/src/components/Playground/CodeEditor/index.tsx +++ b/src/components/Playground/CodeEditor/index.tsx @@ -46,7 +46,7 @@ const CodeEditor: React.FC = ({ (item) => ![IMPORT_MAP_FILE_NAME, ENTRY_FILE_NAME].includes(item) && !files[item].hidden ) const propsSelectedFileName = - props.selectedFileName ?? (filteredFilesName.length ? filteredFilesName[0] : '') + props.selectedFileName || (filteredFilesName.length ? filteredFilesName[0] : '') const [selectedFileName, setSelectedFileName] = useState(propsSelectedFileName) const [errorMsg, setErrorMsg] = useState('') diff --git a/src/components/Playground/Preview/index.tsx b/src/components/Playground/Preview/index.tsx deleted file mode 100644 index e9473c2..0000000 --- a/src/components/Playground/Preview/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useRef, useState } from 'react' -import { IFiles } from '@/components/Playground/shared.ts' -import { useUpdatedEffect } from '@/util/hooks.tsx' -import Compiler from '@/components/Playground/compiler.ts' -import { Loader } from 'esbuild-wasm' -import { cssToJs, jsonToJs } from '@/components/Playground/files.ts' - -interface OutputProps { - files: IFiles -} - -const Preview: React.FC = ({ files }) => { - const compiler = useRef() - const [compileCode, setCompileCode] = useState('') - const [fileName, setFileName] = useState('main.tsx') - - const handleOnChange = (e: React.ChangeEvent) => { - setFileName(e.target.value) - } - - useUpdatedEffect(() => { - if (!compiler.current) { - compiler.current = new Compiler() - } - }, []) - - useUpdatedEffect(() => { - if (files[fileName]) { - try { - const file = files[fileName] - - let loader: Loader - let code = file.value - - switch (file.language) { - case 'typescript': - loader = 'tsx' - break - case 'javascript': - loader = 'jsx' - break - case 'css': - code = cssToJs(file) - loader = 'js' - break - case 'json': - code = jsonToJs(file) - loader = 'js' - break - case 'xml': - loader = 'default' - } - - compiler.current - ?.transform(code, loader) - .then((value) => { - setCompileCode(value.code) - }) - .catch((e) => { - console.error('编译失败', e) - }) - } catch (e) { - setCompileCode('') - } - } else { - setCompileCode('') - } - }, [fileName, files]) - - return ( - <> - - - - ) -} - -export default Preview diff --git a/src/components/Playground/Transform/index.tsx b/src/components/Playground/Transform/index.tsx new file mode 100644 index 0000000..796ee64 --- /dev/null +++ b/src/components/Playground/Transform/index.tsx @@ -0,0 +1,77 @@ +import React from 'react' +import MonacoEditor from '@monaco-editor/react' +import { Loader } from 'esbuild-wasm' +import { useUpdatedEffect } from '@/util/hooks' +import { IFile, ITheme } from '@/components/Playground/shared' +import Compiler from '@/components/Playground/compiler' +import { cssToJs, jsonToJs } from '@/components/Playground/files' +import { MonacoEditorConfig } from '@/components/Playground/CodeEditor/Editor/monacoConfig' + +interface OutputProps { + file: IFile + theme?: ITheme +} + +const Preview: React.FC = ({ file, theme }) => { + const compiler = useRef() + const [compileCode, setCompileCode] = useState('') + + useUpdatedEffect(() => { + if (!compiler.current) { + compiler.current = new Compiler() + } + }, []) + + const compile = (code: string, loader: Loader) => { + compiler.current + ?.transform(code, loader) + .then((value) => { + setCompileCode(value.code) + }) + .catch((e) => { + console.error('编译失败', e) + }) + } + + useUpdatedEffect(() => { + if (file) { + try { + const code = file.value + + switch (file.language) { + case 'typescript': + compile(code, 'tsx') + break + case 'javascript': + compile(code, 'jsx') + break + case 'css': + setCompileCode(cssToJs(file)) + break + case 'json': + setCompileCode(jsonToJs(file)) + break + case 'xml': + setCompileCode(code) + } + } catch (e) { + setCompileCode('') + } + } else { + setCompileCode('') + } + }, [file]) + + return ( + <> + + + ) +} + +export default Preview diff --git a/src/components/Playground/compiler.ts b/src/components/Playground/compiler.ts index ece9440..e896478 100644 --- a/src/components/Playground/compiler.ts +++ b/src/components/Playground/compiler.ts @@ -9,9 +9,7 @@ class Compiler { void esbuild.initialize({ worker: true, wasmURL: wasm }).then(() => { this.init = true }) - } catch (e) { - throw e - } + } catch (e) {} } transform = (code: string, loader: Loader) => diff --git a/src/components/Playground/files.ts b/src/components/Playground/files.ts index ab47d75..9b7f4f2 100644 --- a/src/components/Playground/files.ts +++ b/src/components/Playground/files.ts @@ -3,18 +3,19 @@ import importMap from '@/components/Playground/template/import-map.json?raw' import AppCss from '@/components/Playground/template/src/App.css?raw' import App from '@/components/Playground/template/src/App.tsx?raw' import main from '@/components/Playground/template/src/main.tsx?raw' -import { IFile, IFiles } from '@/components/Playground/shared' +import { IFile, IFiles, ILanguage } from '@/components/Playground/shared' export const MAIN_FILE_NAME = 'App.tsx' export const IMPORT_MAP_FILE_NAME = 'import-map.json' export const ENTRY_FILE_NAME = 'main.tsx' -export const fileNameToLanguage = (name: string) => { +export const fileNameToLanguage = (name: string): ILanguage => { const suffix = name.split('.').pop() || '' if (['js', 'jsx'].includes(suffix)) return 'javascript' if (['ts', 'tsx'].includes(suffix)) return 'typescript' if (['json'].includes(suffix)) return 'json' if (['css'].includes(suffix)) return 'css' + if (['svg'].includes(suffix)) return 'xml' return 'javascript' } @@ -62,27 +63,30 @@ export const getModuleFile = (files: IFiles, moduleName: string) => { return files[_moduleName] } +export const jsToBlob = (code: string) => { + return URL.createObjectURL(new Blob([code], { type: 'application/javascript' })) +} + export const jsonToJs = (file: IFile) => { - const js = `export default ${file.value}` - return URL.createObjectURL(new Blob([js], { type: 'application/javascript' })) + return `export default ${file.value}` } export const cssToJs = (file: IFile) => { const randomId = new Date().getTime() - const js = ` - (() => { - let stylesheet = document.getElementById('style_${randomId}_${file.name}'); - if (!stylesheet) { - stylesheet = document.createElement('style') - stylesheet.setAttribute('id', 'style_${randomId}_${file.name}') - document.head.appendChild(stylesheet) - } - const styles = document.createTextNode(\`${file.value}\`) - stylesheet.innerHTML = '' - stylesheet.appendChild(styles) - })() - ` - return URL.createObjectURL(new Blob([js], { type: 'application/javascript' })) + return `(() => { + let stylesheet = document.getElementById('style_${randomId}_${file.name}'); + if (!stylesheet) { + stylesheet = document.createElement('style') + stylesheet.setAttribute('id', 'style_${randomId}_${file.name}') + document.head.appendChild(stylesheet) + } + const styles = document.createTextNode( +\`${file.value}\` + ) + stylesheet.innerHTML = '' + stylesheet.appendChild(styles) +})() +` } export const initFiles: IFiles = getFilesFromUrl() || { diff --git a/src/pages/OnlineEditor.tsx b/src/pages/OnlineEditor.tsx index aacaff1..be818c9 100644 --- a/src/pages/OnlineEditor.tsx +++ b/src/pages/OnlineEditor.tsx @@ -1,13 +1,14 @@ -import React from 'react' +import React, { useState } from 'react' import CodeEditor from '@/components/Playground/CodeEditor' -import { initFiles } from '@/components/Playground/files' +import { initFiles, MAIN_FILE_NAME } from '@/components/Playground/files' import { IFiles } from '@/components/Playground/shared' -import FitFullscreen from '@/components/common/FitFullscreen.tsx' -import FlexBox from '@/components/common/FlexBox.tsx' -import Preview from '@/components/Playground/Preview' +import FitFullscreen from '@/components/common/FitFullscreen' +import FlexBox from '@/components/common/FlexBox' +import Transform from '@/components/Playground/Transform' const OnlineEditor: React.FC = () => { const [files, setFiles] = useState(initFiles) + const [selectedFileName, setSelectedFileName] = useState(MAIN_FILE_NAME) return ( <> @@ -15,12 +16,14 @@ const OnlineEditor: React.FC = () => { setFiles(files)} onRemoveFile={(_, files) => setFiles(files)} onRenameFile={(_, __, files) => setFiles(files)} onChangeFileContent={(_, __, files) => setFiles(files)} /> - +