Whimsical开发第三个月总结

进度

本月比较刺激,全家老小都阳了,工作也是斗转星移,不过项目本来的计划没有太耽误。

  • 补充了主要功能的单元测试
  • 构建了基本的文档
  • å处理了一些运维问题å
  • 添加了monaco编辑
  • 增加了类型转为JSONSCHEMA的能力
  • 启动了数据绑定功能的开发
  • 重构了部分底层配置

原本的计划基本完成了,但是进度还是不快,随着新一年的到来,我会开始对结构树及数据绑定的你能力进行开发,希望能在2月份完成playground的上线。

一些心得

随着开发的深入,也发现了自己开发越来越多的问题,一边开发一边学习,也是我启动这个项目的目的。

TS类型定义

做项目之前整体的TS类型定义还比较基础,12月份的开发中发现自己类型会的那点东西完全不够用,从项目现有的代码也可以很清晰地看到这一点。

不过我现在正在通过https://github.com/type-challenges/type-challenges项目进行类型的联系,还是很有收获的,1月份我会对全局的类型进行一次重构,希望可以尽可能地弄透类型的使用。

JSONSchema

经过12月的开发,发现JSONSchema的应用范围还是挺广的。

  • DSL标准
  • monaco编辑器语法提示
  • JSON格式验证

因此后面我会对JSONSchema也加大理解的力度,这个和TS类型定义也是相辅相成的,现在JSONSchema和TS的类型是可以做到一定程度的互转的,而这个互转还不仅限于这两个技术,后面做各种工具和BFF的时候应该也用得到。

23年1月规划

过年月,还是想休息一下:)如上文所说,本月主要想在类型上多动动脑,争取分享个相关文章出来。

编辑器功能上,本月争取把数据绑定的交互写好,提前祝大家新年快乐。

Whimsical开发第二个月总结

进度

  • 新增功能
  • 产物的导出和内容的导入
  • 属性配置表单能力
  • 样式配置的模块
  • 表达式解析能力
  • 数据绑定能力及相关表达式
  • 画布自适应
  • 其他
  • 对工具包的功能进行了丰富
  • 补充部分单元测试
  • vite升级到4.0.0-beta.0版本(为了处理库打包多入口问题)
  • 引擎及组件库支持按需加载
  • 增加了性能比对工具

一些问题和思考

使用vite做支持按需加载的组件库

vite默认打包是单入口的,也就是在build.lib.entry里面只能穿一个字符串。

而支持按需加载主要是要将打包产物的内容进行分离,那这个vite也在不断做改进。

根据我现有项目的样本

  • vite2.x版本支持通过rollupOptions中的input来实现多入口分包,但是entry需要传''空字符串,来保证路径和命名符合预期。
  • vite3.2.x这个机制产生了变化,用2.x的配置进行打包会报错,因为entry不允许传''空字符串了,而在看源码的时候发现main分支已经进入到4.0.0-beta.0版本了
  • vite4.x在我使用的时候还没发布正式版,但是打包的时候build.lib.entry配置实现了rollupOptions.input相似的功能了,可以看代码段github.com/vitejs/vite…

属性配置能力选型formily

因为之前做相关建设就选用的formily,所以这次还是用了formily,但是没用全家桶,状态管理仍然使用了mobx,这里会有一些冗余,但不是当前的重点,后续再进行优化。

引擎解析性能比预计的好一些

这里测试性能的样本使用了深度为4,每个节点广度为10的全树总计10000个节点进行100次渲染的测试,下面可以看下结果。

从图中可以看出,还是多了一些解析代价的,毕竟要在运行时构建JSX接口再生成VNode,在上面的样本中有多接近10%的解析代价,在正常业务场景是可以接受的,而且这个解析思路也可以做到SSR上,那这个解析代价就会变得更小,这里还有很多细节,后面单独写文章说一下。

不过这不是最终的数据,后面随着功能的增加还会做增量的更复杂场景的对比,如:

  • 有大量表达式的时候
  • 打包文件和DSL文件因大小差异带来的优势和代价,从当前的用例来看,用DSL的包大小会比JSX打包出来的大小更大,这个跟我之前的预期是有差距的,但是这也是因为节点都是最简单的节点导致的。
  • 因状态变化带来的重新渲染的代价。

