周末花了二十多个小时,将自己的博客从React客户端渲染(CSR)升级到了NextJs服务端渲染(SSR),一方面是为了提高自己博客的SEO,也是为了练习学习。
然而第一次做,经验不是很丰富,国内的相关资料比较少,文档版本滞后,自己英文水平也捉急,查资料花了许多时间。这里将我遇到的问题做个汇总分享给大家。
这是我的博客欢迎大家访问留言 Cc技术人生
欢迎大家关注我的公众号:前端进阶攻城狮
Postcss问题/安装Less
首先是我的博客由于为了适配PC端与移动端,所以使用了postcss-px-to-viewport-plugin 随着屏幕宽度的变化,页面尺寸也相应变化。
然而最新版的Next使用的版本是8+,导致没有对css中的px单位进行vw的转换,而对postcss降级又会引发其他问题,于是无奈只能将所有scss文件转成less
这里提一句postcss-px-to-viewport-plugin在postcss 8+版本中会抛出废弃说明,建议更换成postcss-px-to-viewport-8-plugin
在nextjs中使用less
npm i next-with-less -D
在next.config.js中用withless函数包裹你的相关配置
const withLess = require("next-with-less");
module.exports = withLess({
...
})
嵌套路由/动态路由
路由规则
常规的单页面应用一般都是通过配置路由表来定义页面组件的渲染,在next中有一套约定成俗的规定:/pages下的文件名,就是我们的路由地址
例:
/pages/index.tsx ---> xxx.com
/pages/about.tsx ---> xxx.com/about
/pages/message/index.tsx ---> xxx.com/message
动态路由
当你需要通过params传参给到下一个页面时,比如访问/message/1 Router.push('/message/1')
这时我们在message目录下新建文件[id].tsx
然后在getServerSideProps函数的参数里获取
嵌套路由
在React或者Vue项目中,都可以通过声明一个路由的children以及在自身页面中提供<Outlet />或者<RouterView/>来实现路由嵌套。
然而在next中,我们通过定义一个layout组件,或者在pages/_app.tsx中定义好导航栏、侧边栏、底部等等
// layout/index.tsx
import { Meta } from '../layout/Meta';
import { AppConfig } from '../utils/AppConfig';
import Footer from './Footer';
import HeadNav from './HeadNav';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen flex flex-col relative">
<Meta title={AppConfig.title} description={AppConfig.description} />
<HeadNav />
<div
className=" flex-auto"
style={{
background: 'linear-gradient(225deg,#ffdee9,#b5fffc)'
}}
>
{children}
</div>
<Footer />
</div>
);
}
// pages/_app.tsx
import '../styles/global.css';
import type { AppProps } from 'next/app';
import Layout from '@/layout';
const MyApp = ({ Component, pageProps }: AppProps) => (
<Layout>
<Component {...pageProps} />
</Layout>
);
export default MyApp;
这里<Component />就是我们接下来页面的入口
浅层路由shallow
在使用Router.push路由跳转时,在第三个参数传递shallow:true页面只会改变url参数,而不会重新去进行获取数据。注意,这只适用于当前页面的修改!在我的项目里使用在右侧分类栏的点击。
SSR\SSG\ISR
NextJs很强大的一点在于能够同时支持这三点,根据你页面的实际情况需求来选择你需要怎么样的渲染方式
SSR服务端渲染
能够解决SEO和爬虫的问题,也是一开始我选择NextJs的原因,然而每次渲染都要去服务器请求数据,而一些文章可能几个月都不更新一次,无疑是浪费资源的。
export async function getServerSideProps(context: any) {
const initData = await request.post(APIS.ARTICLE_PAGE);
return {
props: {
initData
}
};
}
SSG静态站点生成
纯纯的静态页面,在构建时请求服务器获取数据进行生产静态页面,所以当数据变动时完全不会更新。当然好处也是显而易见的,快,很快啊,啪的一下就打开了。
export async function getStaticProps() {
const initData: Article = await request.post(APIS.ARTICLE_DETAIL);
return {
props: {
initData
},
};
}
ISR增量静态生成
当配置好重新构建的间隔时间,在间隔之后刷新页面才能看到动态变更后的数据
export async function getStaticProps() {
const initData: Article = await request.post(APIS.ARTICLE_DETAIL);
return {
props: {
initData
},
revalidate: 30
};
}
与SSG区别就是多了个revalidate间隔时长
环境变量
当我们在根目录下创建定义环境变量的文件例如.env.development或者.env.production文件,其中的值可以直接在getStaticProps、getServerSideProps函数中获取,因为这是定义了服务器端的环境变量,在React函数中是获取不到的,需要在定义变量的名称加上前缀NEXT_PUBLIC_这样浏览器和服务端都可以使用环境变量。
其他
目前遗留了两个问题
- 在React组件中的请求用的是相对路径,服务端或者静态站点生成时请求只能使用绝对路径去请求,否则就会报无法请求80端口,而我的后端服务并非是80端口,这点暂时没有很好的解决方案。
- 因为使用了
md-editor-rt插件去渲染markdown格式的文本,在预览模式下添加mdCatLog组件,可以看到文章内容的大小标题,点击可以跳转,类似掘金右侧的文章导航,而在我项目中无法正常跳转。
还望大佬指点解惑
开发阶段遇到的问题差不多就这些,上线部署就比较简单了,pm2后台挂机运行,nginx做个转发。
访问地址Cc代码人生