关于前端:zonejs由入门到放弃之五NgZone-ApplicationRef源码分析

31次阅读

共计 13769 个字符,预计需要花费 35 分钟才能阅读完成。

啸达同学刚写 zone.js 系列就说过,NgZone 影响着 Angular 中的变更检测,历时一个多月的笔耕不辍,终于到了他首次下笔时的目的地~

zone.js 系列

  • zone.js 由入门到放弃之一——通过一场游戏意识 zone.js
  • zone.js 由入门到放弃之二——zone.js API 大练兵
  • zone.js 由入门到放弃之三——zone.js 源码剖析【setTimeout 篇】
  • zone.js 由入门到放弃之四——Angular 对 zone.js 的利用

初见 NgZone

其实在上一篇文章中,大家曾经初步窥探过 NgZone 的芳容了。而且咱们也晓得了,在 NgZone 中保护了 OuterZone 和 InnerZone 两个 Zone。明天的这篇文章,咱们次要剖析一下 InnerZone,并看一下 InnerZone 是如何跟 Angular 的变更检测分割到一起的。

InnerZone 四办法

NgZone 中 InnerZone 的创立是通过 forkInnerZoneWithAngularBehavior 实现的,创立过程的简化版如下,其中又能看到很多相熟的勾子函数。这里简略温习一下这几个勾子的意义:

  • onInvokeTask:zone.js 会在初始化的时候将异步办法都 Pathc 成 ZoneTask,从而跟踪异步工作的执行状况的。onInvokeTask就是其中的一个勾子函数,它会在异步工作执行回调的时候触发。
  • onInvokeonInvoke会在咱们手动执行 zone.run()的时候执行。
  • onHasTask:是针对整个工作队列状态扭转的监听,当检测工作队列中有工作进入、或是有工作执行完出队列的时候会被执行。
  • onHandleError:当有异样抛出时被执行

InnerZone 对异步工作的管制精髓基本上就全副稀释在这几个勾子函数中了,与此同时,为了更好地配合对异步工作的跟踪,NgZone 中还定义了很多状态监控字段。只有理清这些字段的含意能力持续往下深刻代码。

不相熟 zone.js 原理的能够回看一下 zone.js 由入门到放弃之一和 zone.js 由入门到放弃之二(链接见文首)

传送门

function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
  zone._inner = zone._inner.fork({
    name: 'angular',
    properties: <any>{'isAngularZone': true},
    onInvokeTask: (...): any => {...},
    onInvoke: (...): any => {...},
    onHasTask: (...): any => {...},
    onHandleError: (...): any => {...},
  });
}

InnerZone 五状态

接下来这几个状态属性会贯通在前面的源码剖析的全副过程中,咱们也会通过对这几个状态的跟踪理解一下 InnerZone 事件跟踪的原理。

  • hasPendingMacrotasks: boolean 队列中是否有待执行的宏工作
  • hasPendingMicrotasks: boolean 队列中是否有待执行的微工作
  • _nesting: number 队列中待执行工作的个数
  • isStable: boolean 当工作队列中既没有待执行的宏工作,也没有待执行的微工作时,isStable 为 ture,示意以后是个稳固的状态。反之则代表非稳固状态。
  • lastRequestAnimationFrameId: number 这个状态有些特地,它是一个延时器,前面会开展解释。

代码走读

后面在介绍 zone.js 的时候咱们说过,zone.js 把异步工作分为 MacroTask、MicroTask 和 Event 三种。明天咱们就别离把这三种工作都按流程剖析一遍。从难易水平上看,MacroTask 最简略,Event 绝对最简单。接下来,咱们就依照这个程序解说。

MacroTask

之前在 zone.js 由入门到放弃之三中,具体介绍过 zone.js 对 setTimeout 的 Patch 过程,如果不理解具体过程的强烈建议先浏览一下那篇文章。

这一次,咱们还是通过个 setTimeout 事件来跟踪 NgZone 的处理过程,测试代码很简略,如下所示。

export class AppComponent implements OnInit {
  title = 'ngzone-process';

  ngOnInit(): void {setTimeout(() => {console.log('[setTimeout] run in next 5s');
    }, 5000);
  }

  ngDoCheck() {console.log('rendering...');
  }

}

因为 zone.js 能够感知到工作队列的变动状况,所以当 setTimeout 执行时,它能够晓得以后有一个宏工作来了,同时会触发 onHasTask 勾子。

onHasTask

onHasTask“ 检测 ” 到有宏工作到来时,会把hasPendingMacrotasks 设置为 true。

