Back to home

YouTubeのURLを貼ったらiframeに展開するようにした

2 min read
Table of Contents

このブログに YouTube の URL を埋め込めるようにしました。

以下のように記事を書くと、勝手に iframe タグで囲って色々してくれるようにしました。

一例

例えば以下のような記事を書くと

個人的におすすめなのは、知床の動画です。ぜひ見てください。

https://www.youtube.com/watch?v=apf90zxAkso <!-- これ -->

こんな感じになります。

こんな感じになる

無駄にレスポンシブにしたり、遅延ローディングをいれてSEO対策しています。

実装云々

Remark で実現しています。

小一時間で作ったコードなので、バグはあるかもですが載せておきます。
よかったら参考にしてみてください。

import { visit } from 'unist-util-visit';

function createDom(id: string) {
  // YouTubeの埋め込みURLを生成
  const url = `https://www.youtube.com/embed/${id}`;

  // w-full 4:3
  const className = 'w-full aspect-16/9 h-full';

  return `
  <iframe
    class="${className}"
    src="${url}"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen
    loading="lazy"
  ></iframe>
  `;
}

export default function remarkYoutube() {
  //  YoutubeのURL(https://www.youtube.com/watch?v=)を取得して、iframeに変換する
  return async (tree: any) => {
    visit(tree, 'paragraph', (paragraphNode: any, index) => {
      if (paragraphNode.children.length !== 1) {
        return tree;
      }

      if (paragraphNode && paragraphNode.data !== undefined) {
        return tree;
      }

      visit(paragraphNode, 'text', (textNode: any) => {
        const youtubeUrl = textNode.value.match(
          /(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+/g,
        );

        if (!youtubeUrl) {
          return tree;
        }

        const youtubeId = new URL(youtubeUrl[0]).searchParams.get('v');
        if (!youtubeId) {
          return tree;
        }

        const dom = createDom(youtubeId);
        const cardNode = {
          type: 'html',
          value: dom,
        };

        tree.children.splice(index, 1, cardNode);

        return tree;
      });
    });
  };
}

上記のコードを、 astro のコンフィグ( astro.config.ts )に入れればOK。

export default defineConfig({
  markdown: {
    shikiConfig: {
      theme: 'css-variables',
    },
    remarkPlugins: [remarkYoutube], // こんな感じ
  },
});