那就结而论,这个结果是比我预计要好的,在对性能要求没那么极致,但是对搭建有需求的场景,是很OK的。

12月规划

前面两个月的工作积累了一些功能,12月我会暂停新功能的开发,对项目补充单元测试和文档,争取一个月把现有的内容稳定下来。

Whimsical开发第一个月总结

进度

项目已经启动了一个月了,编辑器部分的整体进度在15%左右,进度不是很快,当前核心内容已经有了雏形,主要实现了一下功能:

  • 编辑器Layout
  • 事件调度
  • 历史快照
  • 画布分层
  • 属性配置联动
  • 设计了logo

演示

record-1m.2022-11-11 16_58_33.gif

一些技术选型

这里部分内容借鉴了formily的编辑器designable,属性配置联动部分的表单更是选用了formily进行驱动。

但是在事件调度和状态管理上方案有所不同

  • 状态管理:mobx
    • 使用mobx是为了降低项目维护的复杂度
    • mobx使用了严格模式,不允许直接通过赋值进行状态改变
  • 事件调度:rxjs
    • 当前使用rxjs是为了不去仔细考虑这里的设计,将重点放在整体框架上
    • 因为仅使用了rxjs中的subject,后续可能会对该部分进行重写
  • 拖拽系统使用了react-DND
    • 为了能更快速的开发,干脆对react-DND进行了汉化,当前是用到什么汉化什么,预计今年内会将文档全部汉化

这里没有详细写技术选型中的思考,如果有需要可以私信我,我可以多水一篇文章。

感想

项目启动至今,基本每天会抽1个小时左右写一点代码,从现在的心态上来看还OK,很充实。 中间有一段时间还有一些功利心作祟,想着无论如何要提交些什么,为了提交而提交, 现在就很释然了,尽力而为,心态放松后好像效率反而更高了。 总体来说,是个不错的尝试,当前除了时间比较少,还没有什么太大的瓶颈。

11月也会努力更新,期待感兴趣的同学和我交流。

项目地址:https://github.com/gaofeiyu/whimsical

我有一个Whimsical的项目启动了

I have a Whimsical project started

Whimsical[ˈwɪmzɪkl] 是异想天开的、古怪的、怪诞的意思,在我准备做这个项目之前并不认识这个单词,只是在想用什么作为项目名字的时候,想找个npm包中没有的名字,无意中碰到了这个词,而这个词意外地和我做这件事的目标和可执行性有些贴合,且为我要做的这件事的半途而废找到了一个很好的后路,就很完美。

我想做的东西是一个以低(零)代码编辑器为中心辐射出的一套工具包。面对这个时间点的低代码发展情况,这个赛道已经是一块让个人难以耕耘的盐碱地了,而我想做的不是一个低代码的整体平台,而是平台中每一块的零件,为低代码平台的整体架构进行解构,对页面编辑器、debugTools、设计稿自动解析、PRD自动解析、数据层等等方面输出针对的工具包和思路。

我做低代码相关的工作已经有较长一段时间了,在技术职场中,低代码是一个大多数人都用过,技术团队总想要,但又被团队十分嫌弃的一个课题。尤其是在重业务的团队,低代码相关的开发者在搞出惊天动地的结果之前,都是一直要被否定和挑战的。

不过这些困难和实践让我产生了更多的思考,于是我便启动这个项目,想将我的一些思考和实践,且跟现有工作不直接相关的内容提炼出来,期望能在更开放的平台学习和产出,解决一些低代码的通用问题。

对我的意义

这是一个从利己角度出发,产出利他结果的项目。

为什么是利己?

我是一个互联网某厂的码工,工作节奏快且充实,而长时间投入在业务和实操让我对技术最原始的驱动力变得懒惰和迟缓,简单讲就是生锈了。

我想通过这个项目来给自己一些强制的训练,复习以前的知识,并跟进新的知识,因此我在该项目中不会考虑兼容性的问题,会使用一些我感兴趣的技术栈和方案。

