shikijs / next-shiki

Use Shiki with Next.js 13
26 stars 3 forks source link

Fails to load onig.wasm, themes and languages #1

Open marcofranssen opened 1 year ago

marcofranssen commented 1 year ago

In my blog I use tailwind and I have followed the instructions from the README.md. The page I share here is using the pages approach.

https://nextjs-blog-git-replace-code-blocks-highlighting-marcofranssen.vercel.app/git-recipes

components/code-block.tsx

import { Lang } from "shiki";
import { useState, useEffect } from "react";
import { highlight } from "../../lib/highlight";

export default function CodeBlock({
  title,
  url,
  children,
  language,
}: {
  title?: string;
  url?: string;
  children?: string;
  language: string;
}) {
  const [code, setCode] = useState("");
  const [isLoading, setIsLoading] = useState(false);

  const theme = "one-dark-pro";

  useEffect(() => {
    if (children) {
      setIsLoading(true);
      const highlightCode = async () => {
        const highlightPromise =
          typeof children === "string"
            ? highlight(children, theme, language as Lang)
            : Promise.resolve("You need to define codeblock as a string");

        setCode(await highlightPromise);
        setIsLoading(false);
      };

      highlightCode();
    } else {
      const parsedUrl = !url?.startsWith("http")
        ? `/downloads/code/${url}`
        : url;

      const fetchCode = async () => {
        setIsLoading(true);
        const res = await fetch(parsedUrl);
        const body = await res.text();
        const highLightedCode = await highlight(body, theme, language as Lang);
        setCode(highLightedCode);
        setIsLoading(false);
      };

      fetchCode();
    }
  }, [children, url, language]);

  return isLoading ? (
    <div data-rehype-pretty-code-fragment>
      {title && <div data-rehype-pretty-code-title>{title}</div>}
      <pre data-language={language} data-theme={theme}>
        <code data-language={language} data-theme={theme}>
          Loading…
        </code>
      </pre>
    </div>
  ) : (
    <div data-rehype-pretty-code-fragment>
      {title && <div data-rehype-pretty-code-title>{title}</div>}
      <pre data-language={language} data-theme={theme}>
        <code
          data-language={language}
          data-theme={theme}
          dangerouslySetInnerHTML={{ __html: code }}
        />
      </pre>
    </div>
  );
}

lib/highlight.js

import { Highlighter, Lang, Theme } from "shiki";
import { renderToHtml, getHighlighter } from "shiki";

export async function highlight(code: string, theme?: Theme, lang?: Lang) {
  const highlighter: Highlighter = await getHighlighter({
    langs: lang ? [lang] : [],
    theme: theme,
  });

  const tokens = highlighter.codeToThemedTokens(code, lang, theme, {
    includeExplanation: false,
  });
  const html = renderToHtml(tokens, { bg: "transparent" });

  return html;
}

On this page I use the code-block as following:

import CodeBlock from "../components/blocks/code-block";

…
…
…

          <CodeBlock language="bash">
            git cherry-pick --strategy recursive --strategy-option theirs
            «mergeCommitHash»^..«mergeCommitHash»
          </CodeBlock>

          <CodeBlock
            title=".gitconfig"
            url="https://raw.githubusercontent.com/marcofranssen/dotfiles/master/.gitconfig"
            language="ini"
          />

I have following in the next config


    experimental: {
      appDir: true,
      serverComponentsExternalPackages: ["vscode-oniguruma", "shiki"],
    },

What am I missing to make it work? 🤔

For other pages you might notice it does work as there I'm prepocessing the md files using rehype. https://nextjs-blog-git-replace-code-blocks-highlighting-marcofranssen.vercel.app/secure-your-software-supply-chain-using-sigstore-and-github-actions

The code blocks that work are processed via rehype, the ones that don't work are the ones clientside resolving the content on the given url as shown in above example.

It would be really cool if this example could be updated to also show how to use shiki client-side using the wasm module.

marcofranssen commented 1 year ago

As a workaround I now do following:

cd public
ln -s ../node_modules/shiki/dist dist
ln -s ../node_modules/shiki/themes themes
ln -s ../node_modules/shiki/languages languages
git add public
git commit -m "Add symlinks for shiki client-side integration"

Not sure if there is a better approach.

https://github.com/shikijs/shiki/issues/398#issuecomment-1531314736

However now realizing this breaks the build and only works in the development server.