Portfolio-website / Blog Post

Using content-collections and rehype plugins

June 23, 2026

Documenting the process of learning how to use conetent-collections markdown compiler with plugins.

portfolio-websitewebdevcontent-management

Bruhh sometimes things are just wacky.

So I noticed that markdown links on my website would redirect to the link rather than open a new tab for it. So I needed a solution and I made one by manipulating the compiled markdown HTML code as a string as seen below.

export function outsideLinkFormatter(compiledMarkdown: string): string {
  let compiledContent: string = compiledMarkdown;

  let index_of_last_closing_bracket: number = -1;
  for (let i = compiledContent.length - 1; i >= 0; i--) {
    if (compiledContent[i] === `>`) {
      index_of_last_closing_bracket = i;
    }
    if (i + 10 <= compiledContent.length) {
      if (compiledContent.substring(i, i + 10) === `href="http`) {
        // for every outside link
        if (index_of_last_closing_bracket !== -1) {
          compiledContent =
            compiledContent.substring(0, index_of_last_closing_bracket) +
            ` target="_blank" rel="noopener noreferrer nofollow"` +
            compiledContent.substring(index_of_last_closing_bracket);
          index_of_last_closing_bracket = -1;
        }
      }
    }
  }
  // target="_blank" rel="noopener noreferrer nofollow"

  return compiledContent;
}

I'm aware that this solution is not the best. Like what if there was a code sample that this function string matched? So I asked AI what a good solution would be and it recommended using a rehype plugin to handle this. Seemed simple enough right? just follow the steps on their website and... wait... there isn't any examples... NOOOOO.

so I tried to implement it by asking AI and it came up with this...

// lib/markdown.ts
import rehypeExternalLinks from "rehype-external-links";

export const sharedRehypePlugins = [
  [
    rehypeExternalLinks,
    { target: "_blank", rel: ["noopener", "noreferrer", "nofollow"] },
  ],
];

// content-collections.ts
import { sharedRehypePlugins } from "./lib/markdown";

export const blog = defineCollection({
  ...
  transform: async (context, document) => {
    const compiledContent = await compileMarkdown(context, document, {
      rehypePlugins: sharedRehypePlugins,
    });
    return {
      ...doc,
      compiledContent,
    };
  },
});

but behold, the red squiggly line at rehypePlugins: sharedRehypePlugins, so I had to put the actual value of sharedRehypePlugins in there instead. NO IDEA WHY IT WORKED THOUGH.


previous