前端人员在开发过程中,如何快速感知到组件的功能和属性?现状是通过阅读组件相关文档,好在基础组件库的文档相对完整和清晰,手动补全示例。业务组件相关文档目前只能在内部 NPM 私库上查看,静态的 API 文档,没有组件的 Demo。对于非前端人员,如何预览和调试组件呢?比如:某一天,产品想提前调研其它业务线的业务组件功能能否满足业务诉求;业务组件开发完成,测试和设计可以介入组件相关功能的验证;运营人员可以在低代码搭建平台,预览和调试相关组件等。
基于以上痛点问题,我们从需求点出发,逐步探索实现方案。
这里的低代码组件是指提供给低代码搭建平台使用的自定义组件,目前公司的低代码搭建平台主要有“鲁班”,对此感兴趣的小伙伴可以翻一下往期关于“鲁班”的文章。
针对组件 schema 调试,低代码组件本身自带 schema 文件,如:“鲁班”自定义组件会有一份 schema.json 文件,需要开发者去编写和维护这份文件。
如:
{
"props": {
"linkList": {
"group": "链接配置",
"title": "链接列表",
"type": "array",
"fields": [
{
"name": "imageAddress",
"title": "图链接图片地址",
"type": "string"
},
{
"name": "imageLink",
"title": "链接跳转地址",
"type": "string"
}
]
}
},
"models": {
"linkList": [
{
"imageAddress": "",
"imageLink": ""
},
{
"imageAddress": "",
"imageLink": ""
}
]
}
}
同样,业务组件也需要同一份 schema 协议的 JSON 文件,这样就可以动态调试组件的属性。但是,不会让开发组件的同学去手动编写。
自动生成 schema 文件大致思路:
大致画了下页面的结构图:
需求和应用场景已经很明确了,考虑到不同的用户群体,交互方式也有差别,重点是组件调试功能的差异性,对于研发人员可通过代码编辑器去修改代码达到调试效果,非研发人员则通过修改属性面板的组件属性值。而市面上的成熟产品会提供一些设计思路,具体实现方案下面会细讲。
从页面结构图,我们先聊下代码编辑器、组件属性面板、工具栏、预览区的设计方案。
目前主流的有两种:
两种代码编辑器都能满足我们的需求,在线修改一些组件 Demo 的部分代码,其实 Codemirror 够用了。
了解低代码搭建平台的朋友应该很熟悉了,其实就是通过表单去动态修改组件的属性参数,因此,需要一份通用的 schema 协议,来描述组件的自定义属性。可以由鲁班和大数据搭建平台那边提供 schema 数据,我们负责渲染即可。
大致列了下组件属性的类型和操作表单类型的对应关系:
工具栏包含的主要功能有:
上面实现的前提是需要一个代理服务,在本地开发环境我们可以用 http-proxy 插件创建本地代理服务,那么问题来了,在浏览器端如何做代理服务?
目前主流的方案都是通过 Chrome 插件形式,需要用户手动填写代理接口等信息。在我们的场景下,这个方案对用户体验显然不够友好。还有个方案可以利用浏览器的黑科技 —— Service Worker,它可以拦截网页发出的请求,并能自定义返回内容,相当于在浏览器内部实现了一个反向代理。
核心会涉及到两点:
通信时序图:
设计思路,主要参考了 CodeSandbox 的核心源码,主要涉及到代码转译和代码执行。核心模块有 Manger、Transpiler、Preset、Transpiled-module、Runtime。
架构图:
大致流程:
顾名思义“管理者“,即管理其它核心模块,主要负责代码转译和执行的一系列过程。
核心方法有:
addTranspiledModule
resolveTranspiledModuleSync
resolveTranspiledModuleAsync
evaluateTranspiledModule
首先将转译后的模块缓存起来放到 transpiledModules
对象 ,需要的话可以从缓存里同步或异步加载转译后的模块,如果需要执行转译的模块,可以调用 evaluateTranspiledModule
方法。transpiledModules
的类型定义:
type IModule = {
path: string;
url?: any;
code: string;
requires?: Array<string>;
parent?: Module;
};
interface ITranspiledModules {
[path: string]: {
module: IModule;
tModules: {
[query: string]: ITranspiledModule; // ITranspiledModule 类型定义放在 Transpiled-module 模块
};
};
}
类比 Webpack 的 loader,对指定类型的文件进行编译,如:Babel、Typescript、vue、tsx、jsx 等。
介绍下部分内置的 Transpiler 模块:
babelTranspiler
stylesTranspiler
rawTranspiler
noopTranspiler
vueTranspiler``rawTranspiler
跟 Webpack 的 raw-loader 作用一样,将模块的内容作为字符串导入,从而实现静态资源内联。实现原理也很简单:
module.exports = JSON.stringify(sourceCode)
babelTranspiler
这里实现了简化版,script 标签引入 bable-standalone.js,拿到全局对象 Babel。
部分核心代码:
import babelPluginRenameImports from './plugins/babel-plugin-rename-imports';
const transpiledCode = window.Babel.transform(code, {
plugins: [babelPluginRenameImports],
presets: ['es2015', 'es2016', 'es2017'],
}).code;
vueTranspiler
,这里默认是 vue2.0 版本,核心依赖了 vue-template-compiler
、vue-template-es2015-compiler
。
将 vue 单文件组件转换为 SFC 对象:
import * as compiler from 'vue-template-compiler';
import type {SFCDescriptor} from 'vue-template-compiler';
const sfc:SFCDescriptor = compiler.parseComponent(content, { pad: 'line' });
解析 Vue template 部分核心代码:
import * as compiler from 'vue-template-compiler';
import transpile from 'vue-template-es2015-compiler';
function vueTemplateCompiler(html, options) {
const bubleOptions = options.buble;
const vueOptions = options.vueOptions || {};
const userModules = vueOptions.compilerModules || options.compilerModules;
const stripWith = bubleOptions.transforms.stripWith !== false;
const { stripWithFunctional } = bubleOptions.transforms;
const staticRenderFns = compiled.staticRenderFns.map((fn) =>
toFunction(fn, stripWithFunctional)
); // 静态渲染函数放到数组中
const compilerOptions: compiler.CompilerOptionsWithSourceRange = {
preserveWhitespace: options.preserveWhitespace, // 是否保留 HTML 标记之间的所有空白字符
modules: defaultModules.concat(userModules || []), // 自定义编译模版
directives: vueOptions.compilerDirectives || options.compilerDirectives || {}, // 自定义指令
comments: options.hasComment, // 是否保留注释
scopeId: options.hasScoped ? options.id : null, /
};
const compiled = compiler.compile(html, compilerOptions);
// 生成渲染函数和静态子树
let code = transpile(
'var render = ' +
toFunction(compiled.render, stripWithFunctional) +
'\n' +
'var staticRenderFns = [' +
staticRenderFns.join(',') +
']') + '\n';
// mark with stripped (this enables Vue to use correct runtime proxy detection)
if (stripWith) {
code += `render._withStripped = true\n`;
}
const exports = `{ render: render, staticRenderFns: staticRenderFns }`;
code += `module.exports = ${exports}`;
return code;
}
function toFunction(code, stripWithFunctional) {
return 'function (' + (stripWithFunctional ? '_h,_vm' : '') + ') {' + code + '}';
}
Vue 在渲染阶段将模板编译为 AST,然后根据 AST 生成 render 函数,底层通过调用 render 函数会生成 VNode 创建虚拟 DOM。
组件预设构建模版,针对不同组件的框架类型,如:Vue2、React 等,预设默认该类型组件所需的 Transpiler
模块。类似于 vue-cli、create-react-app。
核心方法:
registerTranspiler
getTranspilers``registerTranspiler
作用是注册 Transpiler 模块。部分伪代码:
vuePreset.registerTranspiler(
(module) => /\.(m|c)?jsx?$/.test(module.path),
[{ transpiler: babelTranspiler }]
);
vuePreset.registerTranspiler(
(module) => /\.vue$/.test(module.path),
[{ transpiler: vueTranspiler }]
);
即转译后的模块,维护转译的结果、代码执行的结果、依赖的模块信息,负责驱动具体模块的转译(调用 Transpiler)和执行。
执行转译后的模块入口,使用 eval 执行入口文件,若遇到 require 函数,加载转译后的依赖模块然后使用 eval 执行执行。
核心代码:
export default function (
code: string,
require: Function,
module: { exports: any },
env: Object = {},
globals: Object = {},
{ asUMD = false }: { asUMD?: boolean } = {}
) {
const { exports } = module;
const g = typeof window === 'undefined' ? self : window;
const global = g;
g.global = global;
// 兼容 Node.js 环境,列举了一部分
const process = {
env: { NODE_ENV: 'development', ...env },
cwd: () => { return '/' },
umask: () => { return 0 }
};
// 全局变量
const allGlobals: { [key: string]: any } = {
require, // require 函数
module,
exports,
process,
global,
...globals,
};
// 是否 UMD 模块
if (asUMD) {
delete allGlobals.module;
delete allGlobals.exports;
delete allGlobals.global;
}
const allGlobalKeys = Object.keys(allGlobals);
const globalsCode = allGlobalKeys.length ? allGlobalKeys.join(', ') : '';
const globalsValues = allGlobalKeys.map((k) => allGlobals[k]);
const newCode = `(function $csb$eval(` + globalsCode + `) {` + code + `\\n})`;
(0, eval)(newCode).apply(allGlobals.global, globalsValues);
}
从页面功能模块到组件的构建核心包设计,相信各位看官已经有了初步的了解。有两点没有提到,在这里简单补充下。
第一点是依赖包的数据源问题,简单粗暴点就是创建 manifest 文件,事先预存一份底层通用的依赖包数据,如:Babel 插件相关等,如果需要动态添加依赖包,可以使用 import-maps 特性。
第二点在 Transpiler 模块没有提到针对 react 组件的构建方案,添加相关 Babel 插件就好了,如:transform-runtime
、@babel/plugin-transform-react-jsx-source
等。
背景、需求、调研、方案这四个层面,其中背景和需求更多是从产品的角度去思考和设计,这样做出来的东西才更符合用户需求和提升用户体验。我们技术人员不仅仅只关心技术层面的设计,更多时候还要从产品的角度去思考。
组件作为项目开发不可分割的一部分,从基础组件到业务组件,我们前端开发人员每天都在跟组件打交道。围绕着组件我们可以有很多专题,如何打造高质量组件?如何提升组件的复用率?如何提升组件的感知度?等等,贯穿组件的整个生命周期,那么如何治理好组件,需要我们共同努力和思考。
CodeSandbox 核心源码:https://github.com/codesandbox/codesandbox-client/tree/master/packages/sandpack-core
CodeSandbox 浏览器端的 webpack 是如何工作的?:https://www.yuque.com/wangxiangzhong/aob8up/nb1gp2
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/ydbuD9y8Uo-MZgOlxRZB0Q
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。