传送门

onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {delegate.hasTask(target, hasTaskState);
  if (current === target) {// ...} else if (hasTaskState.change == 'macroTask') {zone.hasPendingMacrotasks = hasTaskState.macroTask;}
  }
},

此时,NgZone 中的几个状态值大略是这个样子的,hasPendingMacrotasks 变为 true,示意以后有一个待执行的 MacroTask。

接下来,zone.js 会通过调用scheduleFn,并把封装后的回调函数放在 Timer 队列中期待时钟达到。

hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
true false 0 true -1
onInvokeTask

过后钟达到当前,事件循环会把封装后的回调函数放在工作队列中期待执行。当执行到回调时,回调会触发 task.invoke 函数,接下来就会唤醒 onInvokeTask 勾子函数。

传送门

onInvokeTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
 applyArgs: any): any => {
  try {onEnter(zone);
    // 执行真正的回调 👇
    return delegate.invokeTask(target, task, applyThis, applyArgs);
  } finally {
    // ...
    onLeave(zone);
  }
},

delegate.invokeTask(target, task, applyThis, applyArgs);是用来调用真正的回调函数的。除了这行,咱们能够看到在回调之前先后别离还各有一个办法:onEnteronLeave

onEnter

onEnter执行过程中,_nesting会自增,示意了以后新增一个待执行工作。当有工作要执行时,之前的稳固状态会被突破,同时触发一个 onUnstable 事件。这个 onUnstable 事件被 ApplicationRef 订阅,ApplicationRef 会依据这个事件同步批改它本身的稳固状态(ApplicationRef 的代码前面解说)。

传送门

function onEnter(zone: NgZonePrivate) {
  zone._nesting++;
  if (zone.isStable) {
    zone.isStable = false;
    zone.onUnstable.emit(null);
  }
}
hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
true false 1 false -1
onLeave

onLeave函数执行的时候,阐明 MarcoTask 的回调曾经执行结束,_nesting会执行一次自减操作。接下来又执行了 checkStable 函数。

传送门

function onLeave(zone: NgZonePrivate) {
  zone._nesting--;
  checkStable(zone);
}

checkStable函数十分要害!每当执行到 checkStable 的时候,都是变更检测执行的要害。以至于这个函数的每一行都值得拿出来讲一下,我在代码中标记了序号,这样不便前面走读代码。

  1. checkStable既然是判断是否进行变更检测要害,那么 1 标识的 if 子句就是判断的要害。代码的意思大略就是,只有确保以后没有任何待执行的工作,同时以后状态为不稳固状态的时候才须要触发变更检测。
  2. 代码 2 标识了一个成对的 _nesting 自增、自减操作。这里这么做的起因是代码 3 这里抛出了事件,对该事件的订阅实际上也是一个异步工作。所以这里通过 _nesting 的自增、自减操作阐明这里是有一个异步工作的。
  3. 代码 3 就是变更检测的要害了,AppliactionRef 会订阅 onMicrotaskEmpty 事件,每当 onMicrotaskEmpty 触发后,AppliactionRef 就会执行一次变更检测。
  4. 代码 4 这里大家可能会有疑难,为什么在这里还要对 hasPendingMicrotasks 进行一次判断?这是因为在代码 3 这里,对 onMicrotaskEmpty 的订阅者有可能会在订阅回调中再执行一些异步工作,就像上面这样。此时,并不能保障在 checkStable 的过程中,不会有新的工作进入到待执行队列。所以这里,又对 hasPendingMicrotasks 的状态做了一次判断。确保在状态变为稳固之前,工作队列中不存在工作微工作。
zone.onMicrotaskEmpty.subscribe(() => {Promise.resolve(0).then(console.log);
});
  1. 代码 5 是对外触发一个状态稳固的事件,这个事件跟 OnEnter 函数中那个 onUnstable 绝对。然而你可能会好奇,这里为什么要在 runOutsideAngular 中执行。我这里解释下,仅代表个人见解。onStableonMicrotaskEmpty 存在一样的问题,因为都是可察看对象,所以存在订阅者在回调继续执行异步工作的问题。如果在 onStable 的订阅中执行异步工作,那 NgZone 的状态马上有会变成非稳固的,这将会陷入一个有限的死循环中,NgZone 会在稳固和不稳固状态之间来回切换,永不进行。所以这里应用 runOutsideAngular,让 zone.js 放弃对这里的代码进行跟踪。这样,依据上一讲咱们学过的内容,runOutsideAngular 中执行异步不会触发变更检测,当然也不会触发 NgZone 的状态变动。
  2. 扭转 zone 的状态为稳固。

