反思现代网络

2020-05-11 06:45:24

Web开发的新兴规范是构建一个带有服务器呈现的Reaction单页面应用程序。此架构的两个关键元素类似于:

这个想法真的席卷了互联网。它从几个主要的流行网站开始,然后悄悄进入营销网站和博客等角落。

有一个反应的甜蜜点:在适度互动的界面中。需要即时反馈的复杂表单,需要移动和即时反应的UI。这就是它出类拔萃的地方。我在Mapbox Studio和Observable中帮助构建了编辑器,在很大程度上,Reaction是一个很好的选择。

高性能部件没有反应。例如,Mapbox GL是普通的JavaScript,可能应该永远如此。Reaction工作的抽象级别太高,使用Reaction的成本-输入有效负载、解析时间等等-对于任何公司来说都太高了,无法将其作为SDK的一部分。与可观察到的运行时一样,这也是该产品的核心:它是性能密集型的,几乎不会从端口中获益。

不需要对低性能部件进行反应。列出页面、静态页面、博客--这些东西越来越多地内置在Reaction中,但它们带来的好处却极其有限。在这些角落出现的许多优化,如捆绑包拆分、服务器端渲染和预渲染,本质上都是三角化,就像我们在Reaction兴起之前所拥有的那样。

我们的想法是,随着您的Reaction应用程序的增长,应用程序包也会随之增长。与传统的多页应用程序不同,这种增长会影响到每一个访问者:您在第一次访问时就下载了整个应用程序。在某种程度上,这会成为一个真正的问题。登陆About页面的人也在下载同一应用程序捆绑包中的其他20个页面。捆绑包拆分通过创建许多可以互相延迟加载的捆绑包“解决”了这个问题。所以您加载About页面,浏览器下载的是一个“index”包,然后“index”包加载“about page”包。

这在某种程度上解决了问题,但不是很好。大多数包拆分技术都需要加载那个“索引包”,然后只有在加载并执行该JavaScript之后,您的浏览器才知道它需要哪个“页面包”。因此,您需要两次往返才能开始页面呈现。

另外,还有更新代码拆分包的问题。用户会话时间长得令人吃惊:有人可能会让您的网站一次在一个选项卡中打开数周。我亲眼目睹了这一切的发生。因此,如果他们打开“关于页面”,保持选项卡打开一周,然后请求“主页”,那么他们请求的主页将由他们上周下载的索引包决定。这是一种非常奇怪的情况,而且没有得到充分的讨论。基本上有两种解决方案:

您可以永远保留所有生成的JavaScript,这样人们就可以看到在他们的第一个页面请求时处于活动状态的站点版本。

您可以创建一个系统,在部署了新版本的站点时提醒用户,并提示他们重新加载。

第一种解决方案的缺点可能不会立即显现。在加载站点和单击链接之间的几周内,您可能部署了一个新的API版本。因此,用户将使用旧版本的JavaScript前端和新版本的API后端,它们会触发您的测试中没有人知道的错误,因为您通常会测试每个版本的当前版本。

第二种解决方案虽然有效(这也是我们为Mapbox Studio实现的解决方案),但它是Web应用程序的一种奇怪的行为方式。促使用户“更新”的东西来自过去糟糕的桌面软件时代,而不是来自闪亮的网络新时代。

当然,传统的非SPA网站也不能幸免于这个陷阱。有些人可能会加载您的网站,让一个表单打开数周,然后在他们的会话到期或API更改后提交。但与SPA的案例相比,这对失败的风险要有限得多。

好的,这里的理论是SPA最初是一个空白页面,必须由Reaction&;JavaScript填充。这显然不利于性能,因为HTML页面最初不需要为空。因此,Server-Sider呈现在后端运行JavaScript前端代码,创建一个填充的HTML页面。用户加载已填充的页面,然后JavaScript加载并使页面具有交互性。

第一个是您最初呈现的页面是死的:您已经创建了Time to Interactive度量。这是你的创业公司的主页,它有一个“注册”按钮,但是在JavaScript加载之前,这个按钮什么都不做。所以你需要补偿。要么在加载时省略一些交互元素,要么非常努力地确保JavaScript加载的速度快于用户单击的速度,或者使一些元素不需要JavaScript才能工作-比如使它们成为普通的链接或表单。或者它们的某种组合。

然后是认证的故事。如果在用户自定义的任何页面上执行SSR,则需要将任何cookie或与身份验证相关的信息转发到API后端,并确保不会缓存服务器呈现的结果。

API的梦想是拥有漂亮的REST端点,它们与业务逻辑中的数据库或模型中的每个不同表保持一致。那个想法很快就会瓦解。

