网页客服,欢迎咨询

海外项目的SSR开发实践

2025-01-06 21:45:03 189
  • 收藏
  • 管理
    总篇111篇 2021年第2篇前言进入海外项目的初期,从外包团队中接手两个Vue?CSR的项目。在国际化的背景下,项目对SEO及社媒分享的需求是优先级最高的。之前的项目在这些方面有很大的提升空间,如果在旧有项目的基础上去实现SEO的需求,需要团队去了解针对CSR架构的Lambada方案。另外旧有项目的性能存在一定优化空间。经过考虑,开启新的项目来继续完成海外产品的需求是更优的选择。SSR的优点是SEO友好,有更短的白屏时间,看上去和需求完美契合。那么接下来需要选择前端框架。在Vue和React之间进行调研,结果如下:Vue支持单向数据绑定和双向数据绑定,但是项目已经使用的Vue的版本在 2.6.11,Vue3的发布时间不定,与之配套的UI库? Element-UI几乎是停止维护的状态。React的下载量更高,每个月都有更新的小版本,社区活跃。并且有着和国际化产品设计效果一致,使用Google Material Design风格的UI库Material-UI。Next.js、Nuxt.js是目前成熟的同构框架,前者基于React,后者基于Vue。有了这些框架,开发者可以方便地搭建一个同构应用:只对首屏同构直出。考虑到Vue和React的社区活跃度及UI生态,决定一边维护历史项目,一边循序渐进得使用Next.js开发新业务功能,对历史功能进行重构和优化,进行服务器端渲染。接下来,笔者就分享一些项目中遇到的一些技术细节点,希望对大家有所帮助。自定义页面路由基于搜索引擎优化的需求,需要特定的页面路径。比如英国经销商页面要求的路径为/uk/dealer,德国经销商页面要求的路径则为de/handler。Next.js的页面路由能够提供自定义的动态化路由配置,相应的文件名成需要依据路由的要求写成:? ?pages/[locale]/[content].js。对应的query为:{?"locale":?"uk",?"content":?"dealer"?}{?"locale":?"de",?"content":?"handler"?}当页面路径有更多的参数要求时,这样的文件名就显得过长。对比之下,自定义的路由方式显得更加灵活。router.get(['/:locale(uk)/dealer','/:locale(de)/handler'],?(req,?res)?=>?{//?第四个参数?`query`?用于入口文件使用?getServerSideProps?方法时,将其传入到?useRouter?中//?注意在命名路由时,?query?与?params?不能重名const?query?=?{?...req.query,?...req.params?};return?app.render(req,?res,?'/demo/post',?query);});Next.js 获取数据Next.js会在每次请求时候,在服务端调用? ? getServerSideProps这个方法。这个方法只会在服务器端运行,主要是升级9.3之前的getInitialProps方法。举个例子:NewsPage是一个页面组件,它接收在服务器端就请求到的数据,并利用这些数据进行首屏的数据渲染。你可以在getServerSideProps中对得到的接口数据进行处理。9.3之前的getInitialProps方法有一个很大的缺陷是在浏览器中req和re对象会是undefine。也就是使用它的页面,如果是浏览器渲染你需要在组件内再显式地请求一次,开发体验不太好。如果无特殊问题,建议使用getServerSideProps替代getInitialProps方法。//?此函数在每次请求改页面时被调用export?async?function?getServerSideProps({?req,?res?})?{const?{?query,?cookies?}?=?req;//?res?是?express?的方法,借助它去设置缓存res.set('Cache-Control',?'public,?max-age=60');?//?设置缓存1分钟//?获取接口数据const?news?=?await?request('https://.../detail',{locale:?query.locale})//?通过返回?{?props:?news?}?对象,NewsPage?组件在渲染时将接收到?`news`?数据return?{props:?{?news?},}}function?NewsPage({?news?})?{?//?这里接收到?news?数据//?Render?posts...const?{?title?=?''?}?=?news;render?( {title} )}export?default?NewsPage使用SSR需要注意的是:客户端和服务端有两套逻辑。服务端不能够使用window/Document等对象,cookie需要从getServerSideProps的req中获取,如果页面有CDN的话,需要单独设置白名单来实现cookie透传。客户端获取cookie和平时方法相同。下面是在客户端进行的request请求:const?getData?=?async?({?locale?=?'de'?})?=>?{let?obj?=?{};try?{?obj?=?await?request({url:?`/api`,params:?{locale,ids:?'1,3',},});}?catch?(error)?{console.error(error);}return?obj;};Next.js 内置 CSS 支持如果想要在Next.js项目中使用CSS Modules,不需要任何额外的配置,只需要将css或scss文件重命名为.module.css或.module.scss。CSS Modules会为每一个class名字追加组件名称的前缀以及哈希值的后缀,这样就拥有了局部作用域的独一无二的class name,不会相互影响。CSS Module 中可以使用 global 关键字声明一个全局规则。.title?{color:?red;}:global(.title)?{color:?green;}:global?{.title?{color:?green;}.detail?{color:?red;}}或者使用下面的方式function?HelloWorld()?{return?( scoped!)}Material UIMaterial UI最初设计受到了在服务器端渲染的约束,但后续能够支持服务器端的渲染。详细见官方文档。这也是选择它的重要原因。数据拿到后,开始进行首屏数据的渲染。为尽可能的减少服务器的请求,首屏也有一些非必要数据可以放在客户端请求,对此Material UI提供了一个骨架屏的组件,在首屏数据或图片未加载出来之时,渲染基础形状的骨架屏,告知用户,页面正在加载更多内容。{?imgSrc?()?:?()?}RWD 的实现可以依赖客户端的媒体查询进行断点的适配,也可以借助Material UI的useMediaQuery,编写一个通用的函数,方便使用页面的宽度或高度,判断页面当前的断点。import?{?useMediaQuery?}?from?'@material-ui/core';function?getDeviceType()?{const?isDesktopOrLaptop?=?useMediaQuery('(min-width:1128px)')const?isBigScreen?=?useMediaQuery('(min-width:1920px)')return?{isDesktopOrLaptop,isBigScreen}}const?{?isDesktopOrLaptop?}?=?getDeviceType();render?({?isDesktopOrLaptop?&?'detail'?})动态组件Webpack根据ECMAScript提案实现了用于动态加载模块的import方法。React v16.6版本提供了React.lazy和Suspend,用于动态加载组件。然而React.lazy和Suspend并不适用于SSR,next/dynamic能够支持服务器端的动态加载。import?dynamic?from?'next/dynamic'const?DynamicComponent?=?dynamic(()?=>?import('../components/hello'),{?loading:?()?=>},?//?自定义加载组件{?ssr:?false?}?//?在服务器端不包括该模块)function?Home()?{return?( )如果是视频详情页面,一般标记为如果一个页面上有多个需要标识出的内容, 可以重复meta标签,将认为og:type标签是每一段内容的起始处。特别针对于Facebook,需要加上指定的 id。通过指定twitter:site的值,Twitter可以将这些信息嵌入到分享的帖子中,展示图片等信息。如果当前页面对爬虫屏蔽,但又想要Twitter拿到meta标记内容,可以在robots.txt中特殊写明User-agent: TwitterbotDisallow:User-agent: *Disallow: /如果网站内容很少,比如资讯列表页面在多种筛选条件的叠加下,几乎等同于空白页或者详情页,需要额外标记以避免造成重复以及低质量的页面。Google Recaptcha为更好的贴近海外用户的使用习惯,我们选用了? ? ?Google Recaptcha来实现人机验证。Google Recaptcha分为二代机器人和三代机器人。三代机器人对于用户是无感知的,它会返回一个 0 到 1 之间的评分,在没有任何用户交互的情况下验证该用户是否合法,在调用一些涉及风控的接口之前去调用它,可以自行根据分数判断是否允许用户继续操作。v2 版本是用户可感知的,登录按钮是最常见的使用场景。验证成功后就会看到下面的图片。将类似的基础逻辑都封装为Hook,为多个业务服务。具体使用方式如下:import?useRecaptcha?from?'./useRecaptcha';const?{?validate?}?=?useRecaptcha();const?vote?=?(recaptcha_code)?=>?{}validate({onSuccess:?(recaptcha_code)?=>?{vote({?recaptcha_code?});},});onSuccess是Google Recaptcha验证成功的回调,在里面我们再操作下一步的逻辑。具体的接入细节可以参考Google Recaptcha的官方文档。const?useRecaptcha?=?()?=>?{useEffect(()?=>?{loadScript(`${API_PATH}?render=${RECAPTCHA_V3_KEY}`,()?=>?{window.grecaptcha.ready(()?=>?{});},()?=>?{});})const?validate?=?(options?=?{})?=>?{const?{?grecaptcha:?Gre?}?=?window;const?{action?=?'social',onFail?=?()?=>?{},onSuccess?=?()?=>?{},}?=?options;Gre.ready(async?()?=>?{try?{const?recaphta_response?=?await?Gre.execute(RECAPTCHA_V3_KEY,?{?action?});onSuccess(recaphta_response);}?catch?(err)?{onFail(err);}});}return?{?validate?};}export?default?useRecaptcha使用hl设置国际化语言`${API_PATH}?render=${RECAPTCHA_V3_KEY}&hl=${region?===?'GB'?'en-GB'?:?'de'}`国际化文案为了进一步缩短FMP的时间,可以减小加载文件的大小,这其中可以操作的包括css样式,js文件,以及必要的国际化文本文件。将文本文件配置在组件内部,并通过Webpack提供的require.context,对当前页面下所有? ? i18n文件夹下定义的JSON文件,通过正则匹配语言环境并进行合并,将合并后的内容赋值到msgJson变量,最后得到的内容格式如下:{"comps.Header.Hello":?"Hello"}使用时,无论如何命名ID, 有组件名称作为前缀,就不用担心ID冲突的问题。import?{?useIntl?}?from?'react-intl';const?useI18n?=?()?=>?{const?{?formatMessage?}?=?useIntl();return?{//?文案t_msg:?(id,?params)?=>?formatMessage({?id?},?params),};};//?使用const?{?t_msg?}?=?useI18n();return?({{t_msg('comps.Header.Hello')}})具体的详细介绍可见于海外项目的 React 国际化开发实践。货币import?{?useIntl?}?from?'react-intl';const?useI18n?=?()?=>?{const?{?formatNumber?}?=?useIntl();return?{//?货币t_currency:?(value)?=>?formatNumber(value,?{?format:?'currency'?}),};};//?使用const?{?t_currency?}?=?useI18n();const?val?=?t_currency(value,?{?minimumFractionDigits:?2?});React-Intl插件依赖于原生Intl API,由于? NodeJS默认13.0+版本开始完整支持,所以在13.0以下版本需要增加适配,可以使用full-icu库进行polyfill,安装该npm包,然后启动node时进行一个路径指向即可。启动方式一 :?NODE_ICU_DATA=node_modules/full-icu nodemon src/server启动方式二 :?nodemon --icu-data-dir=node_modules/full-icu src/server总结SSR对页面的首屏渲染和SEO有很大的帮助,使用Next.js可以方便的实现SSR,其中关键在于getServerSideProps的使用。在此基础上,面对大量的业务需求,海外项目接入监控系统,用以及时发现和快速定位并收集记录线上异常,保证线上访问的稳定。尽最大可能的模块化和组件化,极大得提高开发效率和项目代码的可维护、可复用性。作者简介 海外项目的SSR开发实践
    上一页:深度学习在封面图筛选中的应用 下一页:浅谈研发数字化在汽车之家的落地实践
    全部评论(0)