Markdown previewer with Prism.js highlighting confusion

I have everything working fine apart from inline code block highlighting using Prism.js.

I have it working for anything within <pre><code> tags when I use 3 x escaped back ticks. However anything within 1 x escaped back ticks which shows as just <code> tags on inspection is not being detected/highlighted.

I guess my main concern is I feel I’m not completely understanding the documentation for Marked.js highlighting section or what the following does:

const renderer = new marked.Renderer();

I have resorted to copying the highlight function inside marked.setOptions () from the example code project, but mine works with or without the line above. I also read an article where someone used the Prism API and Prism.highlightAll() inside useEffect (commented out in my code) but that wouldn’t work at all.

I have put code below for just my Previewer.js component (I’m using VS code and trying to upload all projects to github pages for practise).

Can anyone point me to any articles or anything that might help me understanding the docs for Prism.js and Marked.js as I think I’m quite poor at understanding docs. I don’t like copying things without understanding them.

To summarise I don’t completely understand the following:
1.

    highlight: function (code) {
        return Prism.highlight(code, Prism.languages.javascript, 'javascript');
      } 

How did the example project get to that from reading this in the marked.js docs example as the above is so much lighter:
Using Advanced - Marked Documentation

    highlight: function(code, lang, callback) {
    require('pygmentize-bundled') ({ lang: lang, format: 'html' }, code, function (err, result) {
      callback(err, result.toString());
    });
  }
  1. Why are people using the following when mine works without.
    const renderer = new marked.Renderer();

and then passing in {renderer: renderer} as additional argument to marked() in the dangerouslySetInner HTML object?

  1. Why is Prism therefore only detecting (and highlighting) my <pre> <code> tags and not just the <code> tags

My code below. I’ve searched around for days, but can’t seem to get my head round it and I find the documentation for both libraries very cryptic, which I’m sure says more about me than the docs!

import React from 'react';
import { useEffect } from 'react';
import './TextAreas.css';
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';

const marked = require("marked");

marked.setOptions({
    breaks: true,
    highlight: function (code) {
        return Prism.highlight(code, Prism.languages.javascript, 'javascript');
      }
  });

const renderer = new marked.Renderer();

export default function Previewer(props) {
//const renderer = new marked.Renderer();
   /* useEffect(() => {
        Prism.highlightAll();
      }) */
    return (
        <div className="text-container">
            <div
            //ref={outputTextArea}
            className="preview-area" 
            dangerouslySetInnerHTML={{__html: marked(props.text, {renderer: renderer})}}
            id="preview" 
            style={{paddingTop: "0px", paddingBottom: "0px", paddingLeft: "1em"}} 
            >
            </div>
        </div>
    )
}

Right, how can that possibly work?

Code in markdown, so single backticks, that produces

<code>Some code</code>

The only way you’re going to get inline highlighting is if you actually write the HTML for a code block (which is valid in Markdown, there is no issue with doing that), because you need to specify the language to get syntax highlighting for a language, it has to be

<code class="language-xxx">Some code</code>

Where “xxx” is a language.

The Prism function needs something to attach to in the HTML, if you don’t provide that then it won’t hook onto anything. And because

`some code`

just produces

<code>some code</code>

you can’t provide anything that way.

With fenced code blocks, there is normally a way to indicate some extra info re. what the language is: all that will do is generate a class on the HTML (which in turn lets you apply the prism function)

Thanks for your reply, but I’m afraid I don’t understand what you mean here:

Right, how can that possibly work?

I want it to work like the codepen example provided in the project:
https://codepen.io/freeCodeCamp/full/GrZVVO.

When I enter same text in my editor for the below (I have copied from the codepen example below). It only highlights the multiline code section:

// this is multi-line code:

function anotherExample(firstLine, lastLine) {
  if (firstLine == '```' && lastLine == '```') {
    return multiLineCode;
  }
}

but doesn’t highlight this bit:

Heres some code, <div></div>, between 2 backticks.

