位置: IT常识 - 正文

【React】使用Next.js构建并部署个人博客(react extend)

编辑:rootadmin
【React】使用Next.js构建并部署个人博客

推荐整理分享【React】使用Next.js构建并部署个人博客(react extend),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:react from,react either,react .then,react index,react nexttick,react index,react extend,react next,内容如对您有帮助,希望把文章链接给更多的朋友!

👉 TypeScript学习:TypeScript从入门到精通

👉 蓝桥杯真题解析:蓝桥杯Web国赛真题解析

👉 个人简介:一个又菜又爱玩的前端小白🍬 👉 你的一键三连是我更新的最大动力❤️!

🏆分享博主自用牛客网🏆:一个非常全面的面试刷题求职网站,真的超级好用🍬

前言

关于博客系统,相信大家早已驾轻就熟,网上有很多以markdown驱动的博客框架,如vuepress,hexo等,这类框架的本质是生成静态站点,而个人开发的博客系统大多是使用数据库的全栈项目,这两种方式各有各的好处,这里就不做比较了

这篇文章我们将自己独立去开发并部署一个以markdown驱动的静态站点博客,所用技术栈如下:

ReactTypeScriptNext.jstailwindcssVercel部署

注意: 本文只是演示使用Next.js从0到1构建并部署一个个人博客项目,不会对项目构建过程中所用到的技术做详细的讲解,不过不用担心,只要跟着文章一步一步来,小白都能成功部署自己的个人博客!

项目仓库地址:https://github.com/Chen0807AiLJX/next-blog 最终效果可见:https://next-blog-eosin-six.vercel.app/

现在让我们开始吧!

开始之前请确保自己电脑上配置的有Node.js 12.13.0 或更高版本。

文章目录前言1、创建Next.js项目2、安装tailwindcss3、添加布局页面4、新建markdown文章5、解析markdown内容6、添加首页7、添加文章详情页面8、Vercel部署结语1、创建Next.js项目

要创建 Next.js 应用程序,请打开终端,cd进入到要在其中创建应用程序的目录,然后运行以下命令:

npx create-next-app@latest --typescript ailjx-blog

上述代码表示:通过create-next-app创建名为ailjx-blog的TypeScript版本的Next.js应用程序

用vscode打开ailjx-blog项目,目录结构如下:

在项目根目录终端运行以下命令启动项目:

npm run dev

打开http://localhost:3000/显示如下页面:

2、安装tailwindcss

在项目根目录终端运行以下命令:

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

生成tailwindcss配置文件:

npx tailwindcss init -p

此时项目里会多出两个文件:tailwind.config.js和postcss.config.js

修改tailwind.config.js文件里的content为:

content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", "./styles/**/*.css", ],

在pages文件夹下的_app.tsx文件的第一行添加:

import "tailwindcss/tailwind.css";

之后重新启动项目

3、添加布局页面

准备一张自己的头像(建议比例为1:1,这里演示用的头像文件名为author.jpg)

在public文件夹下新建images文件夹,将你的头像图片放入其中,并删除public文件夹下的svg文件

public文件为项目的静态文件,可直接通过地址访问,如访问演示所用头像:

项目根目录下新建components文件夹,并添加布局文件layout.tsx:

import Head from "next/head";import Image from "next/image";import Link from "next/link";const name = "Ailjx"; // 名称,根据需要修改export const siteTitle = "Ailjx Blog"; // 网站标题,根据需要修改interface Props { children: React.ReactNode; home?: boolean;}export default function Layout({ children, home }: Props) { return ( <div className='max-w-2xl mx-auto px-4 mt-12 mb-24'> <Head> <link rel='icon' href='/favicon.ico' /> <meta name='description' content='AiljxBlog——Ailjx的博客' /> <meta property='og:image' content={`https://og-image.vercel.app/${encodeURI( siteTitle )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`} /> <meta name='og:title' content={siteTitle} /> <meta name='twitter:card' content='summary_large_image' /> </Head> <header className='flex flex-col items-center'> {home ? ( <> <Image priority src='/images/author.jpg' className='rounded-full' height={144} width={144} alt={name} /> <h1 className='text-5xl font-extrabold tracking-tighter my-4'> {name} </h1> </> ) : ( <> <Link href='/'> <a> <Image priority src='/images/author.jpg' className='rounded-full' height={108} width={108} alt={name} /> </a> </Link> <h2 className='text-2xl my-4'> <Link href='/'> <a>{name}</a> </Link> </h2> </> )} </header> <main>{children}</main> {!home && ( <div className='mt-12'> <Link href='/'> <a>← 返回首页</a> </Link> </div> )} </div> );}

