[FEAT] support marked.js Custom Extensions for custom rendering of markdown content

This issue has been tracked since 2023-02-16.

Which scope/s are relevant/related to the feature request?

content

Information

Details of marked Custom Extensions: https://marked.js.org/using_pro#extensions

This would allow custom rendering with user flexibility for how to mark text custom render.
For example, getting api data and custom rendering this.

In my particular use case, I'd like to be able to write markdown like the following:

---
title: Demo Post
slug: demo-post
description: Demo of using marked and MathJax
---

## Lorentz Equations

```latex
\begin{align}
  \dot{x} & = \sigma(y-x) \\
  \dot{y} & = \rho x - y - xz \\
  \dot{z} & = -\beta z + xy
\end{align}
```.

This has editor support so is nice to look at as I write it:

But when rendering I don't want html <pre><code>...</code></pre>.

I want to insert MathJax via a call to my local api so it shows the actual formulas: https://www.mathjax.org/ for details.

Describe any alternatives/workarounds you're currently using

I've not coded it yet but I imagine copying and pasting https://github.com/analogjs/analog/blob/main/packages/content/src/lib/markdown-content-renderer.service.ts and inserting the marked.use with an async marked extension would be a hack around this.

I would be willing to submit a PR to fix this issue

  • Yes
  • No
goetzrobin wrote this answer on 2023-02-27

Personally, I think this might be better implemented with a custom markdown renderer.

@Injectable()
export class MathJaxMarkdownContentRendererService implements ContentRenderer {
  platformId = inject(PLATFORM_ID);

  async render(content: string) {
     // include custom logic to support
     return content;
  }
}

export function withMathJaxMarkdownRenderer(): Provider {
  return { provide: ContentRenderer, useClass: MathJaxMarkdownContentRendererService };
}

And then use it in your application's main.ts like:

bootstrapApplication(AppComponent, {
  providers: [
    provideFileRouter(withInMemoryScrolling({ anchorScrolling: 'enabled' })),
    provideContent(withMathJaxMarkdownRenderer()),
  ],
}).catch((err) => console.error(err));

Do you agree @brandonroberts ?

brandonroberts wrote this answer on 2023-02-27

Yes, I agree

AdditionAddict wrote this answer on 2023-02-27

I'll close on this basis. There's a few gotchas to be aware of when composing marked extensions such as marked maintaining a singleton (access to private global variables!) but in principle it's possible to combine multiple marked.js extensions.

  async render(content: string) {
    // Setting options interferes with other calls to marked
    // https://github.com/markedjs/marked/issues/907
    marked.setOptions(marked.getDefaults());

    // base options
    marked.setOptions(markedPrism(prismOptions));

   // extension(s)
    marked.use(markedMathjax());

    return marked(content, { async: true });
  }

}

Here's a repo in case helpful to anyone trying to extend the marked render:
https://github.com/AdditionAddict/marked-typescript-samples

More Details About Repo
Owner Name analogjs
Repo Name analog
Full Name analogjs/analog
Language TypeScript
Created Date 2022-07-06
Updated Date 2023-03-28
Star Count 885
Watcher Count 18
Fork Count 67
Issue Count 33

YOU MAY BE INTERESTED

Issue Title Created Date Updated Date