Optimize Playground

This commit is contained in:
2024-01-25 15:35:52 +08:00
parent 34034ec59b
commit 96acaddf77
12 changed files with 58 additions and 33 deletions

View File

@@ -110,6 +110,10 @@ const FileSelector = ({
}
const handleOnValidateTab = (newFileName: string, oldFileName: string) => {
if (newFileName.length > 40) {
onError?.('File name is too long, maximum 40 characters.')
}
if (!/\.(jsx|tsx|js|ts|css|json)$/.test(newFileName)) {
onError?.('Playground only supports *.jsx, *.tsx, *.js, *.ts, *.css, *.json files.')
@@ -219,4 +223,6 @@ const FileSelector = ({
)
}
FileSelector.Item = Item
export default FileSelector

View File

@@ -160,4 +160,7 @@ const CodeEditor = ({
)
}
CodeEditor.Editor = Editor
CodeEditor.FileSelector = FileSelector
export default CodeEditor

View File

@@ -1,3 +1,4 @@
import '@/components/Playground/Output/Preview/render.scss'
import iframeRaw from '@/components/Playground/Output/Preview/iframe.html?raw'
interface RenderProps {
@@ -66,6 +67,7 @@ const Render = ({ iframeKey, compiledCode, onError }: RenderProps) => {
return (
<iframe
data-component={'playground-output-preview-render'}
key={iframeKey}
ref={iframeRef}
src={iframeUrl}

View File

@@ -48,11 +48,6 @@
});
</script>
<script type="module" id="appSrc"></script>
<div id="root">
<div
style="position:absolute;top: 0;left:0;width:100%;height:100%;display: flex;justify-content: center;align-items: center;">
Loading...
</div>
</div>
<div id="root"></div>
</body>
</html>

View File

@@ -1,16 +1,16 @@
import '@/components/Playground/Output/Preview/preview.scss'
import { IFiles, IImportMap } from '@/components/Playground/shared'
import Compiler from '@/components/Playground/compiler'
import { ENTRY_FILE_NAME } from '@/components/Playground/files'
import Render from '@/components/Playground/Output/Preview/Render'
interface PreviewProps {
iframeKey: string
files: IFiles
importMap: IImportMap
entryPoint: string
}
const Preview = ({ iframeKey, files, importMap }: PreviewProps) => {
const Preview = ({ iframeKey, files, importMap, entryPoint }: PreviewProps) => {
const [errorMsg, setErrorMsg] = useState('')
const [compiledCode, setCompiledCode] = useState('')
@@ -19,7 +19,7 @@ const Preview = ({ iframeKey, files, importMap }: PreviewProps) => {
}
useEffect(() => {
Compiler.compile(files, importMap, [ENTRY_FILE_NAME])
Compiler.compile(files, importMap, entryPoint)
.then((result) => {
setCompiledCode(result.outputFiles[0].text)
})
@@ -36,4 +36,6 @@ const Preview = ({ iframeKey, files, importMap }: PreviewProps) => {
)
}
Preview.Render = Render
export default Preview

View File

@@ -3,9 +3,4 @@
position: relative;
width: 100%;
height: 100%;
iframe {
border: none;
flex: 1;
}
}

View File

@@ -0,0 +1,6 @@
[data-component=playground-output-preview-render] {
border: none;
height: 100%;
width: 100%;
flex: 1;
}

View File

@@ -1,6 +1,6 @@
import FlexBox from '@/components/common/FlexBox'
import { IFiles, IImportMap } from '@/components/Playground/shared'
import FileSelector from '@/components/Playground/CodeEditor/FileSelector'
import Playground from '@/components/Playground'
import Transform from '@/components/Playground/Output/Transform'
import Preview from '@/components/Playground/Output/Preview'
@@ -8,14 +8,15 @@ interface OutputProps {
files: IFiles
selectedFileName: string
importMap: IImportMap
entryPoint: string
}
const Output = ({ files, selectedFileName, importMap }: OutputProps) => {
const Output = ({ files, selectedFileName, importMap, entryPoint }: OutputProps) => {
const [selectedTab, setSelectedTab] = useState('Preview')
return (
<FlexBox data-component={'playground-code-output'}>
<FileSelector
<Playground.CodeEditor.FileSelector
files={{
Preview: { name: 'Preview', language: 'json', value: '' },
Transform: { name: 'Transform', language: 'json', value: '' }
@@ -29,6 +30,7 @@ const Output = ({ files, selectedFileName, importMap }: OutputProps) => {
iframeKey={JSON.stringify(importMap)}
files={files}
importMap={importMap}
entryPoint={entryPoint}
/>
)}
{selectedTab === 'Transform' && <Transform file={files[selectedFileName]} />}

View File

@@ -2,7 +2,7 @@ import esbuild, { Loader, OnLoadArgs, Plugin, PluginBuild } from 'esbuild-wasm'
import localforage from 'localforage'
import axios from 'axios'
import { IFiles, IImportMap } from '@/components/Playground/shared'
import { cssToJs, ENTRY_FILE_NAME, jsonToJs, addReactImport } from '@/components/Playground/files'
import { cssToJs, jsonToJs, addReactImport } from '@/components/Playground/files'
class Compiler {
private init = false
@@ -42,7 +42,7 @@ class Compiler {
return esbuild.transform(code, { loader })
})
compile = (files: IFiles, importMap: IImportMap, entryPoints: string[]) =>
compile = (files: IFiles, importMap: IImportMap, entryPoint: string) =>
new Promise<void>((resolve) => {
if (this.init) {
resolve()
@@ -57,11 +57,11 @@ class Compiler {
}).then(() => {
return esbuild.build({
bundle: true,
entryPoints: entryPoints,
entryPoints: [entryPoint],
format: 'esm',
metafile: true,
write: false,
plugins: [this.fileResolverPlugin(files, importMap, entryPoints)]
plugins: [this.fileResolverPlugin(files, importMap, entryPoint)]
})
})
@@ -72,13 +72,13 @@ class Compiler {
private fileResolverPlugin = (
files: IFiles,
importMap: IImportMap,
entryPoints: string[]
entryPoint: string
): Plugin => {
return {
name: 'file-resolver-plugin',
setup: (build: PluginBuild) => {
build.onResolve({ filter: /.*/ }, (args: esbuild.OnResolveArgs) => {
if (entryPoints.includes(args.path)) {
if (entryPoint === args.path) {
return {
namespace: 'OxygenToolbox',
path: args.path
@@ -165,10 +165,10 @@ class Compiler {
})
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs) => {
if (args.path === ENTRY_FILE_NAME) {
if (entryPoint === args.path) {
return {
loader: 'tsx',
contents: addReactImport(files[ENTRY_FILE_NAME].value)
contents: addReactImport(files[entryPoint].value)
}
}

View File

@@ -1,6 +1,7 @@
import '@/components/Playground/playground.scss'
import { IFiles, IImportMap, ITsconfig } from '@/components/Playground/shared'
import {
ENTRY_FILE_NAME,
IMPORT_MAP_FILE_NAME,
MAIN_FILE_NAME,
TS_CONFIG_FILE_NAME
@@ -13,9 +14,15 @@ interface PlaygroundProps {
initFiles: IFiles
initImportMapRaw: string
initTsconfigRaw: string
entryPoint?: string
}
const Playground = ({ initFiles, initImportMapRaw, initTsconfigRaw }: PlaygroundProps) => {
const Playground = ({
initFiles,
initImportMapRaw,
initTsconfigRaw,
entryPoint = ENTRY_FILE_NAME
}: PlaygroundProps) => {
const [files, setFiles] = useState(initFiles)
const [selectedFileName, setSelectedFileName] = useState(MAIN_FILE_NAME)
const [importMapRaw, setImportMapRaw] = useState<string>(initImportMapRaw)
@@ -93,7 +100,12 @@ const Playground = ({ initFiles, initImportMapRaw, initTsconfigRaw }: Playground
onChangeFileContent={handleOnChangeFileContent}
onSelectedFileChange={setSelectedFileName}
/>
<Output files={files} selectedFileName={selectedFileName} importMap={importMap!} />
<Output
files={files}
selectedFileName={selectedFileName}
importMap={importMap!}
entryPoint={entryPoint}
/>
</FlexBox>
)
}

View File

@@ -32,8 +32,8 @@ import FitFullscreen from '@/components/common/FitFullscreen'
import FlexBox from '@/components/common/FlexBox'
import HideScrollbar from '@/components/common/HideScrollbar'
import Card from '@/components/common/Card'
import CodeEditor from '@/components/Playground/CodeEditor'
import Permission from '@/components/common/Permission'
import Playground from '@/components/Playground'
const Base = () => {
const blocker = useBlocker(
@@ -283,9 +283,11 @@ const Base = () => {
duration: 0
})
void compiler
.compile(files, importMap, [
.compile(
files,
importMap,
compileForm.getFieldValue('entryFileName') as string
])
)
.then((result) => {
void message.destroy('compiling')
void message.loading({
@@ -982,7 +984,7 @@ const Base = () => {
</Card>
{editingFileName && (
<Card>
<CodeEditor
<Playground.CodeEditor
files={editingFiles[editingBaseId]}
selectedFileName={editingFileName}
onSelectedFileChange={() => {}}

View File

@@ -30,8 +30,8 @@ import FitFullscreen from '@/components/common/FitFullscreen'
import FlexBox from '@/components/common/FlexBox'
import HideScrollbar from '@/components/common/HideScrollbar'
import Card from '@/components/common/Card'
import CodeEditor from '@/components/Playground/CodeEditor'
import Permission from '@/components/common/Permission'
import Playground from '@/components/Playground'
const Template = () => {
const blocker = useBlocker(
@@ -866,7 +866,7 @@ const Template = () => {
</Card>
{editingFileName && (
<Card>
<CodeEditor
<Playground.CodeEditor
files={editingFiles[editingTemplateId]}
selectedFileName={editingFileName}
onSelectedFileChange={() => {}}