Next.js是如何发展的,为什么它是市场上最好的反应框架之一。
最近,围绕基于Reaction的Web框架Next.js有很多炒作。但是,这种炒作是有根据的吗?与功能丰富、开发人员友好的Create-Reaction-app等现有工具相比,Next.js提供了哪些改进?或者是简单、可靠的静态站点生成工具--Jekyll?
next.js只会给你的应用程序增加更多的膨胀吗?这真的是前端开发的未来,还是仅仅是一时的时尚?它真正解决的是什么问题?
在本文中,我将尝试回答所有这些问题以及更多问题。
在本文中,我不会将Next.js与其主要竞争对手Gatsby进行直接比较。这些框架都有非常相似的功能,也各有长处。它们都在快速进化,周围都有蓬勃发展的生态系统,所以很难做出一个月后仍然有意义的比较。
很多人都听说过Next.js基本上只是一个“静态站点生成器”,它允许在Reaction中编写代码。我过去采访过的一些Reaction开发人员遵循了经验法则,如果他们想创建静态站点,他们应该使用Next.js或Gatsby这样的工具,但如果他们想要一个功能更多的动态站点,他们应该坚持使用久经考验的真正的Create-Reaction-app。
但是Next.js不仅仅是一个静态站点生成器。它比Jekyll强大得多,Jekyll主要是为托管简单的静态站点而设计的。js支持与Jekyll相同的静态站点生成功能,此外还支持create-action-app的所有功能,等等。如果您在Vercel上部署Next.js,您将获得令人难以置信的流畅、严肃、“零配置”的开发体验。
换句话说,静态站点生成只是Next.js擅长的一件事,但到目前为止这是它的主要卖点。我不会称Next.js为静态站点生成器,而是一个自动静态优化框架,它坚持将Reaction作为其核心。
当Next.js应用程序部署在Vercel上时,它也是一个优秀的无服务器框架,非常适合构建JAMstack应用程序。
但是这些东西意味着什么呢?“自动静态优化”与静态站点生成有什么不同?我说的“无服务器”是什么意思?
最重要的是,Next.js使用了一种固执己见的基于文件系统的路由方法,而不是要求您自己通过JavaScript或使用诸如Reaction Router之类的东西来配置所有路由。但它是否足够灵活呢?这种方法是否适合可能具有许多复杂路由场景的严肃企业应用程序,甚至是具有一些动态功能的中型应用程序?
在本文中,我将再次尝试回答或至少涉及所有这些问题,甚至更多。
在我开始大肆宣扬Next.js之前,让我们先来了解一下Next.js是如何作为一种技术发展起来的。
如果您从早期就开始开发Web应用程序,那么您可以跳过这一部分,而不会错过任何东西。
在20世纪90年代早期,当Web第一次被引入时,Web的大部分由存储在不同地方的一堆计算机上的一堆HTML文件组成。
您可以使用URL向特定的Web服务器发出请求。请求最终将被传送到Web服务器,然后该服务器将使用HTML文件进行响应。最后,您的浏览器将向您显示HTML文档。
这在当时是相当慢的,主要是因为计算机速度较慢,互联网基础设施也没有今天那么先进。但总而言之,这是一个相当稳固的系统。这很简单,而且奏效了。生活很美好。
不过,这种“静态文件”方法非常有限-如果页面需要显示数据库中的一些数据,而这些数据一直在变化,那该怎么办呢?如果页面包含的信息包含只应在某些时候呈现的信息,该怎么办?我们是否必须为用户可能看到的每个可能的页面创建单独的HTML文件?
为了支持更动态的Web页面,引入了PHP等技术,这使得根据不同的条件为同一个URL返回不同的HTML响应变得很容易。这种方法称为服务器端呈现,因为服务器为每个请求动态地“呈现”(生成)HTML页面,然后将其发送回用户。
PHP是一个很棒的想法。它允许您用HTML编写一些代码,但是一旦您意识到您正在编写的HTML的一部分必须是动态计算的,您就只需切换到PHP模式,然后开始编写决定当前HTML块中的内容的逻辑。然后,您可以切换回HTML模式,继续使用普通的旧HTML。
服务器端呈现方法启用了大量优秀的Web页面功能(如电子邮件、网上银行等),但代价是页面加载时间。每次服务器需要从数据库中读取一些数据时,数据都可能在全球范围内传输数百甚至数千英里。
即使数据以光速传输,下载HTML页面也可能需要几秒钟,特别是在添加更多请求和加载到页面中的数据量增加的情况下。
随着浏览器的改进和计算机变得更强大,更具交互性的网页变得更加普遍,这一切都要归功于JavaScript。下拉菜单、弹出式菜单、日期范围选择器、交互式图表,甚至交互式地图都成为可能。
使用Ajax,Web页面可以使用新数据进行自我更新,而无需用户完全重新加载页面。这让Web页面感觉更像桌面应用程序,可以让您更新数据并几乎立即看到结果,而不会出现屏幕空白,也不会从头开始呈现。
随着计算机开始变得更快,JavaScript越来越成为网页功能的核心,Web开发人员开始厌倦编写JavaScript代码、PHP代码、HTML代码和CSS代码…。并且必须确保所有这些语言很好地结合在一起,并且必须指导他们所有的团队成员使用如此多不同的技术…。
所以他们想,“如果我们抛弃PHP,只使用JavaScript呈现整个页面,直接在Web浏览器中运行,会怎么样?这样我们就少了一种编程语言了!“。
而这正是他们所做的!引入了像jQuery这样的库,这使得使用JavaScript动态更新Web页面和使用Ajax获取数据变得更加方便,许多人认为jQuery是自切片面包以来最好的东西。
后来,像Ember.js和Angular.js这样的JavaScript框架出现了。(这些链接指向2010年代初这些网站的快照-请查看它们!)。这些框架比jQuery稍微复杂一些,但是它们允许人们在编写Web应用程序时非常高效。他们鼓励人们在客户端编写大部分代码,而不是过多地担心服务器端,从而简化了Web开发。
大约在这个时候,“单页面应用程序”(Single Page Application,SPA)的概念就形成了,即一个Web页面只向服务器发送一个获取初始HTML的请求,然后使用JavaScript和Ajax完成对页面的每次更新,而不是完全重新加载页面。
客户端呈现、JS框架和SPA的“新世界”如下所示:
客户端渲染让Web开发人员和技术公司非常满意。他们可以通过让用户在自己的机器上执行代码来节省计算成本,而且编写和维护主要在客户端运行的代码要比同时用PHP和JavaScript编写代码容易得多。
随着jQuery、Ember、ANGLING、REACTION和VUE等库的引入,以及Create-Reaction-app和Bower等工具使得使用这些库变得更加容易,在Web浏览器中完全呈现变得更加方便和时尚。
客户端呈现对于提高工作效率非常重要,因为它使开发人员能够将主要精力放在JavaScript上。但这对用户来说不一定是更好的。
以前,使用服务器端呈现时,浏览器只直接从服务器请求最终的HTML响应,并且可能会加载一些脚本来向页面添加更多内容。
现在,使用客户端呈现,浏览器接收一个基本上是空白的HTML页面,然后开始下载JavaScript,然后解析、编译和执行JavaScript,然后生成HTML,最后呈现页面。
当多个脚本和其他文件(如图像和CSS)同时加载时,加载时间会变得更糟,这通常是现代Web应用程序的情况。
现在,您可能会认为浏览器、数据中心、CPU、磁盘驱动器、网络基础架构、缓存、RAM都随着时间的推移变得越来越好、越来越快,那么这些额外成本是否值得注意呢?
嗯,这些进步还不够快,跟不上现代Web应用程序的需求。更糟糕的是,在资源较少的国家(这些国家的平均计算机更老,功能更差,互联网基础设施没有那么频繁地升级),用户的体验更差,网页加载非常慢,令人痛苦。
还有一个更紧迫的问题:移动网络。越来越多的人使用他们的移动设备访问网页。当智能手机和笔记本电脑首次问世时,它们的功能只有台式电脑的一小部分,而且使用Angular.js这样的框架构建的客户端渲染页面实在太慢了-手机本身的功能还不够强大,无线网络速度也没有今天那么快。
除了比服务器端渲染速度慢之外,客户端渲染还带来了另一个巨大的问题:搜索引擎优化(SEO)。
如果你不知道SEO是如何工作的,这里有一个简短的总结。像Google这样的搜索引擎有称为“Crawler”的特殊程序,它通过从精心策划的列表Web页面(例如wikipedia.org)开始“爬行”Web,然后跟随来自这些页面的所有可点击链接,然后跟随来自这些页面的链接,依此类推。最终,它们将覆盖“公共网络”的每一个部分。
对于客户端呈现,回想一下,服务器发回一个基本上为空白的初始HTML响应,然后由JavaScript更新该响应。这是一个问题,因为搜索引擎开始从服务器返回空页面,而现在服务器中只有<;script>;标记,需要运行这些标记才能看到最终页面!因此,客户端呈现的页面被认为具有“糟糕的SEO”。
自然,搜索引擎通过模拟真实的浏览器并实际运行页面上的所有JavaScript,然后在所有脚本运行完毕并且页面完全“可见”之后扫描最终页面,从而解决了这个问题。
然而,这种解决方案本身也引入了许多问题。搜索引擎在扫描页面时模拟Web浏览器的速度更慢、成本更高,而且通常更容易出错。谷歌甚至还编写了一份全面的指南,指导如何让你的网页对搜索引擎优化(SEO)友好。
“太棒了,”各地的开发人员都这样想。“在开发Web应用程序时,我们需要担心的问题更多!”
许多已经开始使用客户端呈现的Web开发人员在意识到他们的页面太慢时,最终后退了一步,并进行了一些思考。
他们意识到,最终,他们必须切换回服务器端渲染。但与此同时,他们希望远离PHP的危险。
幸运的是,创建了Node.js-一种允许用JavaScript编写Web服务器的技术!
很多人一开始都对Node持怀疑态度--毕竟,即使在功能强大的Web服务器上运行,JavaScript也很慢。但至少在服务器上运行JavaScript比在小型移动设备上运行要快!此外,随着JavaScript变得越来越好、越来越快,仅通过安装软件更新,基于节点的服务器就变得越来越快!js的性能问题变得越来越不成问题,许多开发人员开始在服务器上使用JavaScript。
与此同时,NPM生态系统蓬勃发展。越来越多功能强大的开源JavaScript库变得易于在浏览器和服务器上使用。创建了像Meteor这样的Node.js框架,进一步模糊了客户端和服务器端开发之间的界限。
同时,人们也不想抛弃像ANGLE这样的Web框架并做出反应。ReactDOMServer、VUE-SERVER-RENDER和ANGLE Universal等库使得使用与客户端相同的代码在Node.js服务器上呈现应用程序变得更加容易,如果页面改为客户端呈现的话。
这些框架在初始页面加载中引入了水合步骤,允许客户端JavaScript从服务器呈现的JavaScript停止的地方继续。这种方法允许客户端更快地获取HTML页面的重要部分,然后以开发人员最少的工作逐步增强页面的交互性。
在这一点上,生活相当不错。我们现在回到服务器呈现的页面,它们在客户机上要轻得多,而且更智能,因为它们能更快地将初始HTML响应传递给客户端。
当与惰性模块加载、代码拆分和捆绑等技术相结合时,这个新世界可以产生一个比完全客户端呈现的页面加载速度快得多的页面。
因此,在这一点上,看起来我们已经解决了大部分问题,我们有一个相当好的系统在运行。
我们可以用JavaScript编写所有代码。页面主要呈现在服务器上。我们仍然可以使用我们非常喜欢的Web框架,比如ANGLE和Reaction。
使用客户端水合的服务器端渲染设置起来并不容易!即使使用Meteor等框架和现代Reaction工具(如Create-Reaction-app),开发人员也必须阅读大量文档才能理解服务器端呈现是如何工作的,为什么需要它,以及如何组合它。对于大多数想要完成某件事的人来说,这实在是太多的工作了。
并非所有页面都包含需要Web服务器从数据库读取的动态数据。事实上,很大一部分Web页面可能只是静态的HTML文件,就像它们在Web非常非常早期的时候一样。登录页面、帮助页面、联系人表单、服务条款/隐私政策页面、职业目录、网站地图和博客都是可以是静态页面的示例。
更进一步,即使从数据库读取的页面也可以表示为静态页面!应用程序的“骨架”HTML可以直接发送到客户端,然后客户端可以发出获取数据的Ajax请求。因此,理想情况下,我们不需要复杂的Web服务器来托管我们的页面!我们只需要一个单独的API服务器,静态HTML文件可以向该服务器发出请求。
“但是为什么我们希望所有的HTML文件都是静态的呢?这不是意味着我们的功能丰富的应用程序会减少吗?“。
嗯,“静电”并不意味着“不动!”静态页面可以加载自己的脚本,包含复杂的JavaScript和CSS。然后,脚本可以对页面执行“动态”操作。您甚至可以使用Reaction创建静态页面。(剧透提醒:这就是Next.js要做的!)。
“这种静态文件方法如何改进呢?为了获取静态文件,我们仍然需要制作一个Web服务器,对吗?那么,为什么不直接从我们酷炫的Node.js服务器请求文件,它将执行我们的服务器端动态渲染呢?“。
首先要了解的是,当您访问网站时,您的Web浏览器在收到Web服务器的响应之前无法执行任何操作。因此,这个初始HTML请求是整个页面加载序列中最大的单一瓶颈。即使您的页面加载了几十个脚本和样式表,并且您已经做了大量的优化以使它们都加载得非常快,但在初始HTML返回之前,所有这些都不会发生!
因此,我们非常希望确保浏览器尽快返回我们站点的初始HTML响应。
“那么,静态文件与快速返回的初始HTML响应有什么关系呢?难道我们不能在靠近用户所在的地方,在全球范围内运行我们的服务器的大量副本吗?那样的话,发往我们服务器的请求就会以超快的速度返回。“。
当然,这是一种方法。但是那也是非常昂贵的!大多数人负担不起让这么多服务器始终在全球运行的费用。
幸运的是,我们有CDN,这是廉价的全球机器网络,针对在世界各地存储静态文件进行了大量优化。如果我们能以某种方式确保我们所有的Web页面都只是静态的HTML文件,那么我们就可以利用CDN在世界各地廉价地分发我们的应用程序,使其随时可供用户使用。
附注:在最新的Web行话中,您可能听说文件是从“边缘”提供的--这几乎就是指的。您可能也听说过Google的“AMP”页面-AMP利用Google的CDN来存储和提供特殊类型的HTML文件(称为AMP文件),这对HTML施加了严格的限制,以防止它执行任何会降低初始页面加载速度的操作。
因此,有了CDN提供的静态HTML,我们可以超快地将初始HTML提供给用户,如果页面足够靠近CDN边缘,页面几乎可以立即加载。
但它会变得更好。如果用户已经访问过某个页面,那么HTML文件可能已经存储在他们的浏览器缓存中。如果缓存的HTML已经是最新的,则CDN服务器返回304 NOT MODIFIED,并且浏览器知道直接从磁盘提供HTML。CDN甚至不必将HTML文件发送回浏览器!
有了缓存和CDN,Web页面的加载顺序现在看起来更像这样:
是!。初始页面加载序列可以使用大量巧妙的技术(如预取、预加载、预连接、SWR、字体和样式表内联、服务工作者缓存等)进行优化-但我不会在这里讨论所有这些技术。我想要关注的主要加速是通过提供静态HTML页面以使其可以被CDN服务器缓存而获得的,因为这种单一的加速对页面加载时间有最大的积极影响。
所以,现在我们知道CDN技术是我们可以使用的主要工具,以确保尽可能快地返回初始HTML响应。
考虑到这一点,下面是我们的新策略,以确保我们的站点尽可能快地加载:
如果我们站点上的某个页面是100%静态的(不包含任何动态内容),那么我们应该确保它在CDN上作为静态HTML文件可用。否则,用户将不得不向我们的服务器发出不必要的请求,而我们的服务器可能离他们很远,并且将通过为每个请求重新计算完全相同的HTML输出来招致不必要的成本。
如果Web页面确实具有动态功能,那么我们应该尝试将尽可能多的页面设置为静态的,这样静态部分几乎可以立即加载,然后我们应该通过从服务器获取所需的数据来增强页面。
好的,这看起来是个不错的策略。但是,我们如何真正实现这一点呢?我们需要编写哪些代码?我们是否必须为静态页面和动态页面维护单独的代码基?我们是否必须用纯HTML/CSS编写静态部分,然后使用普通的旧式JavaScript和Ajax来更新HTML(旧的、不方便的操作方式?)。
因此,我在文章开头附近提到,Next.js的杀手级特性是自动静态优化。它完全实现了我们在上面讨论的这一策略,使站点尽可能多地保持静态,并生成对CDN友好的。
..