Ah, sorry I thought you wanted syntax specific highlighting. Anyway, so prism lets you apply syntax specific highlighting to any code elements if you add it to an ancestor html element.

const renderer = new marked.Renderer()

marked is an object with some functions attached. One of those functions takes a string of markdown and returns a string of HTML. That object has some default properties it uses when converting, so you can just use it as-is. But you can configure your own instance of that object. That’s what the Renderer function is for, to specify some custom rendering logic.

The Renderer function takes an configuration object. One of the properties of that configuration object is a field called highlight. The value of highlight a function that accepts a three arguments.

  • first argument is a string, and when marked encounters a string it regards as code, it will run that function against it.
  • second is what language (you can specify it for fenced code blocks)
  • third is a callback if you want to do some extra thing once the highlight has been applied (in the example code, that’s catching errors)
(code) =>  Prism.highlight(code, Prism.languages.javascript, 'javascript')

In this case, run a function called highlight from the Prism library.

Why is Prism therefore only detecting (and highlighting) my <pre> <code> tags and not just the <code> tags

Don’t know as I don’t have an example to hand, but:

  • what is being injected into the HTML that marked renders (ie look at the element inspector in the browser
  • if you use the third argument, the callback, like in the example, can you s.ee if there are any errors?
1 Like

Thank you for taking the time to provide all this extra info. Some of that made sense:

marked is an object with some functions attached. One of those functions takes a string of markdown and returns a string of HTML. That object has some default properties it uses when converting, so you can just use it as-is. But you can configure your own instance of that object. That’s what the Renderer function is for, to specify some custom rendering logic.

That makes sense!

The Renderer function takes an configuration object. One of the properties of that configuration object is a field called highlight . The value of highlight a function that accepts a three arguments.

This I’m a little confused by as I thought the config object was passed to marked.setOptions() like I did here:

marked.setOptions({
    breaks: true,
    highlight: function (code, lang, callback) {
        return Prism.highlight(code, Prism.languages.javascript, 'javascript')
    }
});

I’ve also been playing around with both my code and the codepen example and realised that the line:
const renderer = new marked.Renderer();
had nothing to do with the highlighting via Prism library, but (as fas as I can tell) just to override something to do with opening links in blank targets as per their comments. (I commented it out and the highlighting still worked)

// INSERTS target="_blank" INTO HREF TAGS (required for Codepen links)
const renderer = new marked.Renderer();
renderer.link = function (href, title, text) {
  return `<a target="_blank" href="${href}">${text}</a>`;
};
  • first argument is a string, and when marked encounters a string it regards as code , it will run that function against it.
  • second is what language (you can specify it for fenced code blocks)
  • third is a callback if you want to do some extra thing once the highlight has been applied (in the example code, that’s catching errors)
(code) =>  Prism.highlight(code, Prism.languages.javascript, 'javascript')

So in the code I copied from the codepen example:

marked.setOptions({
    breaks: true,
    highlight: function (code) {
        return Prism.highlight(code, Prism.languages.javascript, 'javascript')
    }
});

The codepen author set the marked highlight function to only require the 1st argument code and passed that to the returned Prism.highlight() function. They never used the 2nd argument lang or 3rd argument callback

I’ve now managed to find a section in Prism docs where I think I now understand how the codepen author knew how to pass the other 2 arguments to the Prism.highlight() function.
Prism.languages.javascript as the 2nd argument
and the string 'javascript' as the 3rd argument

Here:
return Prism.highlight(code, Prism.languages.javascript, 'javascript')

I now have it working and, as is often the case, feel pretty dumb with my discovery!

I expected the background colour contrast of inline or fenced code blocks to be handled by the installed Prism package. I just realised that I hadn’t tried adding css background properties to my <pre> and <code> tags. So turns out it was working all along, but just highlighting syntax and not adding background color.

If you have time to quickly sanity check the above that would be much appreciated, but even if not thank’s again for taking the time to help me with this!