Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use myst-parser in browser to generate html from myst markdown string? #824

Closed
fhg-isi opened this issue Dec 23, 2023 · 8 comments
Closed
Labels
enhancement New feature or request

Comments

@fhg-isi
Copy link

fhg-isi commented Dec 23, 2023

If I try to use the html example given at

https://github.com/executablebooks/mystmd/tree/main/packages/myst-parser

I get the error Uncaught ReferenceError: unified is not defined

a) Could you please give a full example on how to use myst-parser in the browser to generate html from myst markdown string?

b) Also see https://stackoverflow.com/questions/77707969/how-to-use-myst-parser-for-sharepoint-web-part

@fhg-isi fhg-isi added the enhancement New feature or request label Dec 23, 2023
Copy link

welcome bot commented Dec 23, 2023

Thanks for opening your first issue here! Engagement like this is essential for open source projects! 🤗

If you haven't done so already, check out EBP's Code of Conduct. Also, please try to follow the issue template as it helps other community members to contribute more effectively.

If your issue is a feature request, others may react to it, to raise its prominence (see Feature Voting).

Welcome to the EBP community! 🎉

@agoose77
Copy link
Collaborator

agoose77 commented Jan 8, 2024

Hi @fhg-isi, thanks for opening this issue! It looks like our documentation is slightly out of date.

I'm new to the nitty-gritty of getting this up and running, but did some digging around. I can provide a solution, but do keep an eye on this thread in case one of the team provides a superior alternative.

The error that you're seeing is caused by missing JS dependencies. You need to ensure that your script is being executed in a context where those modules have been loaded. The easiest solution in most modern browsers is to use a <script type="module"> tag to make use of the import statement:

<html>
  <head>
  <link rel="stylesheet" type="text/css" href="myst.css">
  </head>
  <div id="output"></div>
  <script type="module">
    import { unified } from 'https://esm.sh/unified@10.1.2?bundle'
    import { mystParser } from 'https://esm.sh/myst-parser@1.0.21?bundle'
    import { State, transform, mystToHast, formatHtml } from 'https://esm.sh/myst-to-html@1.0.21?bundle'
    import rehypeStringify from 'https://esm.sh/rehype-stringify@9.0.3?bundle'

    const pipe = unified()
      .use(mystParser)
      .use(transform, new State())
      .use(mystToHast)
      .use(formatHtml)
      .use(rehypeStringify);
    const result = pipe.processSync(':::{important}\nHello to the world!\n:::');

    document.getElementById('output').innerHTML = result.value;

  </script>
  </body>
</html>

You can see that this is very close to what the documentation already suggests, but it's a mix of the Node and browser examples. You'll also need a stylesheet, (here, myst.css) of which an example is given in https://github.com/executablebooks/mystmd/blob/690f4695bb172d5a0aa05c0f4600064540528029/packages/myst-parser/myst.css. Note that this is not a published style sheet; we only use it internally for our demos. My thinking is that you'd want to fork this and tweak it. cc @rowanc1

@riziles
Copy link

riziles commented Jan 9, 2024

@agoose77 , this is great! Any chance you can add an example with a LaTeX equation?

@agoose77
Copy link
Collaborator

agoose77 commented Jan 9, 2024

So (again), there might be a better way, but here's a start.

You can load KaTeX and massage the equations to be picked up by KaTeX's auto renderer:

import { unified } from 'unified'
import { mystParser } from 'myst-parser'
import rehypeDocument from 'rehype-document'
import { State, transform, mystToHast, formatHtml } from 'myst-to-html'
import rehypeStringify from 'rehype-stringify'
import mystToMd from 'myst-to-md';
import { selectAll } from 'unist-util-select';


// Prepare math for KaTeX auto renderer by wrapping in `$$`
function mathTransform(tree, file, opts) {
  const inlineNodes = selectAll('inlineMath', tree);
  inlineNodes.forEach((node) => {
    node.value = `$${node.value}$`
  });
  const displayNodes = selectAll('math', tree);
  displayNodes.forEach((node) => {
    node.value = `$$${node.value}$$`
  });
}
const mathPlugin =
  (opts) => (tree, file) => {
    mathTransform(tree, file, opts);
  };