大多数交互式Web应用程序开始对“每页一个查询”进行三角测量。泛型或可重用的API调用似乎永远不会作为基础设施中的值持续存在。这是因为很大一部分Web应用程序的核心是基于数据库的查询和转换接口。他们往往遇到的最困难的性能问题是查询问题和传输问题。

例如:一个清教徒式的REST应用程序试图从不混合“关注点”(表),它将生成一个前端应用程序,该应用程序必须发出大量请求才能显示页面。然后,新时代的GraphQL应用程序将在数据库级别遭受N+1查询问题的影响,直到优化到来。而传统的“进行查询并将其放到页面上”应用程序只会尝试编写一些好的查询。

这些解决方案都不是灵丹妙药:我使用过过于严格的RESTAPI、渴望优化的GraphQLAPI和手工制作的SQLAPI。但是,没有哪种选择能真正让Web应用程序对其数据抓取层漫不经心。

说到数据获取。在Reaction的土地上,这真的很重要,也真的很奇怪。几年前,我预计会出现一些好的模式。坦率地说,他们没有。

GraphQL形式下有一些不错的模式,但是对于从API通过FETCH加载数据的Reaction组件来说,解决方案只会变得更加奇怪。其他的东西都有很棒的文档,但是老式的数据加载只剩下一个例子,就是如何模拟“取出”进行测试,以及许多质量不一的中等帖子。

不要把这理解为反反应。我仍然认为Reaction非常棒,对于特定范围的用例来说,它是您能找到的最好的工具。我想明确地说,从我所看到的情况来看,大多数其他单页面应用程序工具都存在这些问题。它们是模式的问题,而不是用来实现它的特定技术。Reaction替代方案有一些很棒的想法,它们可能会更好,但它们最终确实是相似的。

但我已经到了这样的地步,你可以看看这个领域在哪里,还有什么替代方案-然后再看看不受欢迎、不受欢迎、不酷的东西,比如Django、Rails、Laravel-然后想想到底发生了什么。我们在优化的基础上进行分层优化,以便使类似SPA的模式适合每个用例,我不确定这样做是否值得。

框架应该引诱人们进入成功的深渊,在那里遵循正常的规则和使用正常的技术是取胜的方法。

在这种情况下,我不认为这种反应真的是成功的深渊。天真地实现的Reaction SPA并不稳定或高效,而且它不会自然地扩展到显著的复杂性。

您可以在上面添加修复这些问题的优化,也可以使用像Next.js这样的框架,默认情况下会包含这些优化。那会帮你走得很远的。但是,您将会被所有简单的一键添加臃肿和复杂性的方式所吸引。您将负责保持其中一些复杂、挑剔的优化正常工作。

为了什么?再说一次--有一大堆用例如果没有Reaction就很难实现,而且还不够复杂,不足以超越Reaction的限制。但是也有很多问题,我看不出使用Reaction有什么具体的好处。这些都是像博客、购物车网站一样的东西,大部分是肮脏和表格网站。对于这些事情,所有花哨的优化都是为了让您更接近如果您没有使用那么多技术就会获得的性能。

例如,我可以保证这个博客比任何Gatsby博客都快(也非常感谢Gatsby团队),因为没有什么比非反应静态站点更快的了。

但文化潮流是强劲的。2020年在姜戈建立一家公司似乎相当于驾驶一辆PT Cruiser,在你的朋友们开着特斯拉听The Weeknd时,用CD播放费斯·希尔(Faith Hill)的“呼吸”。逆水行舟并不容易,而且也不是一种时髦的逆向投资方式。

我不认为每个人都在无缘无故地使用SPA模式。对于大公司来说,它允许团队独立工作:“前端工程师”可以“使用”来自可能使用不同语言工作的团队的“API”,并且只能通过层次结构进行通信。对于大量交互的应用程序,它在模块性、性能和结构方面都有真正的好处。对于公司来说,将计算需求从服务器转移到客户的浏览器上是有益的:这是减少他们在基础设施上的支出的真正胜利。

但我认为有很多问题可以通过其他方式更好地解决。没有像Reaction这样的类别获胜者作为替代。具有讽刺意味的是,后端在技术上的变化甚至比前端更快,前端几十年来一直忠于一种编程语言。有一些古老的技术,如Rails、Django和Laravel,也有一些半心半意的尝试从Go、Node和其他新语言进行模板化和“服务网页”。追随庞大项目的脚步-维基百科(Wikipedia)用PHP呈现网页,克雷格列表(Craigslist)用Perl呈现网页-但与现代网络开发的标准相去甚远,这让你受到了认知上的不和谐。如果维基百科今天开通,那就是“反应”。也许吧?