リンクだけあっても味気ないので、埋め込み対応をしてみました。
- remark, remark-rehype, rehype-stringify がインストール済みであること
npm i --save-dev remark remark-rehype rehype-stringify
@remark-embedder/transformer-oembedを使って変換します。
@remark-embedder/transformer-oembed
をインストールします。
npm i --save-dev @remark-embedder/transformer-oembed
コンポーネント markdownToHtml.js が以下のようなものだとします:
```ts:markdownToHtml.js
import { remark } from "remark";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import rehypeExternalLinks from "rehype-external-links";
import remarkEmbedder from "@remark-embedder/core";
import type { Config } from "@remark-embedder/transformer-oembed";
import oembedTransformer from "@remark-embedder/transformer-oembed";
export const markdownToHtml = async (markdown: string) => {
const result = await remark()
.use(remarkEmbedder, {
transformers: [
[
oembedTransformer,
{
params: {
maxwidth: 550,
omit_script: true,
lang: "ja",
dnt: true,
},
} as Config,
],
],
})
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeStringify)
.process(markdown);
return result.toString();
};
markdownToHtml.js を使ってページを表示します。
```ts:index.tsx
import { InferGetStaticPropsType, NextPage } from "next";
import { markdownToHtml } from "../../lib/markdownToHtml";
type Props = InferGetStaticPropsType<typeof getStaticProps>;
const Home: NextPage<Props> = ({ html }) => {
return (
<div
dangerouslySetInnerHTML={{
__html: html,
}}
></div>
);
};
export const getStaticProps = async () => {
return {
props: {
html: await markdownToHtml("https://www.youtube.com/watch?v=dQw4w9WgXcQ"),
},
};
};
export default Home;
<iframe
width="356"
height="200"
src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
title="Rick Astley - Never Gonna Give You Up (Official Music Video)"
></iframe>
<blockquote
class="twitter-tweet"
data-width="550"
data-lang="ja"
data-dnt="true"
>
<p lang="en" dir="ltr">
Creators can now sign up and earn a living directly on Twitter in the EU,
UK, and EEA.<br /><br />Tap on “Monetization” in settings to apply today.<br /><br />For
a full list of available countries see our Help Center:
<a href="https://t.co/YbBw0EVKqJ">https://t.co/YbBw0EVKqJ</a>
</p>
— Twitter (@Twitter)
<a
href="https://twitter.com/Twitter/status/1649507477325488131?ref_src=twsrc%5Etfw"
>2023年4月21日</a
>
</blockquote>
ツイートを以下のような埋め込みにする場合は、widgets.js を使って<iframe>
に変換します。
https://twitter.com/Twitter/status/1649507477325488131
```ts:index.tsx
import { useEffect } from "react";
import { InferGetStaticPropsType, NextPage } from "next";
import { markdownToHtml } from "../../lib/markdownToHtml";
type Props = InferGetStaticPropsType;
const Home: NextPage = ({ html }) => {
useTweetEmbed();
return (
);
};
export const getStaticProps = async () => {
return {
props: {
html: await markdownToHtml(
"https://twitter.com/Twitter/status/1649507477325488131"
),
},
};
};
export const useTweetEmbed = () => {
useEffect(() => {
const script = document.createElement("script");
script.src = "https://platform.twitter.com/widgets.js";
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
};
export default Home;
```