当前位置: 首页 > 后端技术 > Node.js

基于umi的seo预编译

时间:2023-04-03 12:08:48 Node.js

1.单体应用框架项目介绍。打包文件中只有一个index.html作为入口,根据页面的路由加载对应页面的js。当项目需要支持SEO时,如果条件允许,可以选择node作为同构方案,配合react-router-config匹配routes中的组件,然后通过rendersToString方法打印出内容注入到html模板。这种方案的好处是可以支持动态路由,后端动态获取数据。缺点是每次访问需要生成一次,引入节点服务。如果在访问网站之前对html进行预编译,多个路由对应多个html,这就是下面要介绍的预编译解决方案。在umi项目umirc.jsplugins中配置预编译非常简单:[['@umijs/plugin-prerender']],ssr:true,2.预渲染插件在umi中打包后,按照url中的routes访问ssr类似于构造一个虚拟访问生成html。routes会生成所有htmlumirc.js['@umijs/plugin-prerender',{include:['/'],exclude:['/help']},]除非指定黑名单和白名单。三、ssr放umirc。js中的ssr设置为true后,会在dist文件夹下生成一个umi.server.js文件,该文件以/src/pages/.umi文件为入口,包括dist/生成的所有其他大文件*.js文件,并在环境变量上进行了处理。1.区分浏览器打包__IS_BROWSER/src/pages/.umi是每次打包后产生的中间结果。查看代码会发现,它使用了__IS_BROWSER变量来区分浏览器和node环境,而umi.server.js是将__IS_BROWSER变量替换为boolean结果,所以在业务代码中,可以直接使用__IS_BROWSER变量来区分你的逻辑。比如一开始页面有加载等待缓冲的效果,可以使用__IS_BROWSER取消加载,避免编译后的内容失效。上面提到的runInMockContext加载效果的区分,也可以通过配置中自定义环境变量来自定义['@umijs/plugin-prerender',{runInMockContext:{__isCustomEnv:true}}]2.mockWindowumi-server正在调用umi.server.js会将模拟窗口对象附加到全局变量。比如在业务代码中访问window.location.url,得到的结果和浏览器环境下是一样的。3.GetInitialProps想在预编译前的html中放入一些内容,但是实际业务中不需要展示这些内容。这时候可以选择在routes下定义的组件中添加getInitialProps方法(1)StaticcontentfunctionIndex(props){returnprops.nodeContent||'helloworld'}Index.getInitialProps=()=>({nodeContent:'我专门为seo添加的内容'})exportdefalutIndex将不经常更新的内容放入getInitialProps中硬编码,生成的内容是为了seo抓取的,但是它js执行后会刷新。(2)动态内容函数Index(props){returnprops.nodeContent||'你好世界'}Index.getInitialProps=()=>{returnAPI.getData();//promise==>{nodeContent:'dynamiccontent'}}exportdefalutIndex返回一个promise,也可以传递给组件的props,适用于内容不固定的场景。(3)动态路由在某些场景下,需要将路由信息传递给后端来获取动态内容。如果项目原来的动态路由配置如下{path:'/users/:id',component:'../pages/users'},新建一个文件枚举usersroute-users-下的所有idconfig.jsconstusersRoutes=[{path:'/users/10',component:'../pages/users'},{path:'/users/11',component:'../pages/users'},{路径:'/users/99',组件:'../pages/users'},...];exportdefalutusersRoutes会将userRoutes添加到umi的路由配置中,然后列出usersRoutes的路径并添加到pre-render的include中生成枚举动态路由html动态路由信息可以在props函数中获取Index(props){返回props.nodeContent||'你好世界'}Index.getInitialProps=({location})=>{returnAPI.getData(location.pathname);//promise==>{nodeContent:'dynamiccontent'}}exportdefalutIndex4.Dynamictitle,metaBaidusearchTDK需要,为每个页面生成不同的关键词,描述,标题,提高搜索引擎的索引权重。importHelmetfrom'react-helmet';{`一站式数据+增长平台`}['@umijs/plugin-prerender',{runInMockContext:{__isCustomEnv:true},postProcessHtml:($)=>{常量头盔=Helmet.renderStatic();consttitle=helmet.title.toString();constmeta=helmet.meta.toString();constlink=helmet.link.toString();if(title!==''){$('htmlhead').prepend(title);$('htmlhead').append(meta)$('htmlhead').append(link)返回$;}},],4.扩充1.图片umi默认给图片加上一个阈值。当小于这个值时,生成的图片使用base64。但是预编译生成的html中会产生大量的base64字符,使html变大。这里可以设置图片的阈值来减轻html的负担umirc.jschainWebpack(config){config.module.rule('exclude').use('url-loader').tap((options)=>{return{...options,limit:1,};});}2。umi在页面闪烁时使用默认的renderToString方法,renderToString会在根元素上添加data-reactroot属性,如果内容没有变化则不会重新渲染。但是因为umi使用了document.ejs来渲染整体的html,在html根元素上添加了data-reactroot属性,所以第一次进入页面时会出现闪烁。简单的解决办法是:1.在根元素上硬写data-reactroot属性2.在最外层加一层className,作用是设置display:none。注意:不能作为样式直接写在元素上,会被搜索引擎识别。也不能把className设置成类似hide的名字,这样也容易被识别