范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

使用Next。js创建Blog

  Next.js 已经成为 React 应用程序最重要的框架之一。它可以帮助开发人员在没有模板的情况下构建更好的服务器端渲染 React 应用程序。
  Next.js 之所以能成为目前最好的 React 框架之一,与其很多特性离不开,比如打包构建、路由预取、TypeScript、SEO 等。
  对于那些想要拥有一个简单但功能强大的博客的人来说,使用 Next.js 创建博客是当今的最佳选择。
  SEO(搜索引擎优化)是改进应用程序在搜索引擎排名的过程。对于任何想要在搜索引擎上获得更好排名并带来更多流量的博客来说,这都是非常重要的。
  我们将在本文中使用 Next.js 来构建博客。我们将介绍 SSG(静态站点生成)的工作原理,并完成 SEO 友好的博客。 入门
  使用官方推荐的Create Next App创建项目 npx create-next-app@latest --typescript # or yarn create next-app --typescript # or pnpm create next-app --typescript 复制代码
  为什么要使用Create Next App 交互式体验:不带任何参数运行npx create-next-app@latest,将会开启交互模式,引导创建项目 零依赖:Create Next App没有依赖,毫秒级创建项目 离线支持:Create Next App侦测网络状态,无网状态将使用本地依赖缓存 支持模板:通过加入--example参数,可以拉取官方仓库任何模板 集成测试:集成测试功能
  创建完成后项目目录构造如下: .   README.md   next-env.d.ts   next.config.js   node_modules   package.json   pages   pnpm-lock.yaml   public   styles   tsconfig.json 复制代码安装依赖pnpm install globby gray-matter dayjs @chakra-ui/react prismjs @emotion/react @emotion/styled framer-motion next-mdx-remote remark-gfm 复制代码创建文章
  根目录新增_posts目录,在_posts目录下创建两个mdx文件(_posts/js/helloWorld.mdx,_posts/demo.mdx),为什么是mdx文件呢?mdx支持渲染组件,支持引入导出组件,详细文档参考MDX 创建公共函数目录
  根目录新增utils目录,在utils目录下创建getAllPosts.js并写入如下函数 import fs from "fs" import {globby} from "globby" import matter from "gray-matter" const dayjs = require("dayjs") const relativeTime = require("dayjs/plugin/relativeTime")  dayjs.extend(relativeTime)  //获取所有文章 const GetAllPosts = async () => {   const posts = await globby(["_posts"])   return posts     .reduce((prev, next) => {       const fileContents = fs.readFileSync(next, "utf8")       const {data, content} = matter(fileContents)       const postData = {         ...data,         group: dayjs(data.date).format("MMM/YYYY"),         date: dayjs(data.date).format("MMM DD, YYYY"),         fromNow: dayjs(data.date).fromNow(),         modified: dayjs(data.modified).format("MMM DD, YYYY"),         content,         slug: next.replace(/^_posts//, "").replace(/.mdx$/, "")       }       !data.draft && prev.push(postData)       return prev     }, [])     .sort((a, b) => dayjs(b.date) - dayjs(a.date)) }  // 根据slug导出文章 const GetPostBySlug = (slug) => {   // eslint-disable-next-line no-undef   return new Promise((resolve, reject) => {     GetAllPosts()       .then((posts) => {         const post = posts.find((post) =>           post.slug.includes(`${slug.join("/")}`)         )         resolve(post)       })       .catch(() => {         reject({})       })   }) }  export {GetAllPosts, GetPostBySlug} 复制代码创建组件
  根目录新增components目录 创建PostPage.tsx组件,内容如下: import React, {useEffect} from "react" import Prism from "prismjs" import {Box} from "@chakra-ui/react"  // 以下按需引入 require("prismjs/components/prism-go") require("prismjs/components/prism-python") require("prismjs/components/prism-javascript") require("prismjs/components/prism-css") require("prismjs/components/prism-bash") require("prismjs/components/prism-swift") require("prismjs/components/prism-tsx") require("prismjs/components/prism-jsx") require("prismjs/components/prism-typescript") require("prismjs/components/prism-sql") require("prismjs/themes/prism-okaidia.min.css")  const PostPage = ({children}) => {   useEffect(() => {     const highlight = async () => {       await Prism.highlightAll()     }     highlight().then(() => {})   }, [children])   return (            {children}        ) } export default PostPage 复制代码创建pages/index.tsx import NextLink from "next/link" import {Fragment} from "react" import {   List,   LinkOverlay,   ListItem,   Container,   Heading,   Image } from "@chakra-ui/react"  const IndexPage = ({groupByMonthPosts}) => {   return (            {Object.keys(groupByMonthPosts).map((group) => {         return (                                       {group}                                         {groupByMonthPosts[group].map((post) => {                 return (                                                               {post.title}                                          {post.tags.map((tag) => {                       return (                         {tag}                       )                     })}                                    )               })}                                 )       })}        ) }  export default IndexPage  export async function getStaticProps() {   const {GetAllPosts} = await import("utils/getAllPosts")   const posts = await GetAllPosts()   const groupByMonthPosts = posts.reduce((prev, next) => {     if (Array.isArray(prev[next.group])) {       prev[next.group].push(next)     } else {       prev[next.group] = []       prev[next.group].push(next)     }     return prev   }, {})   return {     props: {       groupByMonthPosts     }   } } 复制代码创建pages/[...slug].tsx import {MDXRemote} from "next-mdx-remote" import {serialize} from "next-mdx-remote/serialize" import dynamic from "next/dynamic" import ErrorPage from "next/error" import NextLink from "next/link" import {useRouter} from "next/router" import React from "react" import remarkGfm from "remark-gfm" import components from "utils/components" import {   Container,   Box,   Heading,   Text,   Link,   Image,   Center } from "@chakra-ui/react"  const PostPage = dynamic(() => import("components/PostPage"))  const Post = ({title, description, date, originalUrl, mdxSource, cover}) => {   const router = useRouter()   if (!router.isFallback && !mdxSource) {     return    }   return (                                       Published {date}                             {title}                  {originalUrl && (           
