playground

292 阅读1分钟

1.编译

编译用的 @babel/standalone,这个是 babel 的浏览器版本。

可以用它实时把 tsx 代码编译为 js。

///拿到内容用babel.transform编译,指定 typescript 和 react 的 preset
const res = transform(textareaRef.current.value, { presets: ['react', 'typescript'], filename: 'guang.tsx' });

问题1: import 模块找不到

解决方法: import 的 url 可以用 blob url 可以把JS代码 用URL.createObjectURL和new Blob的方式变为一个 url

<script> 
const code1 =` function add(a, b) { return a + b; } export { add }; `;
const url = URL.createObjectURL(new Blob([code1], { type: 'application/javascript' })); 
const code2 = `import { add } from "${url}"; console.log(add(2, 3));`; 
const script = document.createElement('script'); script.type="module"; s
cript.textContent = code2; document.body.appendChild(script); 
</script>

babel插件

  • babel 编译流程分为parse transform genrate
  • babel 插件就是在 transform 的阶段增删改 AST 的

编辑器部分

@monaco-editor/react

预览部分

iframe,然后加一个通信机制,左边编辑器的结果,编译之后传到 iframe 里渲染就好了

import React from 'react' 
//?raw 是通过字符串引入
import iframeRaw from './iframe.html?raw'; 

const iframeUrl = URL.createObjectURL(new Blob([iframeRaw], { type: 'text/html' }));

const Preview: React.FC = () => { return ( <iframe src={iframeUrl} style={{ width: '100%', height: '100%', padding: 0, border: 'none' }} /> ) } 

export default Preview;

总结

  • 编辑器部分 @monaco-editor/react
  • @babel/standalone 在浏览器里编译
  • 编译过程中用自己写的 babel 插件实现 import 的 source 的修改,变为 URL.createObjectURL + Blob 生成的 blob url,把模块内容内联进去。
  • 对于 react、react-dom 这种包,用 import maps 配合 esm.sh 网站来引入。
  • iframe 预览生成的内容,url 同样是把内容内联到 src 里,生成 blob url