// Create a AST document, or parse using mystmd
const pipe = unified()
  .use(mystParser)
  .use(transform, new State())
  .use(mathPlugin)
  .use(mystToHast)
  .use(formatHtml)
  // Load KaTeX
  .use(rehypeDocument, {
    css: ['myst.css', 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css'],
    js: ["https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js", "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"],
    script: `document.addEventListener("DOMContentLoaded", (event) => {
        renderMathInElement(document.body, {
            delimiters: [{
                    left: "$$",
                    right: "$$",
                    display: true
                },
                {
                    left: "$",
                    right: "$",
                    display: false
                }
            ]
        });
    });`
  })
  .use(rehypeStringify);

// Demo
const result = pipe.processSync(`
:::{important}
Hello to the world!
:::

The math says {math}\`x + y \\frac{x}{y}\`
`);
console.log(result.value);

You don't have to use KaTeX, but I just knew it would be easy to get up and running with it.

@riziles
Copy link

riziles commented Jan 9, 2024

Thanks @agoose77 ! This is great! I made some tweaks (see below) to make it a standalone HTML file. FYI, it doesn't look like the table alignment is working, but I believe this is a known issue: #238

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="myst.css">
  <link rel="stylesheet" type="text/css" href='https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css'>
</head>
<div id="output"></div>
<script type="module">
  import { unified } from 'https://esm.sh/unified@10.1.2?bundle';
  import { mystParser } from 'https://esm.sh/myst-parser@1.0.21?bundle';
  import { State, transform, mystToHast, formatHtml } from 'https://esm.sh/myst-to-html@1.0.21?bundle';
  import rehypeStringify from 'https://esm.sh/rehype-stringify@9.0.3?bundle';
  import { selectAll } from 'https://esm.sh/unist-util-select@5.1.0?bundle';
  import renderMathInElement from "https://esm.sh/katex@0.16.9/dist/contrib/auto-render.mjs";



  // Prepare math for KaTeX auto renderer by wrapping in `$$`
  function mathTransform(tree, file, opts) {
    const inlineNodes = selectAll('inlineMath', tree);
    inlineNodes.forEach((node) => {
      node.value = `$${node.value}$`
    });
    const displayNodes = selectAll('math', tree);
    displayNodes.forEach((node) => {
      node.value = `$$${node.value}$$`
    });
  }
  const mathPlugin =
    (opts) => (tree, file) => {
      mathTransform(tree, file, opts);
    };


  // Create a AST document, or parse using mystmd
  const pipe = unified()
    .use(mystParser)
    .use(transform, new State())
    .use(mathPlugin)
    .use(mystToHast)
    .use(formatHtml)
    // Load KaTeX
    .use(rehypeStringify);

  // Demo
  const result = pipe.processSync(`
# Myst Example

:::{important}
Hello to the world!
:::

| left | center | right |
| :--- | :----: | ----: |
| a    | b      | c     |

:::{figure} https://source.unsplash.com/random/500x200/?mountain
:name: my-fig
:align: center

My **bold** mountain 🏔🚠.
:::

The math says $x^2 + \\big( y \\frac{x}{y} \\big)$
`);

  document.getElementById('output').innerHTML = result.value;

  // console.log(result.value);
  document.addEventListener("DOMContentLoaded", function () {
    renderMathInElement(document.body, {
      // customised options
      // • auto-render specific keys, e.g.:
      delimiters: [
        { left: '$$', right: '$$', display: true },
        { left: '$', right: '$', display: false },
        { left: '\\(', right: '\\)', display: false },
        { left: '\\[', right: '\\]', display: true }
      ],
      // • rendering keys, e.g.:
      throwOnError: false
    });
  });

</script>

</body>

</html>

@fhg-isi
Copy link
Author

fhg-isi commented Jan 20, 2024

I asked here another follow up question: How to resolve relative links?

https://github.com/orgs/executablebooks/discussions/1125

@riziles
Copy link

riziles commented Jan 22, 2024

@fhg-isi , I think for something sophisticated involving multiple markdown documents you may want to use the myst cli's build command to convert all the necessary files to a website as described here: https://mystmd.org/guide/quickstart-myst-websites . My example was more for an edge case where I wanted to dynamically incorporate some simple MyST-flavoured Markdown into a pre-existing webpage.

If you can't use the myst cli for some reason, I'm sure that what you want to do is possible, but I think it's probably more of a unified / remark question than a MyST question (although mine certainly was, too, so please excuse my hypocrisy).

@fhg-isi
Copy link
Author

fhg-isi commented Jan 22, 2024

Thank you. Solved it using regular expressions, see https://github.com/orgs/executablebooks/discussions/1125

@fhg-isi fhg-isi closed this as completed Jan 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants