探索组件在线预览和调试

政采云技术团队.png

梓安.png

这是第159篇没有水的原创文章。想要获取更多原创文章,请搜索公众号【正彩云前端团队】关注我们~

背景

开发过程中如何快速培养前端人员 洞察力 到组件功能和属性?现状是阅读组件的相关文档。好在基础组件库的文档比较完整清晰,示例都是手动完成的。与业务组件相关的文档只能在内部 NPM 私有库上查看,静态 API 文档,没有组件的演示。对于非前端的人,如何预览和调试组件?例如:某天,产品要提前调查其他业务线的业务组件的功能是否能满足业务需求;业务组件开发完成,可参与组件相关功能验证的测试和设计;运营商可以低代码搭建平台,预览和调试相关组件等。

基于以上痛点,我们从需求点出发,逐步探索实施方案。

需要

情景分析

功能

  • 组件预览
  • 组件调试面向不同的用户群。组件功能调试的交互分为两种。一个是 代码调试 ,即通过代码编辑器修改示例代码,另一个是组件 架构调试 ,通过schema JSON数据描述组件的属性,然后通过schema渲染器渲染到组件属性面板中,让非开发人员也能轻松调试组件功能。

分类

  • 基本组件
  • 业务组件
  • 低代码组件大致组织如下:

组件预览和调试-组件分类-导出.png

这里 低代码组件 它是指提供给低代码构建平台的自定义组件。目前,公司低代码搭建平台主要包括“鲁班”。对此感兴趣的可以参考之前的问题。 “我保证” 的文章。

用于组件 架构调试 ,低代码组件本身自带一个schema文件,比如:“鲁班”自定义组件会有一个schema.json文件,需要开发者编写和维护这个文件。

喜欢:

 {  
 “道具” : {  
 “链接列表”:{  
 “组”:“链接配置”,  
 "title" : "链接列表" ,  
 “类型”:“数组”,  
 “领域”:[  
 {  
 “名称”:“图像地址”,  
 "title" : "图片链接图片地址" ,  
 “类型”:“字符串”  
 } ,  
 {  
 “名称”:“图像链接”,  
 "title" : "链接跳转地址" ,  
 “类型”:“字符串”  
 }  
 ]  
 }  
 } ,  
 “楷模” : {  
 “链接列表”:[  
 {  
 “图像地址”:“”,  
 “图像链接”:“”  
 } ,  
 {  
 “图像地址”:“”,  
 “图像链接”:“”  
 }  
 ]  
 }  
 }  
 ​​​  
 复制代码

同理,业务组件也需要相同模式协议的 JSON 文件,以便动态调试组件的属性。但是,开发组件的学生将不允许手动编写它们。

自动生成schema文件的大致思路:

组件在线预览和调试-自动生成 schema 文件-导出.png

应用

  • 基本组件的示例在线预览和调试
  • 演示在线预览和调试业务组件

对于人群

  • 研究与开发
  • 非研发:产品、测试、运营研发主要使用组件的调试功能,而运营、产品等非研发人员有一个简单快速的诉求,就是直接预览组件,看到实时效果通过修改组件的props,那么问题来了,如何修改组件当前的props属性呢?玩过低码的同学应该很清楚有个组件 属性面板 .基于以上,我们可能需要代码编辑面板、组件属性面板、组件功能模块。

粗略画出如下页面的结构图:

组件在线预览和调试-界面图-导出.png

研究

市场上成熟的产品

  • Stackblitz 是一个优秀的在线 IDE,它移植了 VS Code 的许多功能和特性。目前支持很多框架模板,例如:React、Angular、Vue3、Next.js、Nuxt3 和自定义模板。其中,StackBlitz 提供的 WebContainers 可以在浏览器端运行 Node.js 环境。
  • CodeSandbox 是一款为 Web 应用而构建的在线编辑器,同时也提供了多种模板供开发者使用。大部分核心代码也是开源的,网上有相关原理分析和搭建在线IDE解决方案的资料。有兴趣的同学可以去看看。

概括

需求和应用场景已经明确。考虑到不同的用户群体,交互方式也不同。重点是组件调试功能的差异。对于开发者来说,可以通过代码编辑器修改代码,达到调试效果。修改属性面板的组件属性值。市面上成熟的产品会提供一些设计思路,具体实施方案将在下文详细讨论。

程序

从页面结构图中,我们来说说代码编辑器、组件属性面板、工具栏、预览区的设计。

代码编辑器

目前主要有两种:

  • 摩纳哥编辑
  • Codemirror MonacoEditor比较强大,集成度高,但是比较重,而Codemirror轻巧紧凑,核心文件压缩后只有70+ KB左右,根据需要支持的语言打包.

两种代码编辑器都可以满足我们的需求,在线修改一些组件Demo的部分代码,其实Codemirror就够了。

组件属性面板

了解低代码搭建平台的朋友应该不陌生。其实就是通过表单来动态修改组件的属性参数。因此,需要一个通用的模式协议来描述组件的自定义属性。可以通过 我保证 架构数据由大数据搭建平台提供,我们负责渲染。

组件属性类型与操作表单类型的对应关系大致列出:

组件预览和调试-属性面板-导出.png

工具栏

工具栏中包含的主要功能有:

  • 帐号登录
  • 当需要调试接口代理业务组件和低代码组件时,例如测试人员需要干预测试组件功能时,需要使用 帐号登录接口代理功能 .组件中业务接口相关的请求头需要携带当前登录用户的token信息,首先通过请求oauth接口获取对应的token,然后填充到请求头的Authorization字段中。

上述实现的前提是需要代理服务。在本地开发环境中,我们可以使用 http代理 插件创建了本地代理服务,那么问题来了,浏览器端的代理服务怎么做呢?

目前主流的解决方案都是Chrome插件的形式,需要用户手动填写代理界面等信息。在我们的场景中,这个解决方案显然不够人性化。还有一种可以利用浏览器黑科技的解决方案—— 服务工作者 ,它可以拦截来自网页的请求并自定义返回的内容,相当于在浏览器内部实现了一个反向代理。

预览区

核心将涉及两点:

  • 容器
  • 通信容器是指页面容器。业界常见的做法是通过iframe将编译好的组件代码挂载到iframe中的一个根节点,主要用于环境隔离和预览页面访问链接的动态生成。编辑器、核心包和预览区之间的通信可以使用 postMessage。

通讯时序图:

组件预览和调试-通信.png

核心包

设计思路主要参考CodeSandbox的核心源码,主要涉及代码翻译和代码执行。核心模块是 Manger、Transpiler、Preset、Transpiled-module、Runtime。

架构图:

组件预览和调试架构图-导出.png

粗加工:

组件在线预览和调试-核心包流程图-导出.png

马槽模块

顾名思义,管理其他核心模块的“manager”主要负责代码翻译和执行的一系列流程。

核心方法是:

  • addTranspiledModule
  • resolveTranspiledModuleSync
  • resolveTranspiledModuleAsync
  • 评估转译模块 先缓存翻译后的模块,放入 转译模块 目的。如果需要,可以同步或异步地从缓存中加载翻译后的模块。如果需要执行翻译后的模块,可以调用 评估转译模块 方法。

转译模块 类型定义:

 类型 IModule = {  
 路径:字符串;  
 网址?:任何;  
 代码:字符串;  
 需要?:数组<string>;  
 父母?:模块;  
 } ;  
 ​​​  
 接口 ITranspiledModules {  
 [路径:字符串]:{  
 模块:IModule;  
 t模块:{  
 [查询:字符串]:ITranspiledModule; // ITranspiledModule 类型定义放在 Transpiled-module 模块中  
 } ;  
 } ;  
 }  
 复制代码

转译器模块

类似于 Webpack 的 loader,它编译指定类型的文件,例如 Babel、Typescript、vue、tsx、jsx 等。

引入以下内置 Transpiler 模块:

  • babelTranspiler
  • 样式转换器
  • 原始转译器
  • noopTranspiler
  • VueTranspiler`` 原始转译器 与 Webpack 的 raw-loader 一样,它将模块的内容作为字符串导入到内联静态资源中。

实现原理也很简单:

 module.exports = JSON.stringify(sourceCode)  
 复制代码

babelTranspiler 这里实现一个简化版,在bable-standalone.js中引入script标签,获取全局对象babel。

部分核心代码:

 从 './plugins/babel-plugin-rename-imports' 导入 babelPluginRenameImports;  
 ​​​  
 const transpiledCode = 窗口。通天塔。转换(代码,{  
 插件:[babelPluginRenameImports],  
 预设:['es2015','es2016','es2017'],  
 })。代码;  
 复制代码

VueTranspiler ,这里默认是vue2.0版本,核心依赖 vue 模板编译器 , vue-template-es2015-compiler .

将vue单文件组件转换为SFC对象:

 从 'vue-template-compiler' 导入 * 作为编译器;  
 从'vue-template-compiler'导入类型{SFCDescriptor};  
 ​​​  
 const sfc: SFCDescriptor = 编译器。 parseComponent(content, { pad: 'line' });  
 ​​​  
 复制代码

解析Vue模板部分的核心代码:

 从 'vue-template-compiler' 导入 * 作为编译器;  
 从'vue-template-es2015-compiler'导入转译;  
    
 函数 vueTemplateCompiler(html,选项){  
 const bubleOptions = 选项。气泡;  
 const vueOptions = 选项。 vue 选项 || {};  
 const userModules = vueOptions.编译器模块 ||选项。编译器模块;  
 const stripWith = bubleOptions.变换。带!==假;  
 常量 { stripWithFunctional } = bubleOptions。变换;  
 const staticRenderFns = 已编译。静态渲染Fns。地图((fn)=>  
 toFunction(fn, stripWithFunctional)  
 ); // 静态渲染函数放在数组中  
 const compilerOptions:编译器。 CompilerOptionsWithSourceRange = {  
 保留空白:选项。 preserveWhitespace, // 是否保留 HTML 标签之间的所有空白字符  
 模块:默认模块。 concat(userModules || []), // 自定义构建模板  
 指令:vueOptions。编译器指令 ||选项。编译器指令 || {}, // 自定义命令  
 评论:选项。 hasComment, // 是否保留评论  
 scopeId:选项。有作用域?选项。标识:空,/  
 };  
 常量编译 = 编译器。编译(html,编译器选项);  
    
 // 生成渲染函数和静态子树  
 让代码 = 转译(  
 'var 渲染 = ' +  
 toFunction(compiled.render, stripWithFunctional) +  
 '\n' +  
 'var staticRenderFns = [' +  
 静态渲染Fns。加入(',')+  
 ']') + '\n';  
 // 用剥离标记(这使 Vue 能够使用正确的运行时代理检测)  
 如果(带){  
 代码 += `render._withStripped = true\n`;  
 }  
 ​​​  
 常量导出=`{渲染:渲染,静态渲染Fns:静态渲染Fns}`;  
 代码 += `module.exports= ${ 出口 } `;  
    
 返回码;  
 }  
 ​​​  
 函数 toFunction(代码,stripWithFunctional){  
 return 'function (' + (stripWithFunctional ? '_h,_vm' : '') + ') {' + code + '}';  
 }  
 ​​​  
 复制代码

Vue 在渲染阶段将模板编译成 AST,然后根据 AST 生成渲染函数。底层通过调用render函数生成VNode来创建一个虚拟DOM。

预设模块

组件预设构建模板,针对不同的组件框架类型,如:Vue2、React等,预设该类型组件所需的默认组件 转译 模块。类似于 vue-cli,create-react-app。

核心方法:

  • 注册表转译器
  • 获取转译器`` 注册表转译器 作用是注册Transpiler模块。

部分伪代码:

 vue 预设。注册转译器(  
 ( 模块 ) => /.(m|c)?jsx?$/.测试(模块。路径),  
 [{ 转译器:babelTranspiler }]  
 );  
 vue 预设。注册转译器(  
 (模块)=> /.vue$/。测试(模块。路径),  
 [{ 转译器:vueTranspiler }]  
 );  
 复制代码

转译模块模块

即翻译后的模块维护翻译结果、代码执行结果和依赖模块信息,并负责驱动特定模块的翻译(调用Transpiler)和执行。

运行时模块

执行翻译后的模块入口,使用eval执行入口文件,如果遇到require函数,加载翻译后的依赖模块,然后使用eval执行。

核心代码:

 导出默认函数(代码:字符串,要求:函数,模块:{导出:任何},环境:对象= {},全局:对象= {},{ asUMD = false }:{ asUMD?:布尔} = {}) {  
 常量 { 出口 } = 模块;  
    
 const g = typeof window === 'undefined' ?自我:窗口;  
 常量全局 = g;  
 G。全球=全球;  
    
 // 兼容Node.js环境,部分列出  
 常量进程 = {  
 env: { NODE_ENV: '发展', ...env },  
 cwd: () => { return '/' },  
 umask: () => { 返回 0 }  
 };  
    
 // 全局变量  
 const allGlobals: { [ key: string]: any } = {  
 require, // 需要函数  
 模块,  
 出口,  
 过程,  
 全球的,  
 ...全局变量,  
 };  
 ​​​  
 //是否UMD模块  
 如果(asUMD){  
 删除所有全局变量。模块;  
 删除所有全局变量。出口;  
 删除所有全局变量。全球的;  
 }  
    
 常量 allGlobalKeys = 对象。键(所有全局);  
 const globalsCode = allGlobalKeys。长度 ?所有全局键。加入( ', ') : '';  
 const globalsValues = allGlobalKeys。地图( ( k ) => allGlobals[k]);  
    
 const newCode = `(function $csb$eval(` + globalsCode + `) {` + code + `\n})`;  
 (0,评估)(新代码)。应用(allGlobals.global, globalsValues);  
 ​​​  
 }  
 ​​​  
 复制代码

概括

从页面功能模块到组件构建的核心封装设计,相信大家已经初步了解了。有两点没有提到,这里简单补充一下。

第一点是依赖包的数据源。简单粗暴的一点就是创建一个manifest文件,并预存一份底层通用依赖包数据的副本,比如:babel插件相关等,如果需要动态添加依赖包,可以使用import -地图功能。

第二点是Transpiler模块没有提到react组件的构建方案,只是添加了相关的Babel插件,比如: 转换运行时 , @babel/plugin-transform-react-jsx-source 等待。

最后

有背景、需求、研究和计划四个层次。其中,背景和需求更多是从产品的角度考虑和设计。只有这样,事物才能更好地满足用户需求,提升用户体验。我们的技术人员不仅关心技术层面的设计,更经常从产品的角度思考。

组件是项目开发的一个组成部分。从基础组件到业务组件,我们的前端开发人员每天都在与组件打交道。我们可以有很多关于组件的话题,如何创建高质量的组件?如何提高组件的复用率?如何提高对组件的感知?等等,贯穿组件的整个生命周期,如何把组件管理好,需要我们的共同努力和思考。

参考

CodeSandbox 核心源码

CodeSandbox 的浏览器端 webpack 是如何工作的?

推荐阅读

NPM 包的规范升级

你想知道的前后端协作规范都在这里

带你了解摇树

锋利的!这个正则表达式写的这么详细

学习 HTTP 引荐来源网址

开源作品

  • Zhengcaiyun front-end tabloid

开源地址 www.zoo.team/openweekly/ (小报官网首页有微信交流群)

  • 产品选择sku插件

开源地址 github.com/zcy-inc/sku…

职业生涯

ZooTeam是一支年轻、充满激情、富有创造力的前端团队,隶属于正彩云产品研发部,基地位于风景如画的杭州。团队目前有90多名前端合伙人,平均年龄27岁,其中近40%是全栈工程师,妥妥的青年风暴群。成员由来自阿里、网易的“老兵”,以及浙江大学、中国科技大学、航电大学等学校的新生组成。除了日常业务对接,团队还在材料系统、工程平台、搭建平台、性能体验、云应用、数据分析与可视化等领域进行技术探索和实战,推动和实施了一系列内部技术产品。探索前端技术系统的新前沿。

如果你想改变,你已经被东西折腾了,希望开始折腾东西;如果你想改变,你被告知你需要更多的想法,但你不能打破游戏;如果你想改变,你有能力做到那个结果,但你不需要你;如果你想改变你想要完成的事情,你需要一个团队来支持,但没有地方让你带领人;如果要改变既定的节奏,那就是“5年工作时间,3年工作经验”;如果你想改变原来的感悟是好的,但总有那层窗纸的模糊……如果你相信信仰的力量,相信平凡的人可以成就不平凡的事情,相信他们可以遇到一个更好的自己。如果你想参与到业务腾飞的过程中,亲自推动一个业务理解深入、技术体系完善、技术创造价值、外溢影响力的前端团队的成长,我觉得应该讲话。随时,等你写东西,发给[ [电子邮件保护]](/cdn-cgi/l/email-protection)

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。

这篇文章的链接: https://homecpp.art/2621/9723/0756

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/38460/33592112

posted @ 2022-09-21 12:35  哈哈哈来了啊啊啊  阅读(148)  评论(0编辑  收藏  举报