传送门

function checkStable(zone: NgZonePrivate) {
  // 👇 1
  if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
    try {
      // 👇 2
      zone._nesting++;
      // 👇 3
      zone.onMicrotaskEmpty.emit(null);
    } finally {
      // 👇 2
      zone._nesting--;
      // 👇 4
      if (!zone.hasPendingMicrotasks) {
        try {
          // 👇 5
          zone.runOutsideAngular(() => zone.onStable.emit(null));
        } finally {
          // 👇 6
          zone.isStable = true;
        }
      }
    }
  }
}

这里我多补充一点常识,我之前看到这里的代码的时候也感觉有点绕,所以我在这里做了大量的测试。后果发现,如果在 onStable 的订阅回调中再应用 zone.run 执行异步工作的时候就会造成一个有限的死循环。这里是我的最小实现仓,够胆的能够试试,你的浏览器会在霎时解体。当然,我也给官网提了 issue,原作者也证实了这确实是个问题,感兴趣的能够跟踪一下,继续关注。

截止到这里,咱们再看一下 NgZone 的几个状态指标。此时队列中不存在待执行的工作,NgZone 会把本身状态批改为稳固态。

hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
true false 0 true -1
onHasTask

整个 setTimeout 跟踪的最初一步还是这个勾子,这次,勾子函数中会把 hasPendingMacrotasks 置为 false。此时,几个状态曾经复原为最后的问题状态,Angular 也在这个过程中执行了一次变更监测。

hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false false 0 true -1

MicroTask

MicroTask 和 MacroTask 的行为大抵上统一,只不过因为 zone.js 在解决 MicroTask 和 MacroTask 时有一丢丢的区别,导致这里解决也会有一点不同,这个我会在下文做专门解释。当然,如果你还想关注 zone.js 在解决 MicroTask 和 MacroTask 时到底有什么不一样的,能够关注一下我的下一篇文章(如果有的话),外面会像本系列的第三期一样,具体解释 zone.js 解决 Promise 的技术细节。

onHasTask

onHasTask 跟之前没什么区别,执行过后,状态如下。与 MacroTask 不同,这次是 hasPendingMicrotasks 变为 true,示意队列中有一个待执行的微工作。

传送门

onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {delegate.hasTask(target, hasTaskState);
  if (current === target) {if (hasTaskState.change == 'microTask') {
     zone._hasPendingMicrotasks = hasTaskState.microTask;
     // ...
   }
   // ...
  }
},
hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false true 0 true -1
onInvokeTask

MicroTask 和 MacroTask 在这个勾子中的处理过程基本上是雷同的。然而 MicroTask 在回调执行的时候和 MacroTask 还是有一点差别的。后面局部,咱们讲 MacroTask 的时候,delegate.invokeTask(target, task, applyThis, applyArgs);这句会间接触发 setTimeout 的回调函数执行。然而在 MicroTask 中,微工作的回调内部还会包装一层 zone.run,导致 MicroTask 的回调会通过onInvoke 勾子执行。

传送门

onInvokeTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
 applyArgs: any): any => {
  try {onEnter(zone);
    // 执行真正的回调 👇
    return delegate.invokeTask(target, task, applyThis, applyArgs);
  } finally {
    // ...
    onLeave(zone);
  }
},
onInvoke

能够看到 onInvokeonInvokeTask函数的内容是差不多的。onEnteronLeave 的调用也基本一致,所以这里就不专门剖析了。

onInvoke:
(delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function, applyThis: any,
 applyArgs?: any[], source?: string): any => {
  try {onEnter(zone);
    return delegate.invoke(target, callback, applyThis, applyArgs, source);
  } finally {onLeave(zone);
  }
},

当这个函数执行完结后,几个状态值变动如下。

hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false true 0 true -1
onHasTask

最初一个执行的还是 onHasTask 函数,这个函数执行结束后,几个状态又回到初始状态。

hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false false 0 true -1

Event

Event 的执行形式跟 MacroTask 和 MicroTask 都不太一样。还记得之前咱们在讲 NgZone 的 5 大状态的时候,有一个 lastRequestAnimationFrameId 始终没有用到。那么,在 Event 的处理过程中,咱们会看到它的作用。

onInvokeTask

