Angular现在引入了WebComponents啦!哇!哇!哇!~@angular/elements的初印象~
标题是“甲壳虫来了啊!啊!啊!”的模仿作品。
什么是@angular/elements?
@angular/elements是一个用于将Angular组件转换为Web Components的软件包。PullRequest在9月29日被提交,10月28日通过了LGTM,并被移动到labs分支上。这仍然是一项处于实验状态的全新功能。
这可能有些借口,但是@angular/elements的方向仍然不确定,我自己的知识也远远不够。我已经在我理解的范围内总结了目前的情况,但是如果有任何指正或修正,请随时留下评论或编辑请求,谢谢。
Web Components的复习
Web Components 是一个促进在HTML/CSS/JavaScript中实现可重复使用组件的机制。
当使用Web Components时,无论是从哪个应用程序(不仅限于Angular,只要可以访问浏览器的窗口)都可以使用由Angular创建的自定义标签。当然,反过来也是可以的,例如在Vue中创建组件并注册为自定义标签后,在Angular中也可以使用它(但有一些条件)。此外,作为解决Angular独有情况的方案,还可以创建具有多个入口点的Angular应用程序。
为了实现这一点,@angular/elements会为Angular组件进行构建,以适应Custom Elements(WebComponents四天王之一)的接口,并可通过window.customElements进行注册。为什么可以在Angular之外使用呢?因为Custom Elements定义了外部接口规范。通过给定属性或接收事件,可以实现Angular与其他JavaScript应用程序的协同工作。在这种情况下,JavaScript应用程序指的是在script标签中编写的JavaScript函数。请注意,@angular/elements几乎指的就是Custom Elements。
只决定接口是不够的,还需要一个机制来隐藏主机的定制元素。主机的 CSS 和 JavaScript 对象可能会与自定义元素内部发生冲突或被覆盖,反过来,自定义元素的对象也可能对外部产生影响。为此,Shadow DOM (WebComponents 四大组件之一)提供了一个隐藏主机部分的 DOM 空间。
此外,通过ES模块(WebComponents四巨头之一)可以在浏览器中将模块化的内容导入。您也可以在没有改变当前环境的情况下,将Angular自定义标签与阿贝·广场的网站融合在一起。
Web Components是四个强大实体的其中一员。Template(Web Components的第四个实体)是一个在浏览器中加载但处于非激活状态(即不会被渲染)的HTML组件。
@angular/elements的两个背景
浏览器的实现状况得到了进一步改善。
首先的背景是Web Components的规范制定正在推进,浏览器的实现也开始完善。当前的浏览器支持情况如下,涉及到构成Web Components的四个主要元素。
目前,核心的自定义元素还包括黄色和红色行进,但可以确定支持正在Chrome和Safari这两个主要移动浏览器中进行。
自定义元素
https://caniuse.com/#feat=custom-elementsv1
影子 DOM
http://caniuse.com/#feat=shadowdomv1
ES 模块
http://caniuse.com/#feat=es6-module
模板
http://caniuse.com/#feat=template
Angular的用例覆盖已经达到了极限
作为第二个背景,我们要谈到 Angular 的发展问题。自从 Angular2 以后,我们一直努力推动采用 TypeScript 和 AoT 编译的强大单页应用(SPA)开发路线,与此同时,为了换取这种发展,我们弱化了开发者轻松创建 Web 组件、享受开放和协作的互联网、以及使用小工具的路线。
WordPress的下一代编辑器框架选择中,Angular早期便被排除在候选之外。此外,Angular自身的文档网站建设也成为一个问题。关于文档网站的背景信息,请参阅AdventCalender第1天的文章中的“第二个轴:动态应用程序支持”一节。如果你懂英语,我认为你也会对文章中提到的YouTube感兴趣。由于听力有限,我只是通过幻灯片阅读了相关内容。
在构建Angular文档网站时遇到的问题。
视频链接:
幻灯片资料链接:
https://onedrive.live.com/view.aspx?resid=635B97DC223BC5B2!136637&ithint=file%2Cpptx&app=PowerPoint&authkey=!AFgQoakql9CnkD0
为什么要使用@angular/elements?
两个方向
Web Components可以只使用HTML/CSS/JavaScript来创建。使用@angular/elements的原因是可以使用Angular包进行开发。
正如之前提到的,@angular/elements目前仍处于实验阶段。因此,功能尚未确定,使用案例也处于试探阶段。这一点可以从目前参与该项目的人中可以看出,有两个重要的方向。
目前,可观测到的两个方向如下。
-
- UI部品のパブリッシュ-ngComponents Everywhere
特定のAngularコンポーネントをWeb Componentsに乗せ、フレームワーク無関係で利用できるようにする
Angular特有の課題解決-Dynamic Bootstraping
Angularアプリ全体をWeb Components化して、component単位でbootstrapできる手段を提供し、実行タイミングをコントロールできるようにする
Rob Warmald先生是这个提案的发起人,他最初设计了一个轻量级的Web Components API。Rob先生在6月份发布的angular-elements 3示例库主要关注发布特定的UI组件,它将window.customElements.define()进行了包装,并允许将扩展了HTMLElement的Angular组件作为自定义元素进行发布。这个示例对于我这个作者来说,读起来很顺畅,感觉很容易理解。
一方面,实施了@angular/elements的gkalpak先生似乎非常重视将Angular应用程序的引导进行解构,使其能够按组件进行自我引导。这样做的目的是将现有的Angular应用程序转化为Web组件。他还提到,@angular/elements最终可能会被包含在核心程序包中。老实说,对于这些谈论,作者并没有跟上。他们正在试图实现的内容似乎与另一个实验项目ngiv存在重叠,给人一种流动的感觉。
另外,当Rob在十月和十一月份展示@angular/elements时,双方都被包含在内,所以两者似乎都是@angular/elements的目标。@angular/elements的registerAsCustomElements()的定义也涉及这两种多态性。(两个export函数 + 将两者混合的实际实现共计三个。)
幻灯片资料
https://docs.google.com/presentation/d/1jiXHYwfe1iSUiVLdKLFhSPRHLI_FmIvrI60QTpP6KLk/mobilepresent?slide=id.g26d86d3325_0_0
优酷
在各处发布UI组件:ngComponents
你现在可以创建并在互联网上发布你喜爱的潮流按钮了。与以往不同的是,你现在可以接触到不仅限于Angular用户的人群。
容易理解的是Web Components的资产存储6。例如,MaterialDesign目前在每个js框架中实现,如Material Design Lite(JQuery)、AngularMaterial、Material-UI(react)、VueMaterial、paper-elements(polymer)。然而,如果只需要标准接口,通过存储提供MaterialDesign的提供,无论与js框架有无关系,都可以处理。
(@angular/elements的registerAsCustomElements()的使用方法将在另一篇文章中详细介绍。)
此外,Preact和Angular协调演示也已经展示出来。如下所示,Preact的组件内使用JSX编写了Angular自定义标签。
/** @jsx h */
const { h, render, Component } = Preact;
// Preacのコンポーネントを普通に作る
class Demo extend Component {
constructor() {
super();
this.state.progress = 0;
}
...
render(props, state) {
// Angularのカスタムタグを記述
return <ng-progress-bar progress={state.progress}></ng-progress-bar>;
}
}
render(<Demo />, document.body);
地球原来只有一个。
Angular所独特的问题解决方式-动态引导
设立多个入口点
这是一个完全针对Angular用户的说明,目前Angular的入口点= bootstrap基本上只注册一个组件。bootstrap本身是一个数组,在之前提到的“在构建Angular文档站点时遇到的问题”中,我们按照现有的bootstrap形式将embeddableComponents作为数组放入entryComponents中。@angular/elements可以全局覆盖bootstrap以注册多个组件。
将main.ts中的platformBrowserDynamic().bootstrapModule(AppModule)替换为registerAsCustomElements(webComponents, bootstrapFn)的形式。
筆者有点跟不上的重点是,用这种方法,与现有的Angular应用程序几乎没有太大的差别。仍然是SPA,通过路由进行跳转。只是main.ts和app.module.ts的描述有所不同,就像是将现有的Angular应用程序转化为Web组件一样。真的吗?
我們可以通過一個簡單的例子來展示差異。
这是现状。我只是为了比较而发布,实际上几乎是刚使用angular-cli的ng new创建的状态。
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
将Web Components化。在示例代码中通过评论,作者会加上自己的困惑或解释。
import { enableProdMode, destroyPlatform } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { registerAsCustomElements } from '@angular/elements';
import { AppModule, webComponents } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
// なんだこれは!?
destroyPlatform();
const bootstrapFn = () => platformBrowserDynamic().bootstrapModule(AppModule);
// 第一引数にWebComponentsとして登録したいcomponentをセットする。
// 第2引数にこれまでのbootstrapをセットしている。
registerAsCustomElements(webComponents, bootstrapFn)
.then(moduleRef => /* Custom Elements are ready. Do your thing... */);
.catch(err => console.log(err));
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LikeButtonComponent } from './like-button/like-button.component';
// エントリーポイントにしたいcomponentを並べている。
export const webComponents = [
AppComponent,
LikeButtonComponent
];
@NgModule({
declarations: [
...webComponents,
],
// bootstrapのキーは記述せずにentryComponentsにする
entryComponents: [
...webComponents
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
],
})
export class AppModule {
// お前はどこから来た?
// 手動でbootstrapするためのものらしいが...
// https://blog.angularindepth.com/how-to-manually-bootstrap-an-angular-application-9a36ccf86429
ngDoBootstrap() { }
}
SPA和SSR方法的替代选项
这是一个我很少听说过的故事,作为作者,我脑海中构想着一种不使用router的Angular框架。它是作为非SPA(单页应用)存在的,通过服务器路由来保留模板,可以在页面或同一页面中嵌入多个Angular组件的方式。
总的来说,这是一种替代方法,用于构建需要SEO和OGP等应用程序服务的情况,即SSR(服务器端渲染)的需求变得重要。我认为SSR是一种弯曲的解决方案。就是将最初在服务器上创建的模板作为SPA导入到浏览器中,然后再返回到服务器,结果需要另一个node服务器,这太麻烦了!
像Rails和Spring这样的web框架通常都有模板引擎。将@angular/elements与ESModule集成到模板引擎中,就可以按组件单元进行挂载。
因为诚实,所以我觉得将其集成到Web框架中可能会很困难,因为需要使用Node&Angular环境。但是,如果能够像Rails的AssetPipeline一样进行集成,那将会非常方便。关键是使用Custom Elements和ESModule。
只是,我也认为另一个实验项目“ngiv 5”可能会承担起这个角色,正如@lacolaco指出的那样,iv可能是Isomorphic Viewengine的缩写。我找到了作者当时公开的ngiv存储库,但我记得源代码中有一些node的出现,可以看出分别使用了DOM Node的含义和Node.js环境的含义。我只能确认它是基于浏览器API的。
目前阶段可做之事
目前,@angular/elements正在实验性的R&D项目称为lab中开展。同时,它也已经在npm上发布,供使用。
$ npm install angular/elements-builds#labs/elements
在https://github.com/angular/angular/tree/labs/elements中,该代码库提供了分支选择。
筆者曾經複製並娛樂過這個樣板儲存庫。這是指向將SPA保持不變並將其轉換為WebComponents方向的樣本。
https://github.com/playerx/angular-elements-sample
未来的发展
据说作为未来的里程碑,labs将收集反馈,并计划在明年4月的Angular6版本中引入试验性功能,目标是正式发布。另外,在已关闭的Pull Request中,于12月7日添加了一个关于未来路线图的问题评论,gkalpak先生回答如下。4
-
- coreに入るかもしれない?
-
- coreの内部改造を研究中であり、それを受けてngElementsも改良することになるだろう(バンドルサイズの削減など)
-
- angular.ioでngElementsを投入する
- ドキュメントを準備する
另外,3天前,有关于Web Components的问题已经出现。gkalpak先生正在将与@angular/elements有关的议题引导到本讨论串中。
https://github.com/angular/angular/issues/20859
最后
因为这是关于未来的谈论,所以只是我的主观看法,但我认为随着Web组件的全面运行,JavaScript框架的方向将变得解散或融合。
本文中提到的对Bootstrap的解构,可以说是在Angular的优点和缺点之间,通过Web Components的介入而开始进展的动态。这可以看作是在React中,从virtualDOM到Fiber的刷新动态。对于React而言,virtualDOM是其优点,但在canvas和媒体方面则成为了其弱点。Fiber的目标是增加调优功能,但作者注意到它在与DOM的协调方面进行了转变。(可以说是优点和缺点的两面性,根源较深,不太容易简单解决的样子)。
从过去开始,人们认为基于组件化的JavaScript框架是对浏览器在Web Components完成之前的polyfill。虽然Web Components已经完全支持,但我并不认为当前局部优化的各个JavaScript框架的任务已经结束。然而,通过逐渐开放外部接口,我们可以降低互操作性的门槛。Angular和Preact的协同演示是一个象征。我将这称之为融合在一起。
目前的情况下,同时使用多个JavaScript框架并非仅仅解决接口问题,同时还会导致打包文件的增大和开发环境的复杂化等问题。可以说,“虽然可以做,但是否值得去做”是一个讨论点。
然而,只要问题得到明确定义,解决问题就是工程师的责任。Angular已经开始运转。因此,通过Web组件的推动,生态系统和技术人员的技能栈也会发生重大变化,相互操作将得到进一步发展。
地球原来只有一个呢(第二次)
以上是。明天是@ponday先生。