PrismJS / prism

Lightweight, robust, elegant syntax highlighting.
https://prismjs.com
MIT License
12.34k stars 1.29k forks source link

JSON formatting breaks inside Docusaurus2 #3066

Closed ArthurFlag closed 3 years ago

ArthurFlag commented 3 years ago

Information:

Description

Go on any page of this website that contains a code block. Hover over the top-right links to the API reference docs, and the code blocks of the current page break.

It's a website built with Docusaurus2. I've reported the issue to them, but it doesn't seem to come from them, and I can't figure out the issue so I'm thinking it's part of Prism.

img

Example of formatted code block:

<div class="codeBlockContainer_K1bP">
  <div class="codeBlockContent_hGly javascript">
    <pre
      tabindex="0"
      class="prism-code language-javascript codeBlock_23N8 thin-scrollbar"
      style="color: rgb(191, 199, 213); background-color: rgb(41, 45, 62)"
    ><code class="codeBlockLines_39YC"><span class="token-line" style="color: rgb(191, 199, 213);"><span class="token plain">talon</span><span class="token punctuation" style="color: rgb(199, 146, 234);">.</span><span class="token method function property-access" style="color: rgb(130, 170, 255);">trackEvent</span><span class="token punctuation" style="color: rgb(199, 146, 234);">(</span><span class="token string" style="color: rgb(195, 232, 141);">"session1234"</span><span class="token punctuation" style="color: rgb(199, 146, 234);">,</span><span class="token plain"> </span><span class="token string" style="color: rgb(195, 232, 141);">"viewedRestaurants"</span><span class="token punctuation" style="color: rgb(199, 146, 234);">,</span><span class="token plain"> </span><span class="token punctuation" style="color: rgb(199, 146, 234);">{</span><span class="token plain"> restaurants</span><span class="token operator" style="color: rgb(137, 221, 255);">:</span><span class="token plain"> </span><span class="token string" style="color: rgb(195, 232, 141);">"12|53|56|"</span><span class="token plain"> </span><span class="token punctuation" style="color: rgb(199, 146, 234);">}</span><span class="token punctuation" style="color: rgb(199, 146, 234);">)</span></span></code></pre>
    <button
      type="button"
      aria-label="Copy code to clipboard"
      class="copyButton_Ue-o clean-btn"
    >
      Copy
    </button>
  </div>
</div>

The same code block but broken:

<div class="codeBlockContainer_K1bP">
  <div class="codeBlockContent_hGly javascript">
    <pre
      tabindex="0"
      class="prism-code codeBlock_23N8 thin-scrollbar language-javascript"
      style="color: rgb(191, 199, 213); background-color: rgb(41, 45, 62)"
    ><code class="codeBlockLines_39YC language-javascript">talon<span class="token punctuation">.</span><span class="token function">trackEvent</span><span class="token punctuation">(</span><span class="token string">"session1234"</span><span class="token punctuation">,</span> <span class="token string">"viewedRestaurants"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> restaurants<span class="token operator">:</span> <span class="token string">"12|53|56|"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
    <button
      type="button"
      aria-label="Copy code to clipboard"
      class="copyButton_Ue-o clean-btn"
    >
      Copy
    </button>
  </div>
</div>

Somehow, codeBlockLines_39YC loses its javascript class.

Let me know if you need extra information.

RunDevelopment commented 3 years ago

Your Prism setup is weird.

The JSON code is clearly highlighted as JSON (SSR I reckon) but the client-side instance of Prism doesn't have JSON.

image

Same with the Copy to clipboard plugin. That JSON code block clearly has a Copy button but your client-side Prism instance doesn't have that plugin loaded.

image

Even weirder: the client-side Prism instance only gets loaded after you hover over those links.

The cause

I think this lazy loading is the problem. Prism will auto highlight all code blocks on a page when loaded if Prism.manual isn't true.

image

What happens is the following:

  1. Prism gets loaded by hovering those links.
  2. Prism (re-)highlights all code blocks.
  3. Since the client-side Prism instance doesn't have JSON, it removes all highlighting.

So why is the code reformatted? It isn't. At least, not from Prism's perspective. Docusaurus2 or prism-react-renderer (whichever is responsible) doesn't use line breaks (\n or \r\n) but CSS flex layout to separate lines. This means that the text content of the <code> element doesn't contain line breaks.

image (Seems familiar, right?)

Solutions

The problem is Prims re-highlighting the entire page. The solution is simple:

Set Prism.manual = true. (See the docs on how to do this.)

Also, this fix has to be applied by whichever library loads/uses Prism. You can apply this fix on your website right now but please make an issue for the library responsible so they can fix it for everyone.

ArthurFlag commented 3 years ago

Thanks a lot @RunDevelopment, this is great news 👍

Let's ping @slorber. Is it something that can be set by default in Docusaurus?

slorber commented 3 years ago

Hey,

I'm on holiday soon so can't investigate much, but the Docusaurus site is able to render json properly:

https://docusaurus.io/docs/next/browser-support#default-values

image

So I guess the issue is related to @ArthurFlageul 's site specificities


The JSON code is clearly highlighted as JSON (SSR I reckon) but the client-side instance of Prism doesn't have JSON.

We have a webpack config to optimize the loading of Prism packages and reduce bundle size (if I remember correctly):

    configureWebpack() {
      const prismLanguages = additionalLanguages
        .map((lang) => `prism-${lang}`)
        .join('|');

      return {
        plugins: [
          new ContextReplacementPlugin(
            /prismjs[\\/]components$/,
            new RegExp(`^./(${prismLanguages})$`),
          ),
        ],
      };
    },

Same with the Copy to clipboard plugin. That JSON code block clearly has a Copy button but your client-side Prism instance doesn't have that plugin loaded.

We don't use a copy to clipboard plugin, it's code from Docusaurus

I know we have a quite unusual setup (that I didn't work on much) and Prism is likely not the problem here.

I don't think Docusaurus either because we render json correctly, as well as many other doc sites (it's not like json is not a popular language...)


@ArthurFlageul I already mentioned this is not valid JSON:

 "effects": [ {   "campaignId": 377,   "rulesetId": 1096,   "ruleIndex": 0,   "ruleName": "25% off",   "effectType": "setDiscount",   "triggeredByCoupon": 97534,   "props": {     "name": "25% off",     "value": 66.25 }

Please add {} around that code block first. I don't want to invest time solving problems we don't have in the first place 😅