diff --git a/src/components/Playground/Preview/iframe.html b/src/components/Playground/Preview/iframe.html new file mode 100644 index 0000000..9257ece --- /dev/null +++ b/src/components/Playground/Preview/iframe.html @@ -0,0 +1,58 @@ + + + + + + Preview + + + + + +
+
+ Loading... +
+
+ + diff --git a/src/components/Playground/Preview/index.tsx b/src/components/Playground/Preview/index.tsx new file mode 100644 index 0000000..f3b1325 --- /dev/null +++ b/src/components/Playground/Preview/index.tsx @@ -0,0 +1,95 @@ +import React, { useRef, useState } from 'react' +import { IFiles } from '@/components/Playground/shared' +import iframeRaw from '@/components/Playground/Preview/iframe.html?raw' +import { useUpdatedEffect } from '@/util/hooks' +import { IMPORT_MAP_FILE_NAME } from '@/components/Playground/files' +import Compiler from '@/components/Playground/compiler' +import '@/components/Playground/Preview/preview.scss' + +interface PreviewProps { + iframeKey: string + files: IFiles +} + +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( + '', + `` + ) + : iframeRaw + return URL.createObjectURL(new Blob([newIframeRaw], { type: 'text/html' })) +} + +const iframeUrl = getIframeUrl(iframeRaw) + +const Preview: React.FC = ({ iframeKey, files }) => { + const iframeRef = useRef(null) + const [errorMsg, setErrorMsg] = useState('') + const [loaded, setLoaded] = useState(false) + + const handleMessage = ({ data }: { data: IMessage }) => { + const { type, msg } = data + switch (type) { + case 'LOADED': + setLoaded(true) + break + case 'ERROR': + setErrorMsg(msg) + break + default: + setErrorMsg('') + } + } + + useEffect(() => { + console.error(errorMsg) + }, [errorMsg]) + + useUpdatedEffect(() => { + window.addEventListener('message', handleMessage) + + return () => { + window.removeEventListener('message', handleMessage) + } + }, []) + + useUpdatedEffect(() => { + Compiler.compile(files, JSON.parse(files[IMPORT_MAP_FILE_NAME].value)) + .then((result) => { + if (loaded) { + iframeRef.current?.contentWindow?.postMessage({ + type: 'UPDATE', + data: { compiledCode: result.outputFiles[0].text } + } as IMessage) + } + }) + .catch((e) => { + setErrorMsg(e) + }) + }, [files, Compiler, loaded]) + + return ( +
+