项目会尽可能以开源项目的思路进行一边学习一边建设,因为还有本职工作,原则上是有时间就多做点没时间就少做点,但不会不做,且有时也会为了我现有的工作当做试验场。

利他的结果是什么?

虽然这是以“我”为中心任性的项目,但是我仍然想要产出的内容有附加价值,在项目出现里程碑结果的时候,我也会进行一些运营,把我认为好的内容分享给社区,即使我的项目只是一个试错的炮灰。

比如该项目的第一个课题即是一个通用的低代码编辑器,这个通用的目标是可以融合任何技术栈的组件库的可拖拽低代码编辑器。因为个人当前的知识储备优先,因此第一阶段只面向web端,随着时间和阅历的推移,我会以整个大前端平台为目标进行学习和推进。

具体要做个什么东西

低代码是一个大课题,SaaS和aPaaS的低代码、流程图的低代码、页面搭建的低代码、低代码的上下游支撑,只从基本内容来看就能看出其建设成本之高往往让团队望而却步,这也是当前低代码相关建设被人主要诟病的原因,也是为什么很多大厂都在做低代码相关的付费服务。

如何将投入开发低代码的成本从逆差变成顺差,是每个相关开发团队需要解决的问题,这不免要进入鸡生蛋和蛋生鸡的扯皮循环。

那我想以我对低代码部分内容的理解,做出低代码整体建设中的零件,让相关团队在进行开发时少走一些弯路,或者可以直接使用我的部分成果为低代码的同僚们的KPI或OKR加把柴。

项目在当前主要涉及的内容包括:

主要内容

看到这里是不是觉得更加Whimsical了呢?

写在最后

我喜欢踢足球,但是不爱看球赛;我喜欢打dota,但是一个电竞选手都叫不出;我喜欢编程,但是已经很流行而我却不知道的技术和框架越来越多;我喜欢网上冲浪,但很少写文章,不知道看文章的你是不是像我一样,习惯把自己缩成一团。2022年里我接触了很多新东西,也尝试了不少,挫败感很多,但也总有新鲜的事物吸引我的注意力,而重要的是我舒展了自己,敢于去拥抱我自以为距离我很远的事物。

我想藉由这个项目,为我已经定型的脑袋敲出一些新花样,这篇文章可能短期不会有人能看到,但希望有那么一天会有人挖出这个文章来刺激一下未来的那个不争气的我,要么就不要异想天开,要么就坚持到底。

项目地址:https://github.com/gaofeiyu/whimsical

项目代码规范

接手的业务和团队走过了一段适应期,想要对团队的代码风格开始进行规范,在渐进落地后整理出一套比较通用的方案。

这里主要描述结论,选型和团队中方案PK的流程暂且先跳过,后面单独起一个专题讨论。

我的团队技术栈主要是React+TS,比较有针对性,因此请选择性食用。

下面的规范主要分美化和lint两个部分,且只讨论自动的部分,不讨论风格指南相关,那我们直接开始。

Lint

什么是Lint?

什么是Lint?

In computer programming, lint is a Unix utility that flags some suspicious and non-portable constructs (likely to be bugs) in C language source code; generically, lint or a linter is any tool that flags suspicious usage in software written in any computer language. The term lint-like behavior is sometimes applied to the process of flagging suspicious language usage. Lint-like tools generally perform static analysis of source code.

ESLint

lint的核心毫无疑问是eslint,但是eslint中用哪些plugin就比较有讲究了。

必须:

可选:

StyleLint

css出现bug的几率比较小,不太容易引起人们的重视,但其实css亦是组件质量的重要部分,在很多场景仍然要消耗大量的开发成本,因此有个好的写css习惯是非常重要的。

我们的项目中并没有严格采用BEM(窟窿比较多,这个优先级很低),因此为了让有好习惯的同学看其他人的代码不会太痛苦,就采用了StyleLint,StyleLint也是前端项目必备的Lint。

这里不需要太多的配置,在我们的项目中仅使用了stylelint-config-idiomatic-order插件来控制大家代码的css样式顺序。

美化

Prettier

