Optimize Playground
This commit is contained in:
77
src/components/Playground/Output/Preview/Render.tsx
Normal file
77
src/components/Playground/Output/Preview/Render.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import iframeRaw from '@/components/Playground/Output/Preview/iframe.html?raw'
|
||||||
|
|
||||||
|
interface RenderProps {
|
||||||
|
iframeKey: string
|
||||||
|
compiledCode: string
|
||||||
|
onError?: (errorMsg: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMessage {
|
||||||
|
type: 'LOADED' | 'ERROR' | 'UPDATE' | 'DONE'
|
||||||
|
msg: string
|
||||||
|
data: {
|
||||||
|
compiledCode: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIframeUrl = (iframeRaw: string) => {
|
||||||
|
const shimsUrl = '//unpkg.com/es-module-shims/dist/es-module-shims.js'
|
||||||
|
// 判断浏览器是否支持esm ,不支持esm就引入es-module-shims
|
||||||
|
const newIframeRaw =
|
||||||
|
typeof import.meta === 'undefined'
|
||||||
|
? iframeRaw.replace(
|
||||||
|
'<!-- es-module-shims -->',
|
||||||
|
`<script async src="${shimsUrl}"></script>`
|
||||||
|
)
|
||||||
|
: iframeRaw
|
||||||
|
return URL.createObjectURL(new Blob([newIframeRaw], { type: 'text/html' }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const iframeUrl = getIframeUrl(iframeRaw)
|
||||||
|
|
||||||
|
const Render = ({ iframeKey, compiledCode, onError }: RenderProps) => {
|
||||||
|
const iframeRef = useRef<HTMLIFrameElement>(null)
|
||||||
|
const [loaded, setLoaded] = useState(false)
|
||||||
|
|
||||||
|
const handleMessage = ({ data }: { data: IMessage }) => {
|
||||||
|
const { type, msg } = data
|
||||||
|
switch (type) {
|
||||||
|
case 'LOADED':
|
||||||
|
setLoaded(true)
|
||||||
|
break
|
||||||
|
case 'ERROR':
|
||||||
|
onError?.(msg)
|
||||||
|
break
|
||||||
|
case 'DONE':
|
||||||
|
onError?.('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('message', handleMessage)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('message', handleMessage)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loaded) {
|
||||||
|
iframeRef.current?.contentWindow?.postMessage({
|
||||||
|
type: 'UPDATE',
|
||||||
|
data: { compiledCode }
|
||||||
|
} as IMessage)
|
||||||
|
}
|
||||||
|
}, [compiledCode, loaded])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
key={iframeKey}
|
||||||
|
ref={iframeRef}
|
||||||
|
src={iframeUrl}
|
||||||
|
sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals allow-same-origin"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Render
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import '@/components/Playground/Output/Preview/preview.scss'
|
import '@/components/Playground/Output/Preview/preview.scss'
|
||||||
import { IFiles, IImportMap } from '@/components/Playground/shared'
|
import { IFiles, IImportMap } from '@/components/Playground/shared'
|
||||||
import Compiler from '@/components/Playground/compiler'
|
import Compiler from '@/components/Playground/compiler'
|
||||||
import iframeRaw from '@/components/Playground/Output/Preview/iframe.html?raw'
|
import { ENTRY_FILE_NAME } from '@/components/Playground/files'
|
||||||
import { ENTRY_FILE_NAME } from '@/components/Playground/files.ts'
|
import Render from '@/components/Playground/Output/Preview/Render'
|
||||||
|
|
||||||
interface PreviewProps {
|
interface PreviewProps {
|
||||||
iframeKey: string
|
iframeKey: string
|
||||||
@@ -10,79 +10,27 @@ interface PreviewProps {
|
|||||||
importMap: IImportMap
|
importMap: IImportMap
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMessage {
|
|
||||||
type: 'LOADED' | 'ERROR' | 'UPDATE' | 'DONE'
|
|
||||||
msg: string
|
|
||||||
data: {
|
|
||||||
compiledCode: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getIframeUrl = (iframeRaw: string) => {
|
|
||||||
const shimsUrl = '//unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js'
|
|
||||||
// 判断浏览器是否支持esm ,不支持esm就引入es-module-shims
|
|
||||||
const newIframeRaw =
|
|
||||||
typeof import.meta === 'undefined'
|
|
||||||
? iframeRaw.replace(
|
|
||||||
'<!-- es-module-shims -->',
|
|
||||||
`<script async src="${shimsUrl}"></script>`
|
|
||||||
)
|
|
||||||
: iframeRaw
|
|
||||||
return URL.createObjectURL(new Blob([newIframeRaw], { type: 'text/html' }))
|
|
||||||
}
|
|
||||||
|
|
||||||
const iframeUrl = getIframeUrl(iframeRaw)
|
|
||||||
|
|
||||||
const Preview = ({ iframeKey, files, importMap }: PreviewProps) => {
|
const Preview = ({ iframeKey, files, importMap }: PreviewProps) => {
|
||||||
const iframeRef = useRef<HTMLIFrameElement>(null)
|
|
||||||
const [errorMsg, setErrorMsg] = useState('')
|
const [errorMsg, setErrorMsg] = useState('')
|
||||||
const [loaded, setLoaded] = useState(false)
|
const [compiledCode, setCompiledCode] = useState('')
|
||||||
|
|
||||||
const handleMessage = ({ data }: { data: IMessage }) => {
|
const handleOnError = (errorMsg: string) => {
|
||||||
const { type, msg } = data
|
setErrorMsg(errorMsg)
|
||||||
switch (type) {
|
|
||||||
case 'LOADED':
|
|
||||||
setLoaded(true)
|
|
||||||
break
|
|
||||||
case 'ERROR':
|
|
||||||
setErrorMsg(msg)
|
|
||||||
break
|
|
||||||
case 'DONE':
|
|
||||||
setErrorMsg('')
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener('message', handleMessage)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('message', handleMessage)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Compiler.compile(files, importMap, [ENTRY_FILE_NAME])
|
Compiler.compile(files, importMap, [ENTRY_FILE_NAME])
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (loaded) {
|
setCompiledCode(result.outputFiles[0].text)
|
||||||
iframeRef.current?.contentWindow?.postMessage({
|
|
||||||
type: 'UPDATE',
|
|
||||||
data: { compiledCode: result.outputFiles[0].text }
|
|
||||||
} as IMessage)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((e: Error) => {
|
.catch((e: Error) => {
|
||||||
setErrorMsg(`编译失败:${e.message}`)
|
setErrorMsg(`编译失败:${e.message}`)
|
||||||
})
|
})
|
||||||
}, [files, Compiler, loaded])
|
}, [files, Compiler])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-component={'playground-preview'}>
|
<div data-component={'playground-preview'}>
|
||||||
<iframe
|
<Render iframeKey={iframeKey} compiledCode={compiledCode} onError={handleOnError} />
|
||||||
key={iframeKey}
|
|
||||||
ref={iframeRef}
|
|
||||||
src={iframeUrl}
|
|
||||||
sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals allow-same-origin"
|
|
||||||
/>
|
|
||||||
{errorMsg && <div className={'playground-error-message'}>{errorMsg}</div>}
|
{errorMsg && <div className={'playground-error-message'}>{errorMsg}</div>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ class Compiler {
|
|||||||
constructor() {
|
constructor() {
|
||||||
try {
|
try {
|
||||||
void esbuild
|
void esbuild
|
||||||
.initialize({ worker: true, wasmURL: 'https://esm.sh/esbuild-wasm/esbuild.wasm' })
|
.initialize({
|
||||||
|
worker: true,
|
||||||
|
wasmURL: 'https://esm.sh/esbuild-wasm@0.19.12/esbuild.wasm'
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.init = true
|
this.init = true
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user