Monthly Archives: 十月 2018

在不考虑SSR的情况下如何优化SEO

Meta标签

description和keywords两个类型的meta标签对SEO影响很大,直接输出给客户端的页面通常有三种:

一种是类似联系地址、公司介绍之类页面标题固定的页面,可以在前端层面直接写好描述和关键词两类meta标签。

还有一种是类似产品详情页这类页面,如果支持SSR的话一般会在标题里显示出产品具体名称之类的信息,在不支持SSR的情况下,可以填写一些比较范范、通用的介绍和关键词,比空着不写要好一些。

第三类是类似具体业务流程的页面,比如下单、支付过程的界面,这些界面可以不做SEO,或者像第一种那样处理。

H1、H2标签权重较高

尤其是h1标签,其内的文本内容权重较高,不要乱用,要放关键内容。

Sitemap

通过尽可能的完善sitemap(网站地图)来诱导搜索引擎爬虫来爬取页面。可定期完善后主动提交给百度等搜索引擎。

本地预渲染

phantomjs/Puppeteer是无界面浏览器,可用于编程实现在本地打包时通过无界面浏览器来访问尽可能多的页面url来得到渲染好的html结构,如果产品数量和详情在一定时间段内变化不大的话效果还是比较可观的。注意这种本地渲染出的页面只是供蜘蛛爬取所用的,并不供用户访问使用,服务端需要根据UA是蜘蛛还是用户浏览器来返回不同的内容。