团队中对使不使用Prettier有一些争议,不建议使用的主要观点是认为eslint可以cover这一块了,那针对这个疑问和一些其他疑问下面给了一些思考和解答:

module.exports = {
  // 行宽,即一行内容超过配置的数字会触发换行行为
  printWidth: 80,
  // 缩进数
  tabWidth: 2,
  // 缩进是否用tab,如果不是则用空格
  useTabs: false,
  // 行尾是否有分号
  semi: true,
  // 是否要使用单引号
  singleQuote: false,
  /**
   * 对象中的Key展示引号的规则
   * as-needed: 仅在必要时展示
   * consistent: 如果对象中有属性需要引号,那么就都要使用
   * preserve: 使用你本来的输入
   */
  quoteProps: 'as-needed',
  // jsx 是否使用单引号
  jsxSingleQuote: false,
  /**
   * 末尾逗号
   * es5: 在es5中的数组和对象增加尾随逗号,TS中的类型参数不会追加
   * none: 没有尾随逗号
   * all: 尽可能使用尾随逗号
   */
  trailingComma: 'es5',
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // 标签的尖括号是否要跟随到最后一行的末尾,而不是单独一行(不包括自闭合)
  bracketSameLine: false,
  /**
   * 箭头函数参数周围的括号
   * always: 始终需要括号
   * avoid: 尽可能省略括号
   */
  arrowParens: 'always',
  // 每个文件格式化的范围是文件的全部内容
  rangeStart: 0,
  rangeEnd: Infinity,
  // 是否需要在文件开头写 @prettier
  requirePragma: false,
  // 是否在文件开头插入 @prettier
  insertPragma: false,
  /**
   * 折行方式
   * always: 超过print width则换行
   * never: 每个文本块为一行
   * preserve: 保持输入的原样
   */
  proseWrap: 'preserve',
  /**
   * HTML的空白换行敏感度
   * css: 根据css的标准进行换行
   * strict: 所有标签周围的空格都会造成换行
   * ignore: 所有标签周围的空格都忽略
   */
  htmlWhitespaceSensitivity: 'css',
  /**
   * 换行符
   * lf: \n mac or linux or git repos
   * crlf: \r\n windows
   * cr: \r 不太常用
   * auto: 保持现有的换行
   */
  endOfLine: 'lf',
  // 是否强制每行单个属性
  singleAttributePerLine: false
};
  • 和其他lint配合使用,值得一提的是,配合使用的方式就是将prettier的配置整合到对应lint中,也就是说不使用prettier也将是一种可能。

工作流相关工具

除了增加lint和美化的配置来让辅助让代码符合规范,为了让代码更确切的能达到规范的目的,我们还希望可以在提交代码的时候进行一次自动验证并进行fix,因此还需要一些其他的工具。

Lint-staged

在代码提交前进行lint,以此来强制仓库的代码格式,这个lint是对当前提交增量的文件进行lint的,官网:https://github.com/okonet/lint-staged

// package.json 
{
  // ... other config
  "lint-staged": {
    "**/*": "prettier --write --ignore-unknown", //格式化
    "src/**.{js,jsx,ts,tsx}": "eslint --ext .js,.jsx,.ts,.tsx", //对js文件检测
    "**/*.{less,css}": "stylelint --fix" //对css文件进行检测
  }
}

Husky

在git执行的生命周期钩子中追加能力,官网:https://typicode.github.io/husky/#/

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo $PATH
npm run test
  • 命令输出后 会展示当前的环境变量,如果命令找不到说明命令不在环境变量中

CommitLint

对提交的commit的message进行lint,官网:https://commitlint.js.org/#/

如果自己不会写,或者想增加更规范化的提交消息,可以再增加个Commitizen

commitlint相关包的依赖关系

其他工具

koroFileHeader

https://github.com/OBKoro1/koro1FileHeader.git

这是一个中国开发者制作的VSCode的插件,用来自动往文件头部写文件被操作的信息的,非常实用。

支持很多自定义配置,我现在使用这个工具主要记录文件创建者+创建时间+文件最后修改者+修改时间信息。

页面FPS分析

chrome现在有一个高大上的fps观测工具,你可以不用再去分析performance面板的跑分了。

开启FPS工具

