Next.js使用总结
前言
本文会总结使用Next.js在具体业务场景下碰到的一些大坑以及具体解决方案,在开始总结前先表达下对ZEIT团队的敬佩,感谢🙏他们开源出一款优秀的同构框架,解救了曾经蛋疼的陷在使用模版引擎做SSR项目的开发者(比如我),通过Next.js重构后的项目更加轻量化,性能上也有大幅度的提升,如下图
重构前:
重构后:
性能数据是通过ABTest使用开源的Nemetric抓取FetchTime
和FirstContentfulPaint
两个性能指标,然后传到kibana上对比,对比后的性能数据在不同纬度下提升20%-30%,这里多提一句可能很多人对优化后的效果很难感知到,或者优化的价值在哪,但实际上根据谷歌发布的性能为何至关重要,真的是一寸光阴一寸金,所以在看到这个数据对比后我的感觉就是:
前言讲完,就开始讲讲总结一下使用了大半年Next.js的感受了。
Next.js适用场景
首先写Next.js之前要先了解它适合用在什么地方,经过看文档总结无外乎以下三种:
- SEO WebSites: 需要SEO自然流量的项目,如果资讯站、博客站等
- Server Render WebSites: 用户增长业务型项目,需要保持较高转化率,如活动H5等
- Static WebSites: 静态网页,如app官网等
重点是第一点和第三点Next.js都做的非常的优秀,举个例子:
- SEO Sites现在基本只面向海外(也就是Google,至于国内搜索引擎什么的大家懂的),而Google推出了AMP框架专门用于提升Google搜索排名,简而言之要做海外业务的产品配套的官网之类的websites基本都会用到AMP,而Next.js刚好可以兼容AMP使用,这点很赞。
- 支持打包静态网页,换句话解释就是用Next写完一些没有接入服务端的静态页面后可以直接用
next export
打包成HTML文件,在不影响页面性能的下又可以让开发体验感没有降低。
如果你开发的业务满足上述三点中的两点,相信Next.js可以满足你当前的业务需求。
与Egg.js结合使用
Next.js官方github有一个example library,里面主要是Next.js与其他技术结合使用的一些demo,但没有与Egg.js结合的例子,而在Egg.js官方github有人提过issueEgg.js怎样去接入Next.js,官方给出的答复是Koa/Egg的底层实现与基于Express实现的Next有冲突,不建议两者结合使用。所以网上对如何把Egg.js和Next.js一起使用的资料比较稀缺。
解决方案:
Next.js+Egg.js配置
上面的搭建配置是经阅读了一点Next.js源码探索出来的,现在已经可以支持我司推广站正常运行。
按页面分割样式
在开发的时候由于VidMate Sites是多页应用,按预期是每个页面只需要加载对应页面的css文件和公共css文件,但是查看network的时候发现每一个页面都是加载同一个styles.css文件
经过查看Next的css插件next-css
源码定位到问题在哪
1 | if (!isServer) { |
上面配置的含义是全部fileExtensions
文件中引入的css文件全部抽取出来打包成styles.css
, fileExtensions
就是webpack配置
中的entry
这种做法对单页应用是很有用的,全部组件页面css文件集中成一个,原来的n个css文件请求减少至一个,但是对于多页应用来说这种分割方式是不适合的,因为跳转页面需要重新请求,这个时候需要做的是减少页面文件的体积,所以腾讯新闻使用styled-jsx
应该也是这个原因
解决方案:
使用styled-jsx
方案,自动打包到每个页面对应的js
中,但由于写styled-jsx
是在.tsx
中所以开发的时候不会有语法提示,所以可以用另一种方式引入scss文件转化为styled-jsx
,需要在next.config.js
中配置一下
next.config.js
1 | webpack: (config, { defaultLoaders }) => { |
兼容AMP
由于我司做的是海外产品需要做谷歌SEO,所以就用到了谷歌开源的AMP框架,这个框架主要是针对谷歌进行优化,兼容AMP是目前使用Next最大的问题,因为这相当于把两个黑盒框架组合使用,难度是可想而知的
AMP也是一个对可配置性限制很大的框架,特别是对css只能嵌入不能引入,并且大小限制在50000Bytes内,然内嵌的自定义css要求以<style amp-custom>.....</style>
方式写入,如果缺少amp-custom
就无法通过amp validator
。而按正常的css开发套路需要对全局样式做一个通用定义,特别是移动端做rem适配需要对html文档做一个初始值font-size定义。
而很操蛋的在<Head/>
组件使用<style>...</style>
定义全局样式是缺少上面提到的amp-custom
属性的,
使用<style jsx global>...</style>
又可能出现初始样式加载失败的情况
解决方案:
初始化样式存放在一个reset
文件,然后在页面样式文件中引入。
Typescript编译兼容
在使用Egg.js文档关于typescript配置的的时候当egg端使用esmodule
规范开发会无法通过编译,经过我本人的踩坑,终于发现是tsconfig配置有关,是的没错,就跟下面这一行有关
1 | "module": "esnext" |
module
的意思是指定生成哪个模块系统代码,而因为nodejs执行的是common.js
规范,所以改成common.js
node端使用esmodule规范进行编译就没有问题,但悲剧的是这个配置next是强制性的,就算改成common.js
也会变成esnext
,so,先凑合着用:)
我基于公司现有ts项目的tsconfig.json文件配置了两个tsconfig文件,为啥会有两个呢,因为在Nextv9版本中支持typescript0配置,所以会在编译中自动生成tsconfig
配置,但是这个配置对编译egg端就不太行,所以只能用这种折中办法,ts.egg.json
用于编译egg,tsconfig.json
编译next
,然后tsconfig.json
去继承ts.egg.json
,还有就是需要保持typescript
版本在3.7以上,这样在开发和生产编译中就不会产生编译报错
具体json配置可以到我的github上找,这里篇幅略长就不放出来了。
生产编译的时候需要先把egg自定义配置(app.ts
和ssr.ts
)打包编译,推荐使用npm run local-tsc
进行本地编译,打包到线上服务器后再使用npm run tsc
编译egg
端的业务代码
package.json
1 | "scripts": { |