Event 的解决入口是 onInvokeTask 而不是 onHasTaskonEnterdelegate.invokeTask与之前都差不多,然而在 finally 子句中,你会发现 Event 的解决中多了一个 delayChangeDetectionForEventsDelegate 函数。其实从函数的函数名大略能猜个七七八八,这个是一个事件延时解决的函数。

onInvokeTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
 applyArgs: any): any => {
  try {onEnter(zone);
    return delegate.invokeTask(target, task, applyThis, applyArgs);
  } finally {if ((zone.shouldCoalesceEventChangeDetection && task.type === 'eventTask') ||
        zone.shouldCoalesceRunChangeDetection) {
      // Event 的非凡解决逻辑 👇
      delayChangeDetectionForEventsDelegate();}
    onLeave(zone);
  }
},
delayChangeDetectionForEventsDelegate

其实咱们在上一期解说中曾经介绍了一些通过 NgZone 进行性能调优的伎俩,那么这个函数的产生实际上也是用于性能上的优化。咱们晓得,浏览器很多事件诸如 mousemove、scroll 这些都会在短时间内产生大量的事件。如果每个这样的事件都会触发一次 Angular 的变更检测的话,那么对性能上的要求是很大的。所以,NgZone 也须要在外部对于这些浏览器的事件做一些非凡解决,让大量的事件积攒一段时间后再对立做一次变更检测。

那么 delayChangeDetectionForEventsDelegate 中理论调用的办法是 delayChangeDetectionForEvents,所以咱们重点关注一下delayChangeDetectionForEvents 函数的源码。

  1. 代码 1 这里,咱们第一次见到对 lastRequestAnimationFrameId 的判断,当第一个 Event 到来时,这里的 lastRequestAnimationFrameId 还是初始值 -1
hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false false 1 false -1
  1. zone.nativeRequestAnimationFrame的调用实际上调用的是 Window.requestAnimationFrame。这里,NgZone 实际上是心愿通过requestAnimationFrame 收集这一帧内的所有事件,在这一帧完结后,再对立执行一次变更检测。requestAnimationFrame执行的返回值会赋值给lastRequestAnimationFrameId,这样,在接下来代码每次进入到代码 1 处的时候,函数会间接返回。
  2. updateMicroTaskStatus被用来更新微工作状态的。那么这里执行之后,状态值中的 hasPendingMicrotasks 会变为 true。这里这么做是为了收集 Event 的时候能够阻塞微工作触发变更检测,这么做的起因是为了确保 Event 事件的执行程序不会被微工作打乱。这里要具体介绍又会有很大篇幅,感兴趣的能够本人看下这个 issue;不想关注的能够先跳过这里。
hasPendingMacrotasks hasPendingMicrotasks _nesting isStable lastRequestAnimationFrameId
false true 1 false 一个正整数返回值
  1. 当以后帧执行结束、下一帧要执行的时候会调用一次 checkStable 函数。这个函数在后面讲过,它是触发 Angular 变更检测的要害。通过执行该办法,Angular 会通过 ApplicationRef 执行变更检测动作。

传送门

function delayChangeDetectionForEvents(zone: NgZonePrivate) {
  // 👇 1
  if (zone.isCheckStableRunning || zone.lastRequestAnimationFrameId !== -1) {return;}
  
  // 👇 2
  zone.lastRequestAnimationFrameId = zone.nativeRequestAnimationFrame.call(global, () => {if (!zone.fakeTopEventTask) {zone.fakeTopEventTask = Zone.root.scheduleEventTask('fakeTopEventTask', () => {
        zone.lastRequestAnimationFrameId = -1;
        updateMicroTaskStatus(zone);
        zone.isCheckStableRunning = true;
        // 👇 4
        checkStable(zone);
        zone.isCheckStableRunning = false;
      }, undefined, () => {}, () => {});
    }
    zone.fakeTopEventTask.invoke();});
  // 👇 3
  updateMicroTaskStatus(zone);
}

再见 ApplicationRef

上一节中,咱们讲过一点 ApplicationRef 相干的常识,这一次,咱们重点看下 ApplicationRef 跟变更检测相干的代码。

变更检测

后面说到,NgZone 在 checkStable 中,如果发现以后曾经没有待执行的工作的时候,会触发一个 onMicrotaskEmpty 事件。在这里,这个事件会被 ApplicationRef 所捕捉。捕捉后,会执行ApplicationRef.tick,而这个 tick 就是变更检测的入口。

传送门

this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({next: () => {this._zone.run(() => {this.tick();
    });
  },
});
tick

