从零开始用React搭建自己的技术博客,遇到的问题
前段时间,我花了些时间跟着教学视频自学了React,所以也想着自己用所学的技术做一个个人博客网站。
我也不多废话,直接列出自己在开发过程中所用的技术和遇到的一系列问题以及解决办法。我相对于大多数刚学React,也想做一个练手项目的同学而言,我的个人经验可能很有启发意义;因为我遇到的问题,大家也很可能遇到。
首先,这个博客网站包括3个部分:博客前台、管理后台、接口中台。这3个部分也应用了不同的技术,前台博客使用了next.js,通过服务端渲染(ssr:首屏加载更快、利于seo等),后台管理使用的是React做的SPA,其中UI框架用的是Ant Design;中台用的是egg.js(基于koa.js的上层框架)。
对于很多刚学了React的同学而言,肯定是会用React开发spa的(建议拥抱react hooks,顺应趋势),而对于中台接口可能大家也会使用express、koa等等去实现,这些我就不再多说。而next.js,在国内讨论的没有那么多(我遇到问题不容易查到),这可能存在问题。
所以,我遇到的问题中我觉得值得讲的主要包括next.js;而另一块就是作为前端工程师不太懂的项目的部署(我也没那么懂,但我会往简单的讲让大家理解)。在这里,我就恬不知耻地挂一下自己博客的地址,欢迎大家访问:immortalboy.cn。
大家知道,SSR是的好处是可以优化SEO、同时能加快首屏加载速度的。因为页面是在服务端渲染的,页面上的接口请求也一同在后端完成了。所以我要说的第一点:以往我们在生命周期里请求接口的代码(或者是在useEffect里请求的代码),需要写在别的地方。next..js中提供了一个方法getInitialProps,所有在useEffect里调用的接口应当拿到这里面来。
(next.js的最新版本中,更推荐使用getStaticprops和getServerSideprops来代替getInitialProps;但是使用getInitialProps没有问题,而且使用后者可能会出现编译时的ESLint的警告,我建议使用getInitialProps)
第二点,也是初学者容易犯的,不是所有的页面都需要服务端渲染,真正需要服务端渲染只有一级导航的页面,所以对于详情页一类的二级页面完全可以按照SPA的开发习惯使用UseEffect 。
由于next.js在开发中代码和SPA的区别不大,像我这种初学者就犯了这个错,我把所有的页面都使用了UseEffect而忘了通过getInitialProps来达到服务端渲染。
所以,我上面罗里吧嗦地说了半天就两点:
- 使用
getInitialProps代替UseEffect运行页面加载时调用的接口代码; - 只需要在一级导航页面实现SSR;
- 服务器带宽也决定了加载速度,所以为了省钱,个人博客不一定要那么快(带宽很贵);
至于代码层面的,我还没有资格去讲,很多人可能用的都比我熟练,我也没必要浪费大家的时间。 下面我要将的就是项目部署,我在这里吃了不少亏,因为没有经验。我先说说我的情况:我不会linux命令,所以服务器买的是window server,网站的文件服务器用的是nginx(nginx我也不熟)。
下面到了干货阶段(希望算是)。现状是,管理后台SPA会打包成静态页面,前台博客构建后是一个本地服务(默认端口3000),中台接口egg.js也是一个本地服务(端口7001)。现在问题来了,服务器上本地访问可以,但是一旦通过域名访问就行不通。 对于这种情况,很多同学可能想到了,可以通过nginx反向代理实现。只要把服务器的端口代理到本地的服务的端口上就可以了。
server {
listen 8001;
server_name immortalboy.cn;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://127.0.0.1:7001; #反向代理
}
}
对于博客前台,需要把nginx的80端口代理到前台服务的3000端口。
server {
listen 80;
server_name immortalboy.cn;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://127.0.0.1:3000; #反向代理
}
}
而管理后台,我是用了一个二级域名,同样监听80端口(默认端口),因为后台是部署在nginx内部的SPA,没必要再代理了。
但是如果需要自己的网站支持https呢(可以通过服务器厂商申请免费证书)?我们知道https只监听443端口,显然上面的方法行不通了,因为我们的中台是监听的8001端口的。
这时候,因为有两个服务都需要反向代理,但是我们只有一个443端口,所以我们这时候不能够拿端口去区分这2个服务了。只能通过路由去匹配。对于博客前台,变化不大:
server {
listen 443 ssl;
server_name immortalboy.cn;
// 证书部分省略,避免赋值产生误导
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://127.0.0.1:3000; #反向代理
}
}
通过路由的话,匹配方式如下:
location /api {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://127.0.0.1:7001; #反向代理
}
大家如果和我你一样对于nginx不太熟练,可以参照我的办法去解决。
除此之外,我们知道egg.js本身是集成了进程管理功能的,所以我们不用处理。但是对于next.js我们需要通过pm2来做进程守护,通过pm2来管理。在这里,我也遇到了一个坑,可能大家也会遇到,所以我先给大家打下预防针。我先列一下常用的pm2命令
pm2 list // 列出所有进程
pm2 delete id/进程名 // 销毁一个进程
pm2 logs // 打印日志
pm2 start npm --name '进程名' --run product // 这里的product实际上是npm中配置的npm script里的脚本命令
// eg: pm2 start npm --name 'blog' --run product
上面的命令中比较难理解和可能会出现就是最后一行,实际这行命令的意思是让pm2开启了一个指定名称的进程,运行了npm script里的指定命令。大家多试几次就能明白它的意思,但是如果实在window server下,即便命令是正确的,也可能会出现问题。因为pm2很可能找不到npm,这个时候我们需要使用npm脚本的绝对路径来代替npm,上面的代码更改后为:
pm2 start C:\software\Nodejs\node_modules\npm\bin\npm-cli.js --name 'blog' --run product
上面的路径是服务器中npm安装的实际路径,每个人都不尽相同,请注意。
在我实际开的过程中也遇到了其他的问题,但这些都不具有共性,是代码层面的,我就不再多说。