方法一

打开devTools,如果你是mac请按组合键 commend + shift + p (win系统自行翻译),然后再搜索框中输入fps,你会看到如下的状态。

选择第一个结果回车即可

方法二

在更多工具的Rendering面板下面,选中“Frame Rendering Stats”即可

这个工具有个缺点是位置不能移动。

根据工具分析FPS

看下面这张图就够了

总结来说就是:

  • 左上角的百分比越高越好
  • 红色块越少越好
  • 红色块越均匀越好

参考资料:

chrome工具之performance面板

前言

你可以通过performance标签下面的learn more,

或者直接跳转

来学习官方的教程。

这里对重点部分做一个摘要来方便你的快速使用。

生成性能数据

1、在DevTools中,单击记录 。当页面运行时,DevTools捕获性能指标。

2、等待一段时间,期间可以执行一些自己想要检测的操作

3、点击红点或者点击stop停止录制查看结果

简单分析数据

官方已经写得很通俗易懂了不需要再概括了,请直接看官方文档

https://developer.chrome.com/docs/devtools/evaluate-performance/reference/

文中也给了一些优化建议,有兴趣也可以看看。

注:教程中fps分析部分已经过时这里可以查看页面FPS分析

前端主要性能的相关指标

这里主要以谷歌的技术文章为依据,此处主要是对参考文章的总结和摘要。

https://web.dev/metrics/ 中已经有更细节的指标描述,而且做了中文版本的翻译,方便大家更好的学习和参考。

定义指标

为了确保用户体验,我们通常围绕以下问题来进行性能的相关优化:

Is it happening?发生了么Did the navigation start successfully? Has the server responded?导航是否成功启动?服务器响应了吗?
Is it useful?是有用的么Has enough content rendered that users can engage with it?是否渲染了足够的内容给用户?
Is it usable?可以使用了么Can users interact with the page, or is it busy?用户可以与页面进行交互,还是页面仍在忙碌中?
Is it delightful?流畅么Are the interactions smooth and natural, free of lag and jank?交互是否流畅,没有延迟和卡顿?

如何度量

  • 通过实验环境进行测试
  • 通过实际生产环境进行测试

指标类型

  • 感知的加载速度:页面加载并将其所有可视元素呈现到屏幕的速度。
  • 加载响应度:页面加载和执行任何必需的JavaScript代码以使组件快速响应用户交互的速度
  • 运行时响应性:页面加载后,页面对用户交互的响应速度有多快。
  • 视觉稳定性:页面上的元素是否会造成用户不期望的方式移动,并可能干扰他们的交互?
  • 平滑度:过渡和动画是否以一致的帧速率渲染并从一种状态流畅地流动到另一种状态?