tick 办法中,咱们能够看到 ApplicationRef 通过调用视图的 detectChanges 办法,让组件实现自上而下的变更检测。上一篇文章中,咱们介绍过一些手动执行变更检测的办法,其中有提到过 ChangeDetectorRef.detectChanges() 这个办法。这个办法能够对以后组件以及以后组件的子组件进行进行变更检测。那么这里看到的 view.detectChanges()ChangeDetectorRef.detectChanges()又有什么关系?

其实从 _views 类型的继承链能够发现,_views的类型 InternalViewRef 继承自 ViewRefViewRef 又继承自 ChangeDetectorRef。所以调用view.detectChanges() 就相当于调用了ChangeDetectorRef.detectChanges(),从而实现一次自上而下的变更检测。

传送门

tick(): void {
  // ...
  try {
    this._runningTick = true;
    for (let view of this._views) {
      // 👇 组件的变更检测
      view.detectChanges();}
    if (typeof ngDevMode === 'undefined' || ngDevMode) {for (let view of this._views) {view.checkNoChanges();
      }
    }
  } catch (e) {
    // Attention: Don't rethrow as it could cancel subscriptions to Observables!
    this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
  } finally {this._runningTick = false;}
}

以上就是 NgZone 和 ApplicationRef 之间的配合关系。咱们整体再回顾一下整个系列课程的内容。zone.js 通过 Monkey Patch 对所有异步办法进行打包;打包后的异步办法被植入了很多勾子函数,而这些勾子函数能够被 zone.js 的上下文检测到,从而实现对异步工作的监控。

NgZone 是对 zone.js 的一个应用案例,NgZone 通过保护 InnerZone 和 OuterZone 两个 Zone 实现了对 Angular 利用中的异步工作的监控和去监控。NgZone 同时在外部也保护了几个对异步工作监控的状态信息,通过这些信息实现了和 ApplicationRef 之间的“通信”,最终由 ApplicationRef 实现对 Angular 利用的监控。

本文小结

到这里,明天的内容就介绍的差不多了。最初,这里还须要像读者阐明一点,在 NgZone 中跟踪 Task 的运行是一件比拟难的事件,本文所有这些 Task 的举例其实都是理想化的。比如说,在举例 setTimeout 的时候,你会发现当你想在 Angular 利用中对异步 Task 跟踪的时候,会有很多其它 Task 同时在执行着,这些 Task 常常会在你调试跟踪的时候对你造成“烦扰”。所以,本文的这些举例只是心愿让大家看过后,能大抵对每种不同工作在 NgZone 中流程有个意识,而实在的过程会远比我明天讲的内容简单的多。这同时也从侧面反映出,zone.js 默默对 Angular 作出多大的奉献。

大完结

本系列分享历时将近 1 个多月,加上后期的一些剖析和总结,我集体大略继续关注 zone.js 有两个多月了。最初的最初,我也分享几点集体感触:

  1. 有人说 zone.js 是暴力美学,我个人感觉可能美的中央更多一些吧。作为 Angular 变更检测的外围,Angular 的变更检测在三大框架中是独一份的存在。我感觉比起其它两个通过数据劫持和虚构 Dom 的形式进行数据绑定的形式,zone.js 显得还是要温顺一些的。毕竟数据劫持是间接“净化”了数据的,而 zone.js“革新”的是工具。我没法说谁更好,只是集体更偏差于后者。
  2. 截止到当初,我集体也没有齐全看完 zone.js 的源码,然而我心愿我会在后续的工作中继续关注这个产品。同时我也看到 JiaLi(zone.js 作者)为了他的作品一直地对 zone.js 进行改良。所以,请他加油,我心愿 zone.js 能够越来越好!不过话说回来,JiaLi 想在 Angular 社区实现一个 PR 是不是太难了点啊。我看了他好多的批改,常常要等良久能力审核通过,有点疼爱他。🤣
  3. 其实最开始的时候,我只是想本人学学 zone.js 的,并没有布局这个系列分享。然而,我在学习源码的时候,苦于能找到的材料太旧又太少,所以就筹备本人写一个有史以来最艰深、最全面、也最适宜中国人学的 zone.js 资料。当然,前两个“最”我可能还不配;然而第三个最,我感觉还是能够搏一搏的✌。

    OpenTiny Vue 招募贡献者啦!

OpenTiny Vue 正在招募社区贡献者,欢送退出咱们🎉

你能够通过以下形式参加奉献:

  • 在 issue 列表中抉择本人喜爱的工作
  • 浏览贡献者指南,开始参加奉献

