作者:狼叔
Next.js是一个用于生产环境的React应用框架(官方介绍:TheReactFrameworkforProduction),使用它可以快速上手开发React应用(enablesyoutobuildsuperfastandextremelyuser-friendlystaticwebsites,),而不需要花很多时间和精力去折腾各种开发工具。所谓的用于生产环境,是指功能和稳定性足够,有大量的实际应用案例。
在整理编辑大人给的《狼书(卷3):Node.js高级技术》修订版,给next.js一个明确观点:"整体来看,Next.js在Node.jsWeb开发领域是一个非常优秀的SSR框架,其众多优秀特性,外加Blitzjs这种周边生态,对于开箱即用的项目来说是极好的。从架构的角度,笔者以为Next.js是过度设计,从商业的角度,我认同Next.js的做法,易用性应该是开发领域最该重视的核心。"
之所以给出这样一个观点,是基于下面5个方面总结出来的。
next.js是什么?有哪些优点?为啥狼叔觉得它看起来像一个海王?
对比cra,umi和next.js,它们之间的差异是什么?
next.js生态除了vercel,还有rust和blitzjs,你都了解吗?
实现一个框架有哪4方面的思考?
在服务端渲染领域,对比next.js和ykfe/ssr,有何异同?
内容有点多,大家需要有点耐心。
1、Next是什么?
针对上面的点评,还需要明确一下next.js的介绍要点,不冲突
基于React,支持csr、ssr、isr、ssg等渲染或用于渲染的生成方式
支持ssr,但只是next.js的一个场景而已
next.js是Nodeweb领域优秀的ssr框架,这只是其一,其实年之后,next.js也开始支持serverless了
搭配vercel部署,对serverless支持极好
开箱即用,简单易用
下面看一下next的基本特性,如下。
简单汇总一下。
基础页面,数据获取,布局,国际化等,都已经是前端领域最佳实践了,这点上umi和next几乎一模一样。各种优化手段,图片,字体,脚本等,基本上都是最潮最新的好东西。
文件即路由,从rubyonrails开始,前端也借鉴了,umi大概也是借鉴了next的。ykfe/ssr也是借鉴了的。
自动按页面拆分代码,其实是webpack做的事儿,NextJS将每个页面单独打包,打开首页时会加载应用基础代码和首页代码,其它页面代码只会在打开时才去加载,这对于大型应用来说非常有用。
静态页面导出,可以将整个NextJS应用导出为一个静态网站,完美的JamStack
CSS-in-JS,内置了styled-jsx方案,样式写法遵循标准,并且样式作用域局限于组件内部而不是全局,避免了组件之间样式互相影响。
在今天,习惯Umi类脚手架和react开发的人,基本上会认为这些是标配,事实上,我们是需要感谢next.js团队的开拓之功的。
1.1、易用极致
nextjs很明显选择易用性,像一个海王一样,太懂用户的心了。所以它也是for企业,小客户和个人开发者的通用方案,从基础框架,到发布运维都帮你解决了,是极为方便的技术,以致于很多人都把它作为第一梯队的选择。
早期的next.js写法是非常简单的,就只有getInitialProps一个静态方法。
functionPage(props){returndiv{props.name}/div}Page.getInitialProps=async(ctx)={returnPromise.resolve({name:Egg+React+SSR})}exportdefaultPage
在egg-react-ssr技术调研期,我们分别看了next.js和easywebpack。
easywebpack在使用上,我不认可使用egg的worker来做。easy-team的方案本地开发采用了在Node中启动webpack编译bundle的方案,将服务端bundle打包在内存中,agent进程通过memory-fs提供的api来读取文件内容,并且通过worker与agent进程的通信,来让worker进程可以获取到文件的字符串内容。然后采用了Node的runInNewContextapi,类似于eval的方式去执行js字符。
next.js写法上是完美的。将请求方法抽取成静态方法,可以复用。另外在服务端渲染,先执行请求方法,是最高效的方式,比Biglet用的对象方法好。
在打包构建方面,本项目本地开发采用的方案为直接将服务端bundle打包到本地硬盘,通过webpack--watch的方式,来实现更新,同时本地开发的时候每次加载之前清空requirebundle的缓存保证刷新后server端的内容与client端一致。结合webpack-dev-server,上手难度低,实现代码更少。
为了适应更多的渲染细化场景,基于getInitialProps都能完成,但next又进行了拆分,让每个写法都有特定的应用场景。好处是用的人简单,缺点是增加学习成本。
除了核心特性上,做了渲染场景的细化外,next还做了非常多的易用性上的小心思,大家讨论最多的,大概就是image了。下面是山月在知乎上写的关于nextimage的体验。
内置ImageProxy,对图片进行转换、压缩,使得图片体积最小化。并配合图片懒加载与srcset一系列关于图片优化的小点子优化网络体验Next团队宣传地也颇为实在
Inordertouseimagesonwebpagesinaperformantwayalotofaspectshavetobeconsidered:size,weight,lazyloading,andmodernimageformats.
举一个栗子,如果你使用了一张pxxpx的PNG图片,放到了pxxpx的小方格里。那么next.js将会做以下操作优化性能。
内置Proxy服务把它压缩成px与px两张图,大幅度压缩体积
内置Proxy服务把它转成webp,一个体积更小的图片格式(比jpg小30%的体积)
内置Proxy服务把它转成75%压缩质量的webp,一个更小的体积与几乎无肉眼可见的图片质量变化
懒加载,看不到图片不加载
按需加载(不像Gatsby那样需要在部署项目前耗费大量精力去压缩图片)
由于内置Proxy运行时处理,可支持非本域名上的图片处理
优点说完了,这里说一下它的缺点吧
无法利用LongTermCache,浏览器二次加载时图片速度慢,使CDN也无法性能最大化
小图片无法内置为DataURI,大量的小图片将造成多次HTTP请求影响性能,比如我的这个网站:开发者武器库
无法支持多分辨率屏幕
CPU,如果部署在Vercel可以利用它的服务器资源做缓存服务,如果自部署处理图片需要消耗CPU。但这个也不算很缺点,只是引入了复杂状态,国内可以利用Ali_OSS或公司共有ImageProxy做图片缓存服务自定义一个loader,详见文档