这里使用了几个Next自带的组件:

Head:向Html页面的head内添加内容,里面内容自己根据需要修改Image:渲染图像的组件,src地址修改为自己头像的地址Link :页面间跳转组件4、新建markdown文章

项目根目录下新建posts文件夹,添加一个markdown文件,如:

欢迎来到我的博客.md

---title: "欢迎来到我的博客"date: "2022-08-08"---## 欢迎你!

注意: 需要在每个markdown文件的顶部通过---添加元数据,元数据需要有title字段表示文章标题,date字段表示日期,如上面欢迎来到我的博客.md的元数据为:

---title: "欢迎来到我的博客"date: "2022-08-08"---

这些数据在我们渲染markdown内容时需要用到

5、解析markdown内容

需要安装以下插件:

remark-prism:代码高亮插件date-fns:处理日期gray-matter:获取元数据next-mdx-remote:用于解析和渲染markdown内容remark-external-links:对markdown内的链接添加rel和target,使其能够在新页面打开

在项目根目录终端运行以下命令安装上述插件:

npm i remark-prism date-fns gray-matter next-mdx-remote remark-external-linksnpm i @types/remark-prism --D

在项目根目录新建存放工具函数的utils文件夹,里面新建处理markdown文件的posts.ts:

import fs from "fs";import path from "path";// gray-matter:获取元数据import matter from "gray-matter";// date-fns:处理日期import { parseISO } from "date-fns";import { serialize } from "next-mdx-remote/serialize";// remark-prism:markdown代码高亮import prism from "remark-prism";// externalLinks:使markdown的链接是在新页面打开链接import externalLinks from "remark-external-links";interface MatterMark { data: { date: string; title: string }; content: string; [key: string]: unknown;}// posts目录的路径const postsDirectory = path.join(process.cwd(), "posts");// 获取posts目录下的所有文件名(带后缀)const fileNames = fs.readdirSync(postsDirectory);// 获取所有文章用于展示首页列表的数据export function getSortedPostsData() { // 获取所有md文件用于展示首页列表的数据,包含id,元数据(标题,时间) const allPostsData = fileNames.map((fileName) => { // 去除文件名的md后缀,使其作为文章id使用 const id = fileName.replace(/\.md$/, ""); // 获取md文件路径 const fullPath = path.join(postsDirectory, fileName); // 读取md文件内容 const fileContents = fs.readFileSync(fullPath, "utf8"); // 使用matter提取md文件元数据:{data:{//元数据},content:'内容'} const matterResult = matter(fileContents); return { id, ...(matterResult.data as MatterMark["data"]), }; }); // 按照日期从进到远排序 return allPostsData.sort(({ date: a }, { date: b }) => // parseISO:字符串转日期 parseISO(a) < parseISO(b) ? 1 : -1 );}// 获取格式化后的所有文章id(文件名)export function getAllPostIds() { // 这是返回的格式: // [ // { // params: { // id: '......' // } // }, // { // params: { // id: '......' // } // } // ] return fileNames.map((fileName) => { return { params: { id: fileName.replace(/\.md$/, ""), }, }; });}// 获取指定文章内容export async function getPostData(id: string) { // 文章路径 const fullPath = path.join(postsDirectory, `${id}.md`); // 读取文章内容 const fileContents = fs.readFileSync(fullPath, "utf8"); // 使用matter解析markdown元数据和内容 const matterResult = matter(fileContents); return { content: await serialize(matterResult.content, { mdxOptions: { remarkPlugins: [prism, externalLinks] }, }), ...(matterResult.data as MatterMark["data"]), };}

posts.ts里有三个主要的函数:

【React】使用Next.js构建并部署个人博客(react extend)

getSortedPostsData:在首页用于展示文章列表

getAllPostIds:获取指定格式的所有文章id(文件名),这个格式是Next所要求的

因为我们在写文章详情页面时需要使用动态路由,每个文章的id就是一个路由,并且我们使用的Next静态站点生成会在项目打包构建时直接生成所有的html文件,需要把每一个路由对应的页面都构建出来,Next会根据getAllPostIds函数返回的这种格式的数据去构建每一个html页面

getPostData:获取文章详情,在文章详情页面会用到

6、添加首页

首页会展示文章列表,会用到一个日期渲染组件,我们先创建一下

在components文件夹下新建date.tsx文件:

import { parseISO, format } from "date-fns";interface Props { dateString: string;}export default function Date({ dateString }: Props) { const date = parseISO(dateString); return ( <time dateTime={dateString} className='text-gray-500'> {format(date, "yyyy年MM月dd日")} </time> );}

