当前位置: 首页 > 科技观察

JavaScript框架发展的四个时代,未来的发展方向是什么?

时间:2023-03-12 06:27:51 科技观察

早在2012年,我就开始使用JavaScript编写代码。我曾经为一家本地企业从头到尾开发过一个PHP应用程序,一个简单的CMS网站。后来,他们决定重写它并添加一些功能。项目经理希望我在.NET中进行开发,部分原因是他更了解这项技术,但也因为他希望能够使该项目成为类似本机的应用程序-减少页面加载时间。经过一些研究和原型设计后,我说服他对网络做同样的事情,这就是全新的JS框架出现的时候。我选择的第一个框架其实是Angular1,当时我基于FuelPHP后端开发了一个比较大的应用。从功能上讲,每当重新渲染子路由/出口时路由器会闪烁这一事实是我们在开发过程中没有考虑到的偶然事件。后来有人向我推荐了RubyonRails+Ember的方案,试用后觉得还不错。我喜欢这两个框架和构建它们的社区的理念。从那时起,许多事情都发生了变化,出现了许多新框架,旧框架已经退役。用JavaScript在浏览器中构建应用的想法,从少数开发者的尝试,逐渐成为前端领域的标准操作。随着基础设施开发人员构建的变化,出现了许多新的可能性。这段时间里,很多开发者的很多想法都陷入了纠结和自相矛盾的迷茫中。我想很多在前端领域工作过一段时间的人可能都有过这样的经历,纠结于使用哪个JavaScript框架,如何编写CSS,函数式编程还是面向对象编程,如何最好地管理状态,哪个build系统或工具是最灵活的,最快的等等。回想起来,我觉得很有趣,我们经常为小错误争论不休,而忽略了更有意义的事情,当然这是“事后诸葛亮”。所以我想做一个回顾,总结过去几十年的JavaScript发展,看看我们走了多远。我认为我们可以大致将其分为四个主要时代:上一代第一代框架以组件为中心的视图层全栈框架(←这是我们目前所处的位置)每个时代都有自己的签名每个时代也给了我们不同的经历和教训,终于使我们进步。关于JavaScript开发,争论一直持续到今天:网站是否变得过于臃肿?普通的网站真的需要用React写吗?我们甚至应该使用JavaScript吗?我不认为我们可以在这里看到未来,最后我怀疑我们可能会再次发现我们在没有关注更广泛和有意义的技术的情况下相互交谈。不过,回望过去,或许其中的一些观点也能帮助我们更好地走向未来。PastLifeJavaScript于1995年首次发布。就像我上面提到的,我在2012年开始编写JS,距JavaScript诞生将近20年,这是我所说的FirstFrameworks时代的开始。可以想象,这个时代可以分为许多子时代,每个子时代都有自己的模式、库、构建工具等。也就是说,我不能写我自己没有经历过的东西。当我开始编写前端应用程序时,新一代的框架才刚刚开始成熟,像Angular.js、Ember.js、Backbone等。在此之前,jQuery和MooTools等库是最先进的。这些库在当时非常重要,它们有助于消除浏览器实现JavaScript的方式之间的差异,这一点非常重要。比如IE实现事件的方式就和Netscape(网景浏览器)完全不同,分别是事件冒泡和事件捕获。这就是为什么我们今天的标准最终实现了这两种浏览器,但在此之前,您需要使用库来编写适用于两种浏览器的代码。这些库主要用于制作小型、独立的用户界面小部件。大多数应用程序业务逻辑仍然通过表单和标准HTTP请求发生,即在服务器上呈现HTML并将其提供给客户端。在这个时代,可谈的构建工具也不多(至少据我所知是这样)。当时的JavaScript没有模块(至少没有标准模块),所以没有任何方法可以导入代码。一切都是全球性的,组织这些东西非常困难。在这种环境下,JS经常被看作是一种点缀的语言,而不是用来编写一个完整的应用程序的语言,这是可以理解的。当时开发者最常做的事情就是使用jQuery并为一些UI小部件编写一些脚本。随着时间的推移和XHR的引入和流行,开发人员开始将他们的部分UI流程放到一个页面中,特别是对于需要在客户端和服务器之间进行多次来回交互的复杂流程,但应用程序中的大部分程序留在服务器上。这与移动应用程序开始出现时发生的情况形成鲜明对比。从一开始,iOS和Android上的移动应用程序就是用Objective-C和Java等高级语言编写的完整应用程序。此外,它们完全由API驱动——所有UI逻辑都存在于设备上,而与服务器的通信则纯粹以数据的形式进行。这导致了更好的用户体验和移动应用程序的爆炸式增长,直接导致了我们今天关于移动设备或网络哪个更??好的争论。最初,许多人认为用JavaScript来做这一切是荒谬的。但随着时间的推移,这些应用程序开始变得更加雄心勃勃。许多社交网络平台都增加了聊天、DM等实时功能。Gmail和GoogleDocs已经验证了浏览器也可以达到与桌面相同的用户体验。越来越多的公司开始提供Web应用程序开发服务,因为在他们的Web中,似乎无处不在,并且从长远来看更易于维护。这推动了整个Web行业的发展。很明显,JS现在可以用来编写更复杂的应用程序。不过在当时的环境下,要做到这一点还是有些困难的,因为当时的JavaScript还不具备今天的所有功能。就像我说的,一切都是全局的,您通常需要手动下载每个外部库并将其添加到您的静态资产文件夹中。那时没有NPM,不存在模块,JS也没有今天一半的功能。在大多数情况下,每个应用程序都是自定义的,每个页面都有不同的插件设置,每个插件都有不同的系统来管理状态和渲染更新。为了解决这些问题,出现了最早的JavaScript框架。第一代框架在2000年代末和2010年代初,第一个专门用于编写完整客户端应用程序的JS框架开始出现。这个时代一些著名的框架是:Backbone.jsAngular1Knockout.jsSproutCoreEmber.jsMeteor.js当然,还有许多其他的或在某些圈子中更为人所知。但是,以上是我记得的,我经常将它们用于原型设计或构建。这是第一代框架,它正式打开了未知领域的大门。一方面,这些框架试图做的事情遥遥领先,以至于许多人认为它们不会真正成功。有许多反对者认为单页JS应用程序(SPA)从根本上来说是糟糕的,并且在时间的考验中,这些批评者在许多方面都被证明是正确的,例如,客户端渲染意味着机器人无法轻易抓取这些页面,在应用程序开始绘制之前,用户甚至必须等待几秒钟。如果您关闭JavaScript,这些应用程序中的很多都是噩梦般的存在,它们根本无法运行。另一方面,我们没有使用JS构建完整应用程序的经验,因此许多开发人员对最佳方法有很多不同的想法。大多数框架都试图模仿其他平台上流行的做法,所以几乎所有的框架都以“Model-View-*”迭代方式结束,比如Model-View-Controller、Model-View-Producer、Model-View-ViewModel等等。从长远来看,其中一些问题确实得到了解决,但解决方案往往不直观,在应用过程中变得越来越复杂。这也是我们真正开始尝试如何编译JavaScript应用程序的时候。Node.js于2009年发布,NPM于2010年紧随其后,将包的概念引入(服务器端)JavaScript。CommonJS和AMD竞争如何定义最好的JS模块,而Grunt、Gulp和Broccoli等构建工具竞争如何将这些模块组合成可交付的最终产品。在大多数情况下,这些都是非常通用的类似任务运行器的工具,它们真的可以构建任何东西,只是恰好与HTML、CSS/SASS/LESS等结合使用,而且许多适用于Web的产品都是基于JavaScript开发的。从这个时代,我们学到了很多东西,获得了宝贵的经验,包括:URL路由是基础。没有它的应用程序往往有问题,开发人员需要从一开始就在框架中考虑它。通过模板语言扩展HTML是一个强大的抽象层。尽管它有时可能有点笨拙,但它使您的UI与状态保持同步变得更加容易。SPA(单页应用)性能差,Web开发有很多原生应用没有的额外约束。我们需要将所有代码发布到网络上,让它进行即时编译(JIT),然后运行它以启动我们开发的应用程序,而本机应用程序已经下载并编译。这是一项艰巨的任务。JavaScript作为一种语言存在很多问题,它确实需要改进以使事情变得更好——仅靠框架无法做到这一点。我们绝对需要更好的构建工具、模块和包装器来编写大型应用程序。总的来说,这个时代是富有成果的。尽管存在这些缺点,但随着应用程序复杂性的增加,将客户端与API分离的好处是巨大的,并且在许多情况下,可以显着改善用户体验。如果不是这样,这个时代可能还会继续,我们可能还会重复MV*的风格直到今天。但紧接着,一颗“小行星”突然出现,将现有范式砸得粉碎,引发了一场小型灭绝事件,将我们推向了下一个时代——这颗“小行星”被命名为React。以组件为中心的视图层我不认为React发明了组件,但老实说,我不太确定它们最初是从哪里来的。我知道现有技术至少可以追溯到.NET中的XAML,那是Web组件作为规范开始流行的时候。现在每个主要框架都使用组件。事后看来,它的流行也是完全有道理的——扩展HTML,减少长期存在的状态,将JS业务逻辑直接绑定到模板(无论是JSX还是Handlebars或Directives)。基于组件的应用程序消除了完成任务所需的大部分抽象,并显着简化了代码生命周期。一切都与组件的生命周期相关,而不是应用程序的生命周期。这意味着作为开发人员,您需要考虑的事情要少得多。然而,当时还有另一个变化:框架开始吹嘘自己是一个“视图层”,而不是一个完整的框架。他们不再解决前端应用所需的所有问题,而只专注于解决渲染问题,而路由、API通信和状态管理等其他问题则留给用户自己决定。这个时代著名的框架包括:React.jsVue.jsSveltePolymer.js当然还有很多很多其他的。现在回想起来,我认为这是第二代框架中流行的框架,因为它主要做了两件事:它极大地缩小了范围。这些框架的核心不是试图解决前端的所有问题,而是专注于渲染,并且可以在更广泛的系统中探索实现其他功能的许多不同的想法和方向。虽然有很多不好的解决方案,但也有好的解决方案,为下一代从精英中挑选最好的想法铺平了道路。这样更容易让开发者接受。采用一个完整的框架来接管你的整个网页意味着你需要重写大部分应用程序,这对于现有的服务器端来说是不可能的。使用React和Vue等框架,您可以将它们的一小部分放入现有应用程序中,并且一次只迁移一个小部件或组件,从而允许开发人员逐步迁移他们现有的代码。这两个因素导致了第二代框架的快速发展,使第一代框架黯然失色。从长远来看,这一切似乎都是有道理的,是一种合乎逻辑的演变。但对当时身处其中的我来说,这是一次非常令人沮丧的经历。首先,工作中关于框架选择的争论不是关于我们应该使用哪个框架进行开发,或者我们是否应该重写我们的应用程序。相反,它通常是“它更快!”或“它更小!”或“这就是您需要的一切!”。还有关于函数式编程与面向对象编程的争论,许多人指出FP是我们所有问题的解决方案。平心而论,这些都是真的。仅查看框架最初更小、更快,并且满足您的所有需求(如果您自己构建或缝制很多东西)。当然,函数式编程模式解决了很多困扰JavaScript的问题,我认为JS总体上因为它们更好。然而,现实是没有灵丹妙药。应用程序仍然变得庞大、臃肿和复杂,状态仍然难以管理,路由和SSR等基本问题仍然需要解决。对于我们中的许多人来说,似乎人们想要的是放弃试图解决所有这些问题的解决方案,并将这个问题留给读者。根据我的经验,为了快速发布新产品或功能,开发团队普遍接受这个想法。但是,他们没有足够的时间来完全开发所有额外的功能。因此,根据我的经验,开发更多时候是围绕这些视图层构建的自制框架,这些视图层本身就臃肿、复杂,而且很难导航。我认为人们对SPA的很多问题都来自这个破碎的框架系统,而这个框架系统恰好发生在SPA使用量激增的时候。我仍然经常遇到不能很好地处理路由或其他小细节的新站点,这绝对令人沮丧。但另一方面,现有的全业务第一代框架并不能很好地解决这些问题。部分原因是仍然存在巨大的技术债务负担。第一代框架是在ES6之前构建的,在模块、Babel和Webpack之前,在我们弄清楚很多东西之前。迭代进化是非常困难的(作为前Ember核心团队成员,我深知这一点),完全重写它们,就像Angular对Angular2所做的那样,扼杀了它们的势头。因此,当谈到JavaScript框架时,开发人员陷入了两难境地——要么选择过时的一体式解决方案,要么选择放肆DIY一半的框架并希望得到最好的结果。就像我说的,当时很沮丧,但最后还是有很多创新。随着为这些框架找出最佳实践,整个JavaScript系统发展得非常快,并且发生了一些其他关键变化:像Babel这样的转译器成为规范并帮助使语言现代化。与其等待多年等待功能标准化,不如今天就使用它们,并且语言本身开始以更快、更迭代的速度添加功能。ES模块是标准化的,让我们最终可以围绕它们构建现代构建工具,如Rollup、Webpack和Parcel。基于导入的捆绑正在慢慢成为常态,即使对于样式和图像等非JS资产也是如此,这极大地简化了构建工具的配置,使它们更精简、更快且通常更好。随着越来越多的API被标准化,Node和Web标准之间的差距正在慢慢缩小。SSR最初是一种真正的可能性,然后成为每个标准应用程序都在做的事情,但每次都有一定程度的定制。边缘计算的发布使基于JavaScript的服务器应用程序能够在分发/响应时间方面获得SPA的好处(SPA,因为它们是CDN上的静态文件,通常可以更快地开始加载,即使完全加载和呈现也是如此最后需要更长的时间)。到这个时代结束时,一些问题仍然存在。尽管我们有比以前更好的模式,但状态管理和反应性到目前为止一直是难题。性能情况也在好转,但是还是有很多臃肿的SPA。可访问性情况通常也是许多开发团队事后才想到的。但这些变化为下一代框架铺平了道路。我想说我们刚刚进入了下一个框架时代。全栈框架就个人而言,框架的最后一个时代真的悄悄降临在我们身上。我认为这是因为我花了4年左右的时间深入挖掘Ember渲染层的内部结构,试图清理上述仍然影响它作为第一代框架的技术债务。但也是因为它更微妙,因为所有这些第3代框架都是围绕上一代的视图层框架构建的。著名的框架包括:Next.js(React)Nuxt.js(Vue)Remix(React)SvelteKit(Svelte)Gatsby(React)Astro(Any)这些框架随着视图层的成熟和固化而出现。既然我们都同意组件是构建框架的核心基础,那么有必要开始标准化应用程序的其他部分——路由器、构建系统、文件夹结构等。慢慢地,这些元框架开始构建与第一代一体式解决方案可以提供,从组件中挑选最佳模式,并在它们成熟时将它们合并,然后再进一步。到目前为止,SPA一直专注于客户端。SSR是每个框架都急于解决的问题,但它只是作为一种优化,一种渲染方式,最终会在JS加载完成后被取代。第一代框架中只有一个敢做大,Meteor.js,但它的“同构JS”理念从未真正实现。但随着应用程序的规模和复杂性的增加,这个想法被重新审视。我们注意到将后端和前端结合起来非常有用,这样您就可以为某些请求隐藏API秘密,在页面返回时修改标头,以及代理API请求。随着Node和Deno实施越来越多的Web标准,服务器端和客户端JS之间的差距逐年缩小,这似乎不再是一个疯狂的想法。将其与边缘计算和令人惊叹的工具相结合,您将拥有不可思议的潜力。最新一代的框架充分利用了这种潜力,无缝地融合了客户端和服务器,我怎么强调它的感觉都不为过。在过去的9个月里,我一直在使用SvelteKit,我坐下来说,“我们应该一直这样做。”次数多得我数不过来。以下是我最近完成的一些任务,通过此设置,它们变得非常简单:将服务器端OAuth添加到我们的应用程序,以便授权令牌永远不会离开服务器,同时还具有API代理,无论何时请求被发送到我们的API添加令牌。将某些路由直接代理到我们的CDN,这样我们就可以托管内置在任何其他框架中的静态HTML页面,从而允许用户制作自己的自定义页面(这是我们为某些客户提供的服务)。当我们需要使用需要密钥的外部服务时,添加几个不同的一次性API路由(不需要向我们的API添加一个全新的路由并与后端人员协调)。将我们对launchdark的使用转移到服务器端,这样我们就可以加载更少的JS并降低总体成本。通过后端路由代理我们的哨兵请求,这样我们就可以捕获由于广告拦截器而不会报告的错误。而这只是冰山一角。这种模式确实有很多很酷的地方,其中最大的一个就是它如何重新激发渐进式增强的想法,利用服务器和客户端的组合特性,允许客户端回退到基本的HTML+HTTP。当我开始使用SPA时,我完全放弃了这种做法,认为它们只是未来的趋势,但我们有可能再次看到它真的很酷。根据经验,基于这些新特性,我将这些框架归类为新一代框架。以前难以或不可能解决的问题现在变得微不足道,只需对响应处理逻辑进行微小的更改。可靠的性能和用户体验触手可及,无需任何额外配置。我们可以根据需要添加一些额外的端点或中间件,而不是构建一个全新的服务。这改变了生活。我认为这一代框架也解决了第一代和第二代框架与其用户之间的一些主要紧张点。它开始于转向零配置术语,但我认为它最终是由围绕第二代框架的衍生系统驱动的,并逐渐成熟和稳定。第三代框架现在再次尝试成为一体化解决方案,试图解决我们作为前端开发人员需要解决的所有基本问题,而不仅仅是渲染。现在,感觉社区比以往任何时候都更一致地解决困扰SPA的所有问题,重要的是,他们正在共同努力解决这些问题。接下来我们应该做什么?总的来说,我认为JavaScript社区正朝着正确的方向前进。今天的开发人员专注于从头开始构建不限于“一个视图层”的完整应用程序的成熟解决方案。同时,我们也终于开始和原生应用SDK在同一起跑线上竞争,提供开箱即用的完整工具包。接下来,我们还有很多工作要做。可访问性是SPA领域中一个长期存在的问题;在GraphQL之外,我仍然认为数据可以用于某些功能(不管你喜欢与否,大多数网络仍然在REST上运行)。但是趋势是对的,如果我们继续朝着共享解决方案的方向发展,我认为我们可以比以前更好地解决这些问题。我也对将这些模型进一步落后于网络平台本身的潜力感到兴奋。WebComponents仍在悄悄地迭代,致力于SSR和摆脱全局注册表,这将使它们与这些第3代框架更加兼容。另一方面,WebAssembly可以以令人难以置信的方式迭代此模式。想象一下能够用任何语言编写一个全栈框架。同样的Rust、Python、Swift、Java等最终可以将前端和后端之间的障碍减少到几乎没有,只是在系统边缘的一点HTML模板(具有讽刺意味的是,尽管UX更好,但是这给我们带来了几乎完整的循环)。如果我们可以默认为开发人员提供正确的工具,也许网站会运行得更好,用户体验也会更顺畅。框架的好坏虽然不能解决网站所有的问题,但是会为网站往好的方向发展打下基础,也会让每个开发者有更多的时间专注于其他事情。