本文翻译自: {originalUrl}
)}
{title}
) } export const getStaticPaths = async () => { const {GetAllPosts} = await import("utils/getAllPosts") const allPosts = await GetAllPosts() const paths = allPosts.map((post) => ({ params: { slug: post.slug.split("/") } })) return { paths, fallback: false } } export const getStaticProps = async ({params}) => { const {GetPostBySlug} = await import("utils/getAllPosts") const {content, ...data} = await GetPostBySlug(params.slug) const mdxSource = await serialize(content, { mdxOptions: { remarkPlugins: [[remarkGfm]], rehypePlugins: [] }, scope: data }) return { props: { ...data, mdxSource } } } export default Post 复制代码   至此,基本框架搭建完成,接下来调整样式及组件的引入,以及 mdx 渲染修正。 调整样式   可选   引入tailwind.css,执行pnpm install -D tailwindcss postcss autoprefixer && npx tailwindcss init -p   修改tailwind.config.js,如下: /** @type {import("tailwindcss").Config} */ module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}" ], theme: { extend: {} }, plugins: [] } 复制代码   修改全局样式styles/globals.scss @tailwind base; @tailwind components; @tailwind utilities; 复制代码   必须   修改pages/_app.tsx,引入chakra-ui的配置 // pages/_app.js import {ChakraProvider} from "@chakra-ui/react" function MyApp({Component, pageProps}) { return ( ) } export default MyApp 复制代码   到这里,不出意外,你的界面应该是长这样   点击链接,应该会报错,未引入utils/components,这个是配置 mdx 内元素渲染的组件,参考MDX Components,mdx 提供默认的渲染组件,所以,这个是非必须的,不需要删除即可   个人比较喜欢 chakra-ui,所以将组件都转成了 chakra-ui 提供的组件,配置如下: import CanIUse from "components/CanIUse" import {Heading, Link, Box} from "@chakra-ui/react" import {FiExternalLink} from "react-icons/fi" const components = { CanIUse, h2: (props) => ( {props.children} ), h3: (props) => ( {props.children} ), h4: (props) => ( {props.children} ), h5: (props) => ( {props.children} ), p: (props) => ( {props.children} ), p: (props) => {props.children}, a: (props) => { return ( {props.children} ) } } export default components 复制代码   好了,到这里基本完成了基于Next.js的博客搭建。 部署到Vercel   Next.js部署到Vercel无需更改和配置,无缝衔接。   【Source Code】   也可以参考我的个人网站Manon.icu | Home