修改pages文件夹下的index.tsx文件如下:

import type { NextPage, GetStaticProps } from "next";import Head from "next/head";import Layout, { siteTitle } from "../components/layout";import Link from "next/link";import Date from "../components/date";import { getSortedPostsData } from "../utils/posts";interface Props { allPostsData: { date: string; title: string; id: string; }[];}const Home: NextPage<Props> = ({ allPostsData }) => { return ( <Layout home> <div> <Head> <title>{siteTitle}</title> </Head> <section className='text-xl leading-normal text-center'> <p>你好,我是 Ailjx</p> <p>一个又菜又爱玩的前端小白,欢迎来到我的博客!</p> </section> <section className='text-xl leading-normal pt-4'> <h2 className=' text-2xl my-4 font-bold'>Blog</h2> <ul> {allPostsData.map(({ id, date, title }) => ( <li key={id} className='mb-5'> <Link href={`/posts/${id}`}> <a>{title}</a> </Link> <br /> <small> <Date dateString={date} /> </small> </li> ))} </ul> </section> </div> </Layout> );};export const getStaticProps: GetStaticProps = async () => { // 获取文章列表 const allPostsData = getSortedPostsData(); return { props: { allPostsData, }, };};export default Home;

修改styles文件夹下的globals.css如下:

a { color: #0070f3; text-decoration: none;}a:hover { text-decoration: underline;}img { max-width: 100%; display: block;}::-webkit-scrollbar { width: 5px; height: 5px; position: absolute;}::-webkit-scrollbar-thumb { background-color: #0070f3;}::-webkit-scrollbar-track { background-color: #ddd;}

删除style文件夹下的Home.module.css

此时运行项目,打开http://localhost:3000/可见:

7、添加文章详情页面

在pages文件夹下创建posts文件夹,在其中创建[id].tsx文件:

import type { GetStaticProps, GetStaticPaths } from "next";import Layout from "../../components/layout";import { getAllPostIds, getPostData } from "../../utils/posts";import Head from "next/head";import Date from "../../components/date";import { MDXRemote, MDXRemoteProps } from "next-mdx-remote";// 引入代码高亮cssimport "prismjs/themes/prism-okaidia.min.css";interface Props { postData: { title: string; date: string; content: MDXRemoteProps; };}export default function Post({ postData }: Props) { return ( <Layout> <Head> <title>{postData.title}</title> </Head> <h1 className='text-3xl font-extrabold my-4 tracking-tighter'> {postData.title} </h1> <Date dateString={postData.date} /> <article className='py-8 prose prose-h1:mt-8'> <MDXRemote {...postData.content} /> </article> </Layout> );}// getStaticProps和getStaticPaths只在服务器端运行,永远不会在客户端运行export const getStaticPaths: GetStaticPaths = async () => { // 获取所有文章id,即所有路由 const paths = getAllPostIds(); return { paths, fallback: false, };};export const getStaticProps: GetStaticProps = async ({ params }) => {// 获取文章内容 const postData = await getPostData(params!.id as string); return { props: { postData, }, };};

之后在首页点击文章列表跳转到文章详情页面: 到此一个简单的博客项目就写好了

8、Vercel部署

没有Github账号的先去注册一个账号

在Github上新建一个名为next-blog的仓库(名称自己根据需要修改):

仓库权限公共私有都可,并且不需要使用README 或其他文件对其进行初始化

在我们的博客项目根目录下运行以下命令推送代码到Github仓库里:

git remote add origin https://github.com/<username>/next-blog.gitgit branch -M maingit push -u origin main

请将上述第一行命令origin后面的地址替换成你的仓库地址,一般是将<username>替换为你Gitub的用户名,next-blog替换成你仓库的名称

之后刷新仓库查看代码:

项目仓库地址:https://github.com/Chen0807AiLJX/next-blog

细心的大佬应该会发现我们这样提交代码是有问题的,因为我们并没有合并本地代码到本地仓库,所以提交到Github仓库的代码并不是我们最终的效果,而是创建Next.js时的初始效果。

不过不用担心,我们在后面会对其进行处理。当然,你也可以现在处理,直接将最新的代码同步到仓库,这样你就免了后面我们对其处理的操作

打开Vercel,没有Vercel账号的点击右上角的注册按钮进行注册,注册时选择通过Github注册,登录时也使用Github登录

登录Vecel成功后打开 https://vercel.com/import/git或https://vercel.com/new或点击新建项目按钮,之后进入到以下页面:

这个页面中会自动获取你的Github仓库,选择你刚刚推送博客项目的仓库,点击Import按钮,之后直接点击Deploy按钮:

稍等片刻,出现以下页面就部署成功了:

点击上述页面左侧的页面预览框就能跳转到你部署成功的网页了,但这时你会发现部署的页面不是我们最终的页面,而是创建Next.js时的初始页面,这是因为我们在Git提交代码到仓库时没有合并本地代码,我们重新提交一下就行了

我们可以在VScode里快速提交代码到仓库:

点击同步更改后会开始转圈,等待转圈结束就提交成功了,之后什么都不用干,仓库代码更新后Vercel会自动部署!!!

打开https://vercel.com/dashboard能查看到你已经部署的项目和对应的网页地址:

好啦,到此我们的任务就全部完成了,之后需要添加文章只需要在项目的posts文件内新建markdown文件就行了(不要忘记在markdown顶部添加元数据),更新完文章提交代码到仓库即可

结语

这次使用Next.js搭建个人博客只是一个小小的尝试,可以说是只搭建了一个骨架,其实走完整个流程你应该会有很多有趣的想法去完善填充你的博客,因为基础功能我们已经实现,剩下的就是锦上添花的操作了,这完全取决于你

项目仓库地址:https://github.com/Chen0807AiLJX/next-blog 最终效果可见:https://next-blog-eosin-six.vercel.app/

参考资料:

Next.js官网tailwindcss中文文档date-fns文档next-mdx-remote仓库remark文档

如果本篇文章对你有所帮助,还请客官一件四连!❤️

本文链接地址:https://www.jiuchutong.com/zhishi/299611.html 转载请保留说明!

上一篇:css元素定位:通过元素的标签或者元素的id、class属性定位(css定位属性的运用)

下一篇:做毕业设计,前端部分你需要掌握的6个核心技能(做毕业设计,前景如何)

  • 徕卡r502评价(徕卡r50)(徕卡r50f2)

    徕卡r502评价(徕卡r50)(徕卡r50f2)

  • 天猫半日达是快递还是外卖(天猫半日达是快递送吗)

    天猫半日达是快递还是外卖(天猫半日达是快递送吗)

  • 红米10xpro有红外线功能吗(红米10x有红外线)

    红米10xpro有红外线功能吗(红米10x有红外线)

  • 为什么看不了对方的朋友圈(为什么看不了对方抖音点赞数)

    为什么看不了对方的朋友圈(为什么看不了对方抖音点赞数)

  • 笔记本电脑顿号键在哪(笔记本电脑顿号是哪个键)

    笔记本电脑顿号键在哪(笔记本电脑顿号是哪个键)

  • qq音乐怎么下载(qq音乐怎么下载免费歌曲)

    qq音乐怎么下载(qq音乐怎么下载免费歌曲)

  • 闲鱼直播有什么要求吗(闲鱼直播有什么要求吗?)

    闲鱼直播有什么要求吗(闲鱼直播有什么要求吗?)

  • 苹果笔记本内存不够用可以扩展吗(苹果笔记本内存和普通笔记本一样吗)

    苹果笔记本内存不够用可以扩展吗(苹果笔记本内存和普通笔记本一样吗)

  • 苹果锁屏界面的手电筒和相机怎么用(苹果锁屏界面的通知)

    苹果锁屏界面的手电筒和相机怎么用(苹果锁屏界面的通知)

  • 台式电脑为什么关不了机(台式电脑为什么连不上wifi)

    台式电脑为什么关不了机(台式电脑为什么连不上wifi)

  • 快手显示该身份证已被其他账号使用怎么办(快手显示该身份证绑定账号已达上限)

    快手显示该身份证已被其他账号使用怎么办(快手显示该身份证绑定账号已达上限)

  • 小米cc9怎么分屏(小米cc9怎么分屏使用方法)

    小米cc9怎么分屏(小米cc9怎么分屏使用方法)

  • ps形状图层按钮在哪里(photoshop形状图层)

    ps形状图层按钮在哪里(photoshop形状图层)

  • 微信邀请链接什么时候过期(微信8.0邀请链接)

    微信邀请链接什么时候过期(微信8.0邀请链接)

  • 双v会员要钱吗(双v会员月费多少)

    双v会员要钱吗(双v会员月费多少)

  • p20超级快充没了(华为p20充电没有超级快充了怎么回事)

    p20超级快充没了(华为p20充电没有超级快充了怎么回事)

  • 手机双频wifi什么意思(手机双频双模块wifi)

    手机双频wifi什么意思(手机双频双模块wifi)

  • 华为p30pro50倍变焦怎么用(华为p30pro50倍变焦是多少米)

    华为p30pro50倍变焦怎么用(华为p30pro50倍变焦是多少米)

  • ps4可以连wifi吗(ps4能连wifi吗?)

    ps4可以连wifi吗(ps4能连wifi吗?)

  • pcie是显卡接口吗(pcie显卡接口信号)

    pcie是显卡接口吗(pcie显卡接口信号)

  • word一二三级标题设置(word一二三级标题字体格式)

    word一二三级标题设置(word一二三级标题字体格式)

  • excel怎么看打印预览(excel怎么看打印页数)

    excel怎么看打印预览(excel怎么看打印页数)

  • 华为p30电池多大(华为p30pro换电池价格)

    华为p30电池多大(华为p30pro换电池价格)

  • 分隔符和分节符的区别(分隔符分节符分页符的差别)

    分隔符和分节符的区别(分隔符分节符分页符的差别)

  • QQ能上,网页打不开(qq能上,网页打不开怎么回事)

    QQ能上,网页打不开(qq能上,网页打不开怎么回事)

  • chrome插件开发时跨域问题解决方案(chrome插件开发语言)

    chrome插件开发时跨域问题解决方案(chrome插件开发语言)

  • Vue3路由守卫(vue3路由守卫 微信授权登陆)

    Vue3路由守卫(vue3路由守卫 微信授权登陆)

  • 增值税纳税申报时间
  • 电子税务局能不能申报个税
  • 进项税额转出会影响利润吗
  • 企业纳税信用等级评定标准
  • 增值税专票和普票的区别税率
  • 出货一般要多久
  • 一般纳税人10万以下免什么税
  • 企业没有进项发票又开出很多发票
  • 建筑企业小型企业有哪些
  • 建筑企业外地施工成立分公司吗
  • 发票到了款未付账务处理
  • 产品缺陷处理流程
  • 公司买车赠与员工
  • 摊销费用怎么计提
  • 房地产开发企业预缴增值税
  • 利息收入汇算清缴
  • 代扣代缴个人所得税会计分录怎么做
  • 公司户进账一定要扣税吗
  • 代理手续费税收分类编码
  • 金税四期再出新公告
  • 坏账核销谁来审批
  • 本期增加固定资产原值
  • 将自产产品无偿赠送 会计处理
  • 个人交社保可以交生育险吗
  • 车位销售代理合同
  • 销售回购会计分录
  • 电子商业汇票背书是什么意思
  • 农村合作社收到财政拨款怎么做分录
  • 工程建设期间的借款利息
  • 企业给予的折扣怎么入账
  • 个体工商户与其经营者构成共同侵权吗
  • 银行手续费发票税率
  • php常用函数大全
  • 员工安置费标准出台
  • 往来款怎么查
  • 优先股转化
  • php如何实现伪静态
  • 单位购买降暑用品
  • 银行日记账本月没有发生业务
  • 商业一般纳税人增值税税负率最低多少
  • 如何配置apache
  • 第三方代付如何开票
  • vue中过滤器有什么作用及详解
  • php用在哪些方面
  • 期末余额跟年初余额是什么意思
  • node.js环境搭建
  • php提供的字符串函数
  • 发票认证相符什么意思
  • 退质保金计入什么科目
  • 生产企业出口转内销增值税申报表怎么填
  • 出版社出版带有编码吗
  • 企业所得税包含员工工资吗
  • 合伙企业所得税征收方式
  • 房屋租赁需要计提印花税吗
  • 需要做审计有哪些行业
  • 实收资本库存现金凭证怎么开
  • 金税盘分盘可以全额抵扣吗
  • 小规模纳税人销售不动产适用税率
  • 餐饮行业购入农产品
  • 飞机票退票费如何开票
  • 企业控股情况怎么看
  • 餐饮行业月末结转成本怎么算
  • 拿到营业执照后需要做的事
  • 固定成本包括哪些项目
  • mac系统如何隐藏文件
  • win7系统莫名其妙占用个D盘
  • win10英文版系统怎么完全改为中文
  • Unity3D游戏开发基础
  • jQuery插件能输出到控制台
  • javascript definitive guide
  • sed基本用法
  • js判断页面是否跳出弹窗
  • angular const
  • javascript快速入门
  • unity角色扮演游戏
  • 电子税务局怎么删除办税员
  • 补缴印花税分录
  • 一季度土地市场
  • 预缴增值税申报表申报期限
  • 南通工伤网上申请流程
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设