1

我正在尝试使用 Prismjs 实现语法突出显示(标记化)代码块的服务器端渲染(注意:我知道如何通过useEffectand使用客户端渲染来做到这一点refs,并且我使用prism-react-renderer得到了这个工作。我是专门寻找“裸” Prismjs & SSR 的解决方案)。

// codeExamples = array of some code strings

const Code = ({ code, language }) => {
  const html = Prism.highlight(code, Prism.languages[language], language);
  return (
    <pre
      data-language={language}
      className={`language-${language}`}
    >
      <code
        dangerouslySetInnerHTML={{
          __html: html,
        }}
      />
    </pre>
  );
};

export default function Home() {
  return codeExamples.map((example, i) => (
    <Code
      language="javascript"
      code={example}
      key={i}
    ></Code>
  ));
}

它在某种程度上确实有效,但我遇到了一个问题:代码块被短暂地重新渲染,可能是因为属性上的前导空格:class

  • 第一次渲染:class="language-javascript"
  • 第二次渲染:class=" language-javascript

在此处输入图像描述

这导致(除了无意义的昂贵重新渲染之外)令人不快的布局偏移,通过向元素添加硬编码font-size像素来临时修复<pre>

我偶尔会收到一些警告,要么是服务器和客户端道具不匹配(现在无法重现),要么是Extra attributes from the server: class——但仅在运行时next dev,而不是在运行时next build && next start

在最新版本的 Nextjs 和 Prism 上测试。

4

1 回答 1

1

我从深入研究Prismjs 源代码中得到了答案:

if (parent && parent.nodeName.toLowerCase() === 'pre') {
    parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
}

这就是空格的来源。很明显,为什么它在这里(作为字符串连接的填充)。

className一个临时的 hacky 修复方法是在 on<pre>元素中添加一个前导空格。

<pre
   data-language={language}
   className={` language-${language}`}
>

但很明显,这不是Prismjs用于 SSR的好方法。

于 2021-03-08T21:37:56.213 回答