实现 React 的 Playground(总结)

567 阅读5分钟

# 实现 React 的 Playground(1)

# 实现 React 的 Playground(2)

# 实现 React 的 Playground(3)

# 实现 React 的 Playground(4)

# 实现 React 的 Playground(总结)

费了很大功夫终于完成了react的playGround,我很开心,这将又是一次编码功底的提升。谢了很多年的业务,很少关注这些小工具,其实这些小工具才是真正带领我们提升能力的臂膀。希望大家有时间也去敲一下,重新理解前端。现在就对这个工具做一个简单的总结。

1.需求

playground 就是一个代码演示器,他最大的优点就是实现代码在线编辑,然后实时获取渲染结果。还能通过分享链接的方式和同伴一起联调代码。同时你也可以下载代码,拿到文件包。最大限度的提高咱们组件库开发的效率。

在整个playground的页面上主要功能是:

1.编辑器编写代码,右侧预览区预览效果

2.编辑区支持react和ts,可以进行代码提示和ts类型提示。

3.预览区错误以抽屉的形式,显示在预览区的下侧,方便开发人员及时关注。

4.在fileList上可以切换文件,删除文件,还能修改文件名,也能新增文件。

5.页面右上角可以切换主题

6.页面右上角可以分享地址,实现多人开发。

7.页面右上角可以下载文件,实现代码移植。

2.实现

2.1布局

因为咱们的playground的编辑区和预览区的中界线是可以左右移动的,你可以自己写css实现,也可以使用组件库,我们选用:allotment;

image.png

2.2编辑器

编辑区的编辑器种类有很多,我们选择@monaco-editor/react,因为它可以编译jsx,ts,通过配置就能实现错误展示,还有api查找

image.png

image.png

这样使用起来更加接近咱们的编辑器vscode

2.3 ts类型检测

在正常的项目里面,我们使用tscofig.json来配置ts的检测,但是在这里,我们无法使用它,那就用@typescript/ata,它会帮我们在浏览器里面进行类型检测

image.png

image.png

2.4 数据中心context

编辑器里面出来的文件都是以字符串的形式存放在files对象里面的。

image.png

你会发现整个playground的数据中心就是整个context。不管是文件list,还是编辑器,还是预览器,还是地址分享,内容下载,还是主题色的切换,都是以context为中心来活动的。

2.5 fileList文件列表

fileList里面对文件的增删改查完全是操作context的结果。

image.png

2.6 预览区--编译代码

预览区就是一个iframe,我们创建一个iframe.html文件,然后将react入口文件main.tsx插入root下面去,然后拿到文件url就可以渲染了。

首先浏览器不认识jsx,也不认ts,在files里面的main.tsx是字符串的形式存储的,所以我们要用@babel/standalone去编译文件,把jsx转成React.createElement() 这样就能拿到一个浏览器可以认识的js文件了。

image.png

2.7 预览区--处理本地文件

光编译代码是不行的,因为我们的组件一般上面都会用 import 导入其他文件,比如 React 文件,比如本地组件App.tsx,现在我们就处理下import App from './App';

他是通过babel插件实现的,就是去监控babel的import, 如果我们的文件是本地文件,他一定存储在files里面,然后从files里面拿到具体的文件代码,然后处理。

image.png

本地文件有三种:css,json,js

1.css文件:在header下面创建一个style标签,然后将css代码插入标签里面就好了。

2.json文件:先把他转成js,就是代码前面加上export default,就变成导出数组了,然后获取内存地址URL.createObjectURL(new Blob([js], { type: 'application/javascript' }));

3.根据文件名,先去files里面拿到文件,然后编译,再获取内存地址:URL.createObjectURL(new Blob([js], { type: 'application/javascript' }));,此时的编译,就是一个递归过程,他会将下属文件里面所有的import地址转成内存地址。

2.8 处理包文件

处理import React from 'react'很重要,就是在html文件里面插入importmap类型的script,然后把包地址配置进去就好了。

image.png

script标签里面放入导入第三方的包地址,一定要注意它的type是importmap

这样导入是找不到具体的包的,所以必须用importmap才行。

<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

这样也行。 image.png

但是我们采用的是ems.sh地址。

2.9 预览器渲染页面

预览区页面加载,拿到编译好的main.tsx文件以后,我们将他插入到html的script的标签里面。一个完整的html文件就出来,然后用 URL.createObjectURL(new Blob([res], { type: 'text/html' }))拿到html的内存地址,然后交给iframe标签,要浏览器进行渲染。

image.png

2.10 主题切换

利用 css3的var()函数

变量要以两个连字符--(横杆)(减号)为开头

就是在父组件里面定义变量,然后在子组件里面使用var()函数加载

image.png

2.11 链接分享

我们把files数据存储到window.location.hash里面,在保存之前要对files进行压缩,我们选择fflate做压缩器,它的优点就是小巧好用。

image.png

压缩好的files数据全部存储到location的hash上,这样即便你改了编辑器里面的代码,也会同步到url里面。

复制数据使用copy-to-clipboard做剪切板。

拿到url以后,第一件事就是解析url里面的files,首先对他进行解压,然后再把他用JSON.parse()编译成对象。存入context.provide的files初始数据里面去。

image.png

2.12 下载文件

下载文件我们选用的工具是:jszip'file-saver,如果不借用后端,直接下载页面文件,我们可以使用file-saver实现,用这个工具我们还可以实现页面表格导出excel。下载的时候我们需要对files里存储的所有的文件进行打包,所以选择jszip

image.png

在我们实现功能的时候导出都用到了Blob对象,我们对这个对象重新进行学习