你能够依据本人的爱好认领以下类型的工作:

  • 编写单元测试
  • 修复组件缺点
  • 为组件增加新个性
  • 欠缺组件的文档

如何奉献单元测试:

  • packages/vue 目录下搜寻 it.todo 关键字,找到待补充的单元测试
  • 依照以上指南编写组件单元测试
  • 执行单个组件的单元测试:pnpm test:unit3 button

如果你是一位经验丰富的开发者,想承受一些有挑战的工作,能够思考以下工作:

  • ✨ [Feature]: 心愿提供 Skeleton 骨架屏组件
  • ✨ [Feature]: 心愿提供 Divider 分割线组件
  • ✨ [Feature]: tree 树形控件能减少虚构滚动性能
  • ✨ [Feature]: 减少视频播放组件
  • ✨ [Feature]: 减少思维导图组件
  • ✨ [Feature]: 增加相似飞书的多维表格组件
  • ✨ [Feature]: 增加到 unplugin-vue-components
  • ✨ [Feature]: 兼容 formily

参加 OpenTiny 开源社区奉献,你将播种:

间接的价值:

  1. 通过参加一个理论的跨端、跨框架组件库我的项目,学习最新的 Vite+Vue3+TypeScript+Vitest 技术
  2. 学习从 0 到 1 搭建一个本人的组件库的整套流程和方法论,包含组件库工程化、组件的设计和开发等
  3. 为本人的简历和职业生涯添彩,参加过优良的开源我的项目,这自身就是受面试官青眼的亮点
  4. 结识一群优良的、酷爱学习、酷爱开源的小伙伴,大家一起打造一个平凡的产品

久远的价值:

  1. 打造集体品牌,晋升集体影响力
  2. 造就良好的编码习惯
  3. 取得华为云 OpenTiny 团队的荣誉和定制小礼物
  4. 受邀加入各类技术大会
  5. 成为 PMC 和 Committer 之后还能参加 OpenTiny 整个开源生态的决策和长远规划,造就本人的治理和布局能力
  6. 将来有更多机会和可能

其余阐明

OpenTiny 是一套企业级组件库解决方案,适配 PC 端 / 挪动端等多端,涵盖 Vue2 / Vue3 / Angular 多技术栈,领有主题配置零碎 / 中后盾模板 / CLI 命令行等效率晋升工具,可帮忙开发者高效开发 Web 利用。

外围亮点:

  • 跨端跨框架:应用 Renderless 无渲染组件设计架构,实现了一套代码同时反对 Vue2 / Vue3,PC / Mobile 端,并反对函数级别的逻辑定制和全模板替换,灵活性好、二次开发能力强
  • 组件丰盛:PC 端有 100+ 组件,挪动端有 30+ 组件,蕴含高频组件 Table、Tree、Select 等,内置虚构滚动,保障大数据场景下的晦涩体验,除了业界常见组件之外,咱们还提供了一些独有的特色组件,如:Split 面板分割器、IpAddress IP 地址输入框、Calendar 日历、Crop 图片裁切等
  • 配置式组件:组件反对模板式和配置式两种应用形式,适宜低代码平台,目前团队曾经将 OpenTiny 集成到外部的低代码平台,针对低码平台做了大量优化
  • 周边生态齐全:提供了基于 Angular + TypeScript 的 TinyNG 组件库,提供蕴含 10+ 实用功能、20+ 典型页面的 TinyPro 中后盾模板,提供笼罩前端开发全流程的 TinyCLI 工程化工具,提供弱小的在线主题配置平台 TinyTheme

欢送退出 OpenTiny 开源社区。增加微信小助手:opentiny-official 一起参加交换前端技术~

OpenTiny 官网:opentiny.design/

OpenTiny 代码仓库:https://github.com/opentiny/

Vue 组件库:opentiny.design/tiny-vue

Angular 组件库:opentiny.design/tiny-ng

欢送进入代码仓库 Star🌟TinyVue、TinyNG、TinyCLI~

如果你也想要共建,能够进入代码仓库,找到 good first issue标签,一起参加开源奉献~

往期文章举荐

  • 必不可少的 UI 组件一——组件的基础知识
  • OpenTiny Vue 3.10.0 版本公布:组件 Demo 反对 Composition 写法,新增 4 个新组件
  • 前端 Vuer,请收好这份《Vue 组件单元测试》宝典
  • OpenTiny 前端组件库正式开源啦!面向未来,为开发者而生
  • 从自研走向开源的 TinyVue 组件库
  • 我要做开源,提交我的第一个 PR

正文完
 0