詹姆斯被担架抬走,孙铭徽5失误6犯规,林庭谦30分逆袭CBA常规赛天津队主场对阵浙江东阳光,天津队本赛季6胜22负的战绩排名倒数第二,东阳光队战绩更好,取得14胜14负的战绩。广厦队的胡金秋和朱俊龙都在本次国家队有所表现。首节,王一方橙汁版锅包鱼,简直太下饭了,怎么吃都不够锅包肉是一道老少皆宜的菜,其实它的做法可以很灵活,把猪肉换成鱼肉也是非常不错的选择,至于调汁也有很多种方法,今天介绍的是用橙汁做的,没有可以换成番茄汁,或者蓝莓汁黄桃汁,都非常好吃66元的白酒宣称堪比茅台158元的手表号称让利11万元忽悠式直播带货何时休原标题66元的白酒宣称堪比茅台158元的手表号称让利11万元忽悠式直播带货何时休本报记者韩丹东本报实习生关楚瑜近日,博主称嘎子哥卖的手机最多值999元话题冲上热搜榜。起因是主播谢孟探究文化挪用的定义是什么文日斤编辑日斤引言为什么担心它很重要?BelJacobs探讨了行之有效的文化合作,以及为什么平等交换精神在时尚中至关重要。2019年,一家意大利大型时装公司推出了一系列棉质府绸超长里弗斯我们只是在打球,在竞争!乡村曼巴必须给力湖人客场27分逆转独行侠,里弗斯本场砍下9分3篮板3助攻。末节,小里和格林发生口角里弗斯Youaintsht。Illfckyouup你什么都不是。我会打爆你赛后里弗斯接受采访时提到特级大师吕钦巧手妙着第1局吕钦(红先胜)胡荣华所见所得,都很科学第9届五羊杯决赛,由吕钦和胡荣华争夺冠军,首局胡荣华在胜势下错失战机,被吕钦逼和。本局是第二局,胡荣华情绪受到影响,而吕钦则士气大振,开局一路顺风。正当双方中局成女星瑜伽健身,谁最美身材最好最性感?随着时代的发展,现在越来越多的人开始习惯穿瑜伽裤,不仅仅它因为舒适性高,还有一个最重要的原因是它能把自己的好身材展现出来。现在明星也开始穿瑜伽裤练瑜伽来健身保持身材这已经司空见惯了社内相亲车室长爆红!金旻奎性感蜜嗓阳光酒窝狙击你的心社内相亲车室长金旻奎最近带来新作神圣的偶像,搞笑逗趣的演出让人又重新爱上他了!首次挑大梁演出男主角的金旻奎,即将高唱从军乐,今天就让我们藉由6大秘密来重新认识这位宝藏男孩吧!名字的宁予洋人不给家奴,恒大两重天政策让韦士豪转会失败网上有消息说,韦士豪转会基本告吹,传说最为接近转入韦世豪的山东泰山队已经停止谈判。原因是恒大要价太高,狮子大张口又盯住了泰山这一块肥肉。上赛季,恒大超低薪,让一些球员不得不另找出路73保超瓦尔纳黑海vs贝迪夫主力含泪离队,人心散了队伍还好带吗?3月4日周六晚上2300昨天,2月28日,保加利亚冬季转会窗关闭前。贝迪夫的队长内德列夫以15万欧元的价格,转会去了卢多戈雷茨。现年30岁的内德列夫司职中场,是保加利亚国脚。他出自欧美著名九零后超级性感女星,有啤酒妹之称麦迪逊比尔麦迪逊比尔美国90后超级性感女歌手明星麦迪逊比尔(MadisonElleBeer),1999年3月5日生于美国纽约耶利哥,美国歌手。从小就很有音乐天赋,4岁开始唱歌,12岁开始学钢
2022年体育传统项目学校田径联赛(南部赛区)延期举行中新网9月13日电据中国田径协会官网消息,13日,中国田径协会发布关于延期举办2022年体育传统项目学校田径联赛(南部赛区)的通知(以下简称通知)指出,2022年体育传统项目学校田国际羽联男单排名更新!赵俊鹏反超谌龙成国羽一哥!昆拉武特第102022赛季的羽毛球职业联赛展开激烈角逐,在北京时间2022年10月丹麦公开赛一触即发,目前国羽众多球员正在积极备战这项赛事的比拼,目前国际羽联的积分正在解冻,在2022年第37周苏伟从国家队队员到国家队教练经历四个城市,奔波30余个小时,国家集训队终于抵达外训地,带队教练苏伟直言松了一口气。肯尼亚,埃尔多雷特。这个小镇苏伟来过,不过那已经是十五年前。看着眼前的小镇,他心生感慨。这个熟小因扎吉同比尔森胜利一战已决定好首发门将,现在不想说本周,国际米兰即将在欧冠赛场上迎来同比尔森胜利的比赛。赛前,国际米兰主帅小因扎吉参加了新闻发布会,小因扎吉在新闻发布会上表示至于首发门将的人选,已经决定了,但我现在不想说,球员们还国米丨张康阳掌舵的国际米兰,让苏宁走向世界又默默地走了回来国际米兰近年因苏宁的经济问题一直饱受质疑,更是在近期出现了国米主席张康阳要变卖股权的消息,如今国米是意甲乃至意大利都比较关注的热点话题,据了解,张康阳已经委托高盛集团为其寻找合作伙狼记联盟正对爱德华兹行为进行审查以判断是否对其施以处罚直播吧9月13日讯据森林狼随队记者ChrisHine报道,消息人士透露,联盟方面正对爱德华兹此前在社交媒体上发布的恐同言论进行审查,以判断是否会对其施以处罚。在此前联盟有过多次这样国羽世界排名出炉!球迷大失所望,为何沦落这般局面?谁来负责?北京时间9月13日,世界羽联公布了各单项第37周最新排名情况。中国队最大优势项目混双遗憾丢掉头名宝座,仅女双陈清晨和贾一凡组合拿到世界第一,这也是国羽唯一一个排名榜首的项目。男单方安吉谈为何决心重建球员彼此间缺乏信任北京时间9月13日,据盐湖城论坛报报道,在今天早些时候,犹他爵士CEO丹尼安吉和总经理贾斯丁扎尼克召开了新闻发布会,讨论了球队在今年夏天的主要运作,以及为何要针对球队进行重建。上赛WTA世界排名更新张帅时隔两年半重返单打TOP30中新网9月13日电据WTA国际女子网球协会官方微博消息,日前,最新一期WTA世界排名出炉。凭借首次闯入美网16强的成绩,中国选手张帅时隔两年半重返单打TOP30。此外,在美网赛场有拆队摆烂重建挨个来?爵士队一个休赛期就完成啦战绩不佳,拆队摆烂重建几乎成了巨星抱团之外,另外一条NBA球队惯用的重回巅峰的道路。犹他爵士队在又一次倒在季后赛首轮之后,就毅然开启了拆队之旅,截止目前,已经只剩康利博扬博格达洛维韩聪当选国际滑联单双人滑技术委员会运动员委员来源中国新闻网中新网9月12日电据中国花样滑冰协会消息,国际滑冰联盟(ISU)于北京时间12日正式任命北京冬奥会花样滑冰双人滑冠军中国花样滑冰运动员韩聪为单双人滑技术委员会运动员委