作成日:2023-12-06
Gatsby5.0が出た時に周りのプラグインの挙動がおかしかったので勉強を兼ねてNextjsに移行してみたらNextjsの方が利便性を感じた。
Gatsbyのver 5が出て、バージョンを上げたら、node,reactのバージョンアップが必要になり、それに伴い、警告メッセージがたくさん出てきて気持ち悪く、また、必要なnodeのバージョンが高かったので、ビルドできない環境であったため、前々から気になってたNextjsに触れることを決めました。
今までNextjsを触らなかったのは、サーバー側も触れる、SSR,SSGとか、とにかく色々できる。つまり機能が多いので、学習コストが高そう、プラグインとかも無いので、全部自前で用意する必要があると思っていたからです。
GatsbyからNextjsに移行する時、今までmdxで記事を書いていたので、これを解決しなければならない、またSEO関連もPluginで終わらせていたので、この辺もどうにかしないといけない、デフォでssrって、別にSSGでいいんだけど、他に画像の最適化もしないといけないのでとにかく時間がかかってしまった。
mdx関係は、Nextjsのmd関係を検索するとまぁまぁ、ライブラリーが出てくるのだが、新規では無く、今までGatsbyで使用した物の移行となるので、既存のライブラリーを使用すると、Gatsbyでカスタマイズしていた書き方が出来なく、解決方法も無かった、エラーばっかりでライブラリーを使うことを諦めました。
そして、最終的には、rehype-○○と,remark-○○のライブラリーを使用し、カスタマイズができるようにしました。
これがかなり大変で、pタグの中にdivが入ってしまっている現象が発生し、正常には画面が表示されるが、エラーメッセージがかなり表示されたり、目次を作ったり、タグ、フィルター機能、とにかくmdx関係で苦戦しました。
const result = unified()
.use(remarkParse)
.use(removeCustomElementParagraph)
.use(remarkGfm)//他の打消~~とかも使えるようになる
.use(plugin)
.use(remarkRehype, {
allowDangerousHtml: true, // trueにしておくことで、自分でカスタマイスしたタグをそのまま吐き出してくれるようになります。
handlers: {
message: handler,
}
})
.use(rehypeSlug)//headerにidを付けれる
.use(rehypeCodeTitles, { customClassName: "code-title" })
.use(rehypePrism, { plugins: ['line-numbers', 'copy-to-clipboard'] })
.use(collectIds)// p in divで構造エラーが出るのでこの関係を外す
.use(rehypeStringify, {
allowDangerousHtml: true
})//mdから最後に変換する必要がある
.processSync(md);
return { result: result, headers: ids }
上記のような感じで,mdxファイルのパース処理をしています。(一部自作)
A to Bみたいに簡単に変換してくれるのだろうと思っていたが、間に色々処理をしないといけない事を始めて知った。特にremarkGfmは必ず入れておかなければ...
このmdxは今でもよくわかっていない、自作ファンクションを作る時に理解?したメモがある参考までに
markdownの変更にはmd -> mdast -> hast -> html
remarkParse md -> mdast
remark-rehype mdast -> hast
rehypeParse html -> hast
rehypeReact hast -> react
stringify hast -> html
remarkRehype mdast -> hast?
rehypeStringify hast -> html
タグで日付ソート、フィルタリングするために。
当初フィルタリングするために、ssrなので、タグをサーバーに一度投げて、その後、mdファイルの全て読み込みタグをさらに読み込みソートして、フィルタリングをして、クライアント側に返す処理になっていましたが、毎回、全てmdファイルを読み込み、タグを取集して日付でソートし、フィルタリングするというかなり無駄な処理をしていました。(だって検索してもそんなサンプルしかなかったし、) nextjsでssr何だからそれが正解なのかなぁと思っていましたが、納得ができず、ビルド前にmdファイルを全て読み込み、タグのjsonファイルと、記事用のmdファイル日付ソートしてjsonファイルを保存する方法を取りました。ついでにサイトマップも作成しちゃう。
const fs = require('fs');
const matter = require('gray-matter')
const Writefile = async () => {
const postf = fs.readdirSync("./blogposts").filter((postPath) => /\.md?$/.test(postPath));;
fs.writeFile('postlist.txt', JSON.stringify(postf), function (err) {
if (err) throw err;
console.log('JSONファイルが作成されました!');
});
let xml = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://yumeno.me</loc><changefreq>daily</changefreq><priority>0.7</priority></url>`;
const posts = postf.map((slug) => {
const content = fs.readFileSync("./blogposts/" + `${slug}`);
const { data } = matter(content);
let tmp = slug.replace(/\.md?$/, '')
xml +=`<url><loc>https://yumeno.me/${tmp}</loc><changefreq>daily</changefreq><priority>0.7</priority></url>`
return {data};
});
xml +=`</urlset>`
fs.writeFile('./public/sitemap/sitemap-0.xml' ,xml , ((err)=>{
if(err) throw err;
console.log('created-sitemap');
}))
const allTags = posts.reduce((a, post) => {
post.data.tag?.map((tag) => a.add(tag));
return a;
}, new Set([]));
//sort tags
const allTagssorted = [...allTags].sort((a, b) => a.localeCompare(b));
allTagssorted.unshift('all');
fs.writeFile('tags.txt', JSON.stringify(allTagssorted), function (err) {
if (err) throw err;
console.log('JSONファイルが作成されました!');
});
}
Writefile();
カオス状態ですね...
import * as fs from 'fs'
import * as path from 'path'
import matter from 'gray-matter';
import { unified } from 'unified';
import rehypeReact from 'rehype-react'
import MDXComponents from '../component/MDXComponets'
import React from 'react';
import rehypeParse from 'rehype-parse';
import { MarkdownToHtml } from '../lib/transpiler';
import { postFileNames , MdxPath} from '../component/utils/mdx-file-loader';
const processor = unified()
.use(rehypeParse, { fragment: true, })
.use(rehypeReact, { createElement: React.createElement, components:MDXComponents})
import BlogpostTemplate from '../component/Blogtemplate1';
export default function Page({ ...props }) {
return (
<BlogpostTemplate frontmatter ={props.frontmatter} headers = {props.headers} slug={props.slug} relative={props.relativepost} >
{processor.processSync(props.html).result}
</BlogpostTemplate>
)
}
export const getStaticProps = async (context) =>{
const slug = context.params.slug;
const filePath = path.join(process.cwd(), 'blogposts', `${slug}.md`);
const fileContent = fs.readFileSync(filePath, 'utf-8');
const { data, content } = matter(fileContent);
const posts = JSON.parse(postFileNames).map((slug) => {
const contentmdx = fs.readFileSync(path.join(MdxPath, `${slug}`));
const { data } = matter(contentmdx);
return {
frontmatter: data,
slug: slug.replace(/\.md?$/, ''),
};
}).filter(post=> data.tag.some(tag => post.frontmatter.tag.includes(tag)))
.sort((a,b)=>{a.frontmatter.date < b.frontmatter.date ? 1 :-1;});
let newArray = []
while (newArray.length < 6 && posts.length > 0) {
const rand = Math.floor(Math.random() * posts.length)
newArray.push(posts[rand])
posts.splice(rand, 1)
}
const datas = await MarkdownToHtml(content);
const htmldata = datas.result.toString();
const headersid = datas.headers;
return {
props: { html: htmldata , frontmatter : data , headers : headersid , slug : slug , relativepost: newArray }
}
}
export async function getStaticPaths() {
const postsPaths = JSON.parse(postFileNames).map((slug) => ({
params: {
slug: slug.replace(/\.md?$/, '')
},
}));
return {
paths: postsPaths,
fallback: false,
};
}
mdxブログのテンプレートでは、getStaticPathsでmdファイルのページを作成しています。
記事の中身はgetStaticPropsを使って、mdファイルを読み込み、ついでに関連する記事を6を渡し、自作ファンクションMarkdownToHtmlでmdからhtmlにしています。
せっかくhtmlにしたのにさらに{processor.processSync(props.html).result}
でhastに変換しています。
html->hastは無駄なのでは?と思っていますが、解決出来なかった。なんかPrismが、ページリロードした時に反映されないので諦めました。
GatsbyとNextjsを使ってみて
短時間でお金かけずにするのであればGatsbyが良い。Nextjsはnodejsが入っているサーバーが必要になるがGatsbyはnodeサーバーが不要。静的ビルドすれば良いとかは言わないで Pluginも充実しているので簡単にGatasbyでサイト構築ができる。難点なのは、バージョンが上がった場合プラグインとかが使えなくなる可能性が大いにある。buildの時間がかかるのは事実だが、ローカルのPCでビルドしてアップロードすることはまず無く,サーバー上で勝手にビルドが実行されるので、実質待たされる時間はほとんどない。一番問題となるのはフォルダー構成が分かりにくいのと、GraphQLを覚え無いといけない部分。
汎用性を重視するのであればNextjsがいいと思う。サーバーサイドで処理する事が頻繁に発生する。Gatsbyもできるとか言わないで そして、Nextjs14から、フォルダー構成が分かりやすくなっている。next/imageだけはちょっとどうにかしてほしいが、cloudinaryを使うことにしてからあまり気にしなくなった。
ブログするならwordpressを使った方がいいし、高速な静的サイトを作るなら、Gatsbyが良いと良いと思う。
なんでもする必要があるならNextjsを使う方がいいと思う。結局は適材適所であるが、迷ったらとりあえずNextjsを使えば、だいたいどんな状況になっても対処できるのでNextjsを使うことをおすすめする。
質問や、間違いがありましたら、お気軽にどうぞ
※お名前とコメントの内容を入力してください。
※全てこのブログ上に公表されます。
※許可なく管理者によって修正・削除する場合がございます。 詳しくはプライバシーポリシーを参照ください