重要的衡量指标

  • First contentful paint (FCP): measures the time from when the page starts loading to when any part of the page’s content is rendered on the screen. (labfield)
    • 第一个内容的绘制:测量从页面开始加载到屏幕上呈现页面内容的任意部分的时间。
  • Largest contentful paint (LCP): measures the time from when the page starts loading to when the largest text block or image element is rendered on the screen. (labfield)
    • 最大内容的绘制:测量从页面开始加载到屏幕上最大的文本块或图像元素被渲染的时间。
  • First input delay (FID): measures the time from when a user first interacts with your site (i.e. when they click a link, tap a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to respond to that interaction. (field)
    • 首次输入的延迟:测量从用户第一次与您的站点交互(即,当他们单击链接、点击按钮或使用自定义的、JavaScript驱动的控件)到浏览器实际能够响应该交互的时间。
  • Time to Interactive (TTI): measures the time from when the page starts loading to when it’s visually rendered, its initial scripts (if any) have loaded, and it’s capable of reliably responding to user input quickly. (lab)
    • 互动时间:衡量从页面开始加载到可视化呈现之间,它的初始脚本(如果有)已加载以及可以可靠快速地响应用户输入的时间。
  • Total blocking time (TBT): measures the total amount of time between FCP and TTI where the main thread was blocked for long enough to prevent input responsiveness. (lab)
    • 总阻塞时间:测量FCP和TTI之间的总时间。如果主线程被阻塞的时间足够长,会阻止输入响应。
  • Cumulative layout shift (CLS): measures the cumulative score of all unexpected layout shifts that occur between when the page starts loading and when its lifecycle state changes to hidden. (labfield)
    • 累积布局偏移:衡量在页面开始加载到页面生命周期状态 变为隐藏之间发生的所有意外布局转移的累积分数。
    • 这个性能分数和其他指标不太一样,该指标依赖视觉及交互相关的设计
    • 计算公式:layout shift score = impact fraction * distance fraction
  • Frames Per Second(FPS): 是指画面每秒传输帧数
该处的内容会有一个专题来描述每个指标具体怎么看。

指标的参考值

注意参考值中的“参考”,表示以下标准适用于大多数场景,但具体情况仍需要具体分析,不可一概而论。

  • FCP:1秒内
    • To provide a good user experience, sites should strive to have First Contentful Paint occur within 1 second of the page starting to load. To ensure you’re hitting this target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.
  • LCP:2.5秒内
    • To provide a good user experience, sites should strive to have Largest Contentful Paint occur within the first 2.5 seconds of the page starting to load. To ensure you’re hitting this target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.
  • FID:100毫秒以内
    • To provide a good user experience, sites should strive to have a First Input Delay of less than 100 milliseconds. To ensure you’re hitting this target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.
  • TTI:5秒内
    • To provide a good user experience, sites should strive to have a Time to Interactive of less than 5 seconds when tested on average mobile hardware.
  • TBT:300毫秒以内
    • To provide a good user experience, sites should strive to have a Total Blocking Time of less than 300 milliseconds when tested on average mobile hardware.
  • CLS:分数小于0.1
    • To provide a good user experience, sites should strive to have a CLS score of less than 0.1. To ensure you’re hitting this target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.
  • FPS: (注:该数据没有找到十分权威的来源,如果你有更权威的来源可以@feiyugao进行补充)
    • 在网页中,帧率能够达到50~60fps的动画将会相当流畅,让人倍感舒适。
    • 帧率在30~50fps之间的动画,因各人敏感程度不同,舒适度因人而异。
    • 帧率在30fps以下的动画,让人感觉到明显的卡顿和不适感。
    • 帧率波动很大的动画,亦会使人感觉到卡顿。

参考资料

前端第三方登录授权策略专题

最近项目中关于授权登录的内容比较多,涉及的同学比较多,但是大家的知识点有些参差不齐,这边的专题科普一下相关点,并抛出一个我关注的iframe中的第三方页面登录态问题

先从什么是SSO单点登录开始

Single Sign-On,简单说就是一次访问,多处可用。

了解SSO之前,我们也可以了解一下CAS( Central Authentication Service ),来帮助我们跟深入的了解这个能力的背景:https://developer.ibm.com/zh/articles/os-cn-cas/

从官方文档总结来看,基础模式的SSO流程主要有以下步骤:

  1. 访问服务: SSO 客户端发送请求访问应用系统提供的服务资源。
  2. 定向认证: SSO 客户端会重定向用户请求到 SSO 服务器。
  3. 用户认证:用户身份认证。
  4. 发放票据: SSO 服务器会产生一个随机的 Service Ticket 。
  5. 验证票据: SSO 服务器验证票据 Service Ticket 的合法性,验证通过后,允许客户端访问服务。
  6. 传输用户信息: SSO 服务器验证票据通过后,传输用户认证结果信息给客户端。

那是不是还有多点登录

多点登录用一句话概括是,一个账号可以在多个端登录,但是每个端只能有一个该账号的登录实例。

IM是典型的多点登录应用。

多点登录一般不用于第三方登录,这里不做讨论。

Oauth2.0授权

第三方单点登录主要目的是授权,Oauth2.0,是现在最为推荐使用的授权机制。

入门:http://www.ruanyifeng.com/blog/2019/04/oauth_design.html

进阶:https://tools.ietf.org/html/rfc6749

既然有2.0,那就也有1.0,想要了解历史可以看下面的文章

入门:https://sexywp.com/oauth-1-intro.htm

进阶:http://oauth.net/core/1.0/