这里有个问题就是,渲染的页面的url需要与spa单页应用的页面url相一致,而且不应使用hash方式的url路由(例如:index.html#hello),所以需要服务端配置一下以支持history模式(例如:index/hello)。对于不支持Html5 history API的浏览器(IE从10开始才支持),可以降级用户体验,使用跳转页面的方式取代无刷新跳转路由。

另外一个问题是,如果搜索引擎蜘蛛发现预渲染的页面与用户实际浏览到的页面差异较大,可能会被认为是在欺骗搜索引擎从而导致网站被降级,因此需要考虑以一个较小的周期(比如每天一次)去执行这个预渲染页的生成工作,并且在有内容更新的时候再执行一次。

目前发现prerender-spa-plugin有现成可用的与webpack集成的方案,也支持不使用这些构建工具的原生js项目。核心问题是需要制定待渲染的路由列表,碰到路由上需要带入参数的情况,需要看看是否可以获取到所有路由(及对应的路由上的参数):

  • 我们可以写爬虫(如果方便爬到所有数据的话,另外如果页面html结构重构了的话需要修改爬取逻辑);
  • 或者如果可以获取到数据库的只读权限(不需要写的权限),或者让数据库管理员导出数据来分析,来。

服务端预渲染

原理与本地预渲染一致,就是提前把静态页面渲染出来。但是服务端渲染与SSR(服务端渲染)是不一样的,不需要由服务端去获取各个原先由客户端ajax请求获取到的数据来拼接页面内容。

java服务在判断访问者为搜索引擎蜘蛛时,即时地去使用phontomjs等无界面浏览器来下载页面渲染页面内容然后将生成的内容返回给蜘蛛。

优点是给蜘蛛的内容与给用户的内容更一致。

有一个缺点是因为要等无界面浏览器下载完页面执行完ajax请求获取完数据才能得到渲染好的页面,过程会比较费时,所以可以考虑设定一个文件过期时间,首次预渲染后将对应的html文件保存到服务器上,下一次访问到该文件时使用该文件而非重新去预渲染,当检测到文件已到过期时间就重新预渲染页面然后保存,以此类推,这样平均访问速度不会很慢,而且对服务器端增加的压力并不大。

另外一个缺点是,根据以前写phantomjs批量爬取网页截图的经验,无界面浏览器并不是很稳定,就跟我们用浏览器打开很多页面一样,容易卡死啥的,如果页面数量很多的话,碰到新发布后一次性遇到蜘蛛大量访问新页面的话,服务器吃不吃得消需要再考虑下,服务器端预渲染也可以结合本地预渲染一起来。

参考资料

浅谈项目中node和依赖的node包的版本管理

这是最近才注意的一个问题。之前在上一家公司的时候,有个项目组的项目,经常发生有的人的电脑里安装项目依赖后无法启动项目的问题,然后每每都是让他从别的同事那里把node_modules文件夹打包拷贝过来,我刚去那个项目组的时候也碰到了这个问题,也是从别的同事那里拷贝了一份node_modules文件夹才能正常跑项目的,后来经过尝试发现好像如果我将npm命令的版本降低到2+再安装项目依赖的话就能正常跑了,但是这个显然是个很奇葩的现象,另外需要说的是他们那个项目也有package-lock.json这个文件的,这个项目因为不是一开始就在跟的项目,我也搞不拎清究竟是哪里出了问题。但是node包的版本管理依旧很重要,不管理的话更容易发生类似这样的问题。

一、不要直接修改package-lock.json/yarn.lock文件

如果要增删项目的依赖或者修改其版本号,不要手动直接去修改package-lock.json/yarn.lock文件,而要通过对应的npm命令或yarn命令进行操作:

1、通过npm增删包

2、通过yarn增删包

通过这些命令去更新项目依赖信息的同事,不仅会自动更新package.json文件,还会同步更新package-lock.json文件(如果用的是npm)或yarn.lock文件(如果用的是yarn)。而且这里有个特点,通过这种方式更新的package.json文件里的项目依赖都是将依赖包按包名字母顺序排列的,这样比较好找包的版本信息。如果你打开一个项目的package.json文件发现里面的包名排列没有顺序乱七八糟的,那就说明这个人是直接自己手改。

二、指定node包到具体的小版本号

因为:

1、你不能信任第三方包都完全按照语义化版本号规则去更新版本号;

2、你不能信任按语义化版本号更新版本号的第三方包在修复bug或添加新功能时不会引入新的bug;

3、第三方包在更新版本号的时候可能会更新它对应的依赖包的版本号,第三方包依赖的第三方包的版本号变动又可能引发上面的问题。

三、不要在同一个项目里同时混用npm和yarn

假设你通过 npm i -S a 命令添加并安装了node包a,并且实际安装的版本是1.0.1,这时候具体的版本信息是记录在package-lock.json文件里的,过了一个月另外一个同事通过 yarn install 命令安装包a时,由于具体的版本信息在yarn.lock问及那种是不存在的,所以完全有可能这位同事实际安装的是1.1.2版本,这样就会造成包的版本管理混乱的问题,反过来也是一样,不再赘述。

四、团队开发时应当同统一node版本号

团队合作开发的项目中,大家各自电脑里的node版本号也需要进行统一,如果不统一,比如甲本地 node --version 为9.2.1,乙本地使用 node --version 为10.0.0,那么可能会有两种问题:

1、如果一个程序的版本遵循语义化版本的规定,那么a.b.c这样的版本号中,a的变动表示的是较大的版本升级(可能会有不向前兼容的新API等)b的变动表示的是较小的、向前兼容的功能更新,c的变动表示的是一些bug修复。但是我们不能保证第三方程序都严格按照这个语义化版本的规定进行版本号的命令,另外也无法确定只是更新了版本号的c部分的是否只是修复了已知bug而没有再次引入新的bug,所以我个人是建议直接把node版本号进行统一,而不是给出一个允许使用的node版本号区间

2、这里还有一个问题,比如乙在本地添加了一个依赖包,该依赖包要求node版本号10.0.0及以上,由于乙本地node版本号为10.0.0所以可以正常安装该依赖了,但是甲本地的node版本号为9.2.1,就无法安装该依赖包了,团队合作开发的项目,我们当然是希望大家都可以在本地正常安装项目依赖并运行项目的。

如果你本地有多个项目分别要求不同的node版本的话,可以使用nvm这个命令行工具。nvm的安装及使用都是非常简单的。

另外需要加一句:推荐使用标记为LTS的版本,这种版本官方会用较长的时间进行维护,所谓LTS,就是Long-Term-Support长期支持的意思。

五、强制约束node版本和使用npm还是yarn来进行依赖管理

我们当然可以只通过文件和口头约定的方式来约束大家都使用相同版本的node,并约束大家都使用npm或者yarn其中一种(不可混用)来进行依赖包的管理,但是在书面/口头约定之外,在代码上再进行一下限制会更稳妥一些。下面是我从vue2官方webpack模版的源码里抄过来并按自己的需求修改了一下的两段代码。

限制使用的node和yarn的版本:check-version.js:

不允许使用npm进行依赖管理(原理是检测项目根目录下是否存在运行npm install时生成的package-lock.json文件,npm-shrinkwrap.json是作向前兼容的,不是很):check-npm.js:

跟check-version.js对应的,需要在package.json文件里添加类似下面这样的代码(这里我认为yarn的版本可以需用限定的太死所以只是限定了一个区间,之所以要求小于2是因为从1都2属于大的版本更新了,现在yarn还没有出2版本,谁知道到时候对应的命令是否还能使用):

check-version.js和check-npm.js两个文件的使用方法很简单,在平时开发和打包命令对应的文件的开头,添加类似下面的代码即可(注意导入后的代码后面需要加一个括号去执行它,因为上面两个文件导出的都是函数):

 

一些关于以前的记录

这几年好像写的东西越来越少了,很多时候想写点啥,但是打开博客又觉得没啥好写的,或者写了一点草稿,发现也就只写那么几句索性也就一直放着或者直接删掉了。

今天我去翻了下很久没发表过东西的微博,最新的一条信息是2015年12月31日发的,时间点真是特别,正好是阳历一年的最后一天。

地铁上看到个看报纸的女孩,还看到了一个戴着耳机看编程视频的男孩

– 2015-12-31 10:11 来自荣耀6

然后逆着时光倒过来看了当时发的一些东西,发现有些摘录的句子写得还挺不错的:

  • 下雨了,我最讨厌在雨里骑机车,又湿又冷的。突然,机车骑进了隧道,没有风,没有雨,黄色的灯光,让我感觉好温暖。虽然,我知道隧道不是尽头,我将会再回到风雨里,但是,我多么感谢这一段的短暂的温暖。谢谢你,隧道。谢谢你。
  • 不论看过别人多少通达、坦荡和风轻云淡的经历,世事总莫测,人言如他无足轻重,愿你读完别人的故事也忘了他们。在做决定的时刻,只记对自己而言最重要的事。
  • 一个懵懂的小男孩看到地面爬行的蚂蚁会突然踩上一脚,以满足自己莫名的快感。
  • 善意本身并无不妥,但只要过了那么一点点,以善意之名行越界之事——这非常容易说服自己是在做好事,也容易说服自己容忍别人以同样方式对待自己——便可能造业。若有天才给出崇高名义加以煽动,以造就天堂的名义集体行为,通常会造就最邪恶的地狱。
  • 一个人,心中最难解的那些问题,通常不是源自知识的匮乏(求知可以谷歌百度),而是思维方式的禁锢。这些禁锢悄无声息,自己无法察觉,却总是能把人局限在一个狭小的认知牢笼中,纠结于不该纠结的问题,烦扰于纷繁芜杂的表象,而看不到一个更宽广的世界。

我想起去年还是前年,亦或是大前年的时候,在高中班主任凌老师的微信朋友圈上看到过老师发的一条信息,里面提到了高中时隔壁二班的一位女生,那位女生跟凌老师说她现在的想法和高中的时候一样,以后要当一个数学家,她好像是在清华还是北大念博士吧,不太记得了,重点也不是这个。重点是,“要当一个数学家”——这是一个成年人说的想法,而非一个小孩子随口而出的不用考虑成本、难度和代价的想法。