pngwn / MDsveX

A markdown preprocessor for Svelte.
https://mdsvex.pngwn.io
MIT License
2.47k stars 103 forks source link

Support math syntax (latex/katex/etc) #302

Open alecandido opened 3 years ago

alecandido commented 3 years ago

I would like to have math in markdown, for this reason I'm using the configurations reported at the bottom.

Nevertheless math is not rendering in markdown neither enclosed in $ (or double $$), nor explicitly annotated in html, e.g.:

Lift($L$) can be determined by Lift Coefficient ($C_L$) like the following
equation.

<div class="math math-display">
  L = \frac{1}{2} \rho v^2 S C_L
</div>

it is rendered literally, without any transformation.

Is this related to #206? Will it be solved, sooner or later? (otherwise I have to consider dropping mdsvex)


// mdsvex.config.js
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';

export default {
  extensions: [".svx", ".md"],
  remarkPlugins: [
    remarkMath,
  ],
  rehypePlugins: [
    rehypeKatex,
  ],
};
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
import preprocess from 'svelte-preprocess';
import { mdsvex } from 'mdsvex';
import mdsvexConfig from "./mdsvex.config.js";

const config = {
  preprocess: [
    mdsvex(mdsvexConfig),
    preprocess()
  ],

  extensions: ['.svelte', '.md', '.svx'],

  kit: {
    adapter: adapter(),
    target: '#svelte'
  }
};

export default config;
pngwn commented 3 years ago

I had a little look at this last night, I can get remark-math working fine, as long as I use an older version (2 or 3 iirc). The reason rehype-katex (which would format things like fractions in second block) isn't working is because of how HTML is represented internally. retype plugins are bit hit and miss in mdsvex due to some quirks of the internal AST.

Math syntax (and rendering) will have almost first class support in the next version which is being actively worked on. I can't give a firm ETA but it will be within the next few months at most barring any major complications. I'd love to have it out sooner but there is only so much time in the day!

Hope this helps clarify the issue at least, even thought it does not yet solve the problem.

alecandido commented 3 years ago

Yes, perfect! I love mdsvex fwiw, and I really would like to make it working.

Unfortunately the thing I wanted to use math for have a deadline of two weeks, so I need either a solution or a workaround by myself.

retype plugins are bit hit and miss in mdsvex due to some quirks of the internal AST.

Since my need I was thinking about jumping into the code and see if I were good enough to get it working in whatever way (not that I had great hopes, but the issue deserved an attempt), and that's quite a hint of a direction not to try.

Math syntax (and rendering) will have almost first class support in the next version which is being actively worked on. I can't give a firm ETA but it will be within the next few months at most barring any major complications. I'd love to have it out sooner but there is only so much time in the day!

I was very willingful to try anything available, unfortunately last commit coincides with last released version (same as last package on npm) and there is no other branch. Do you have anything more than what there is or should start from Jul 2?

I want to thank you for your job, nothing is perfect and everything can always be improved... but mdsvex is already pretty enjoyable :D I would be glad to do something as well, but I'm not very confident to be able to merge a PR myself...

pngwn commented 3 years ago

Let me try something. I think it can be made to work without any changes to mdsvex. I'll get back to you today.

alecandido commented 3 years ago

That's wonderful, I will keep listening for updates!

pngwn commented 3 years ago

I had a go at making this work and got some of the way here: https://github.com/pngwn/mdsvex-math. If you take a look at the svelte.config.js you can see how I got it working.

The problem is, it isn't fully working. Certain syntax doesn't work because svelte chokes on it. But a good chunk of the syntax is supported.

The biggest issue is that svelte tries to evaluate anything in { }. So expressions like k_{n-1} will throw an error that n is not defined and expressions like k_{2-1} will come out as k_{1} because svelte will actually evaluate them.

I think this requires a deeper integration than I have time for right now, if you need solid math support then I'd consider using a plain markdown processor for the time being until mdsvex has the necessary support for math.

alecandido commented 3 years ago

Thank you very much, I would like the complete one of course, but if something is already working I will squeeze what I need in that something.

In any case, I appreciate very much your effort!

pngwn commented 3 years ago

I tried something different that works much better. Instead of using the HTML form that comes with a bunch if issues in mdsvex:

<div class="math math-display">
  L = \frac{1}{2} \rho v^2 S C_L
</div>

we can use a custom code block:

```math
  L = \frac{1}{2} \rho v^2 S C_L


Then we can just get easy access to the raw content without any funny business. You can see this set up and working in the latest commit of https://github.com/pngwn/mdsvex-math. The index route has some working examples. The relevant config is in the [`mdsvex` config file](https://github.com/pngwn/mdsvex-math/blob/main/mdsvex.config.js). There is a custom plugin that specifically handles code blocks with a `math` language.

I did have issues getting macros to work, they seem to cause some kind of parsing issue that I can't quite work out but other syntax seems to work well. The line `$L$` style syntax also works fine as before.

If you try to set this up in your own project the versions of some of the dependencies are important, katex and mdsvex don't matter much (use latest) but for the other three specific version are required.

package | version | when installing
---------|--------| ---------
katex | `latest` | `katex`
mdsvex | `latest` | `mdsvex`
rehype-katex | `5.x.x` | `rehype-katex@5`
remark-math | `2.x.x` | `remark-math@2`
unist-util-visit | `2.x.x` | `unist-util-visit@2`

Hope this helps! Give me a shout if there is anything else I can do to help.
alecandido commented 3 years ago

It helped a lot, and works like a charm! From my point of view you can even consider this issue closed, but you decide.

Give me a shout if there is anything else I can do to help.

I need you to put somewhere a sponsor button, at least I owe you a coffee :D

pngwn commented 3 years ago

Maybe I'll sort something out one day :D

Glad this is all working for you

I think I'll keep this open but I'll change the title to be about supporting math syntax, it will help me to track it for v1.

EricRovell commented 3 years ago

Maybe I'll sort something out one day :D

Glad this is all working for you

I think I'll keep this open but I'll change the title to be about supporting math syntax, it will help me to track it for v1.

Thank you a lot!

I used Math component using raw string as input to calm down svelte arguing and other problems :) Your setup worked, it helped!

Looking forward to future Math support in mdsvex!

durasj commented 2 years ago

I'm using the latest version of SvelteKit, and the only thing I had to do was to downgrade to rehype-katex@5, remark-math@2, and unist-util-visit@2. Using both $ and $$ works like a charm - including {}! :slightly_smiling_face:

image

There are some other issues with plugins, but I'll be patiently waiting for the upcoming version as those are not really urgent for me. Thanks and keep up the good work.

regisin commented 2 years ago

I'm using the latest version of SvelteKit, and the only thing I had to do was to downgrade to rehype-katex@5, remark-math@2, and unist-util-visit@2. Using both $ and $$ works like a charm - including {}! 🙂

image

There are some other issues with plugins, but I'll be patiently waiting for the upcoming version as those are not really urgent for me. Thanks and keep up the good work.

The problem with {} still exists though, if you have math variables like 'a', svelte complains: L = \frac{a}{2} \rho v^2 S C_L

durasj commented 2 years ago

You are mostly right @regisin. I didn't try it with variables, and now that I did, I see it struggles with that. However, at least doing something like \frac{1+2}{2} works. Meaning the output doesn't seem to depend on the evaluation the way someone mentioned previously. So even though the evaluation happens, everything is fine as long as it goes through.

A small workaround for that, for the time being, can be to just declare something like <script>let a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t;</script> at the beginning of the file. I can definitely live with that for now as it is just one line to get rid of and none of the real content is influenced in any way.

janosh commented 2 years ago

@pngwn If you think there's some work here that can be delegated, let me know. Happy to help with this.

kwshi commented 2 years ago

Hi y'all, just wanted to plug a package I wrote to deal with these issues while trying to use mdsvex for my own website: https://github.com/kwshi/rehype-katex-svelte

It's essentially a drop-in replacement for rehype-katex, so it allows $ and $$ syntax, but it resolves the issue of Svelte choking on curly-braces by wrapping things in an {@html "..."} node. Would appreciate it if you try it out and let me know if it helps!

kelvinsjk commented 2 years ago

Can confirm rehype-katex-svelte works like a charm with remark-math@2 for me when dealing with static math (no need for the hacky variable declaration workaround anymore): thanks for the great work!

Masstronaut commented 2 years ago

I got @kwshi's rehype-katex-svelte working pretty easily with:

        "rehype-katex-svelte": "^1.0.3",
        "remark-math": "^3.0.0",
        "mdsvex": "^0.9.1",

and the CSS needed to be katex@0.12.0. I originally tried @0.15.0 and had rendering issues. Using this worked great:

<link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css"
        integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X"
        crossorigin="anonymous"
    />

Thanks for making the plugin!

kwshi commented 2 years ago

Thanks, @Masstronaut! By the way, I just published a newer version of rehype-katex-svelte (v1.1.2) which should work correctly with katex@0.15.0 (this was pointed out and addressed in kwshi/rehype-katex-svelte#2). So give that a try (npm update) if you wanted to use KaTeX 0.15 :)

jthegedus commented 2 years ago

Related: Since this issue was opened GitHub has added both Mermaid & Math Expressions

Might be worth considering using the same solution/libraries as GitHub.

janosh commented 1 year ago

What's breaking remark-math versions later than 3.0.0, anyone know?

jameslounds commented 1 year ago

is there a way to use variables from svelte in the math markdown? EDIT: There is, see below

Something like this would be nice, but I don't have the knowledge of remark or rehype to know how to do this.


<script>
  export let variables;
</script>

Lorem Ipsum $x = {@variables.x}$

EDIT:

We can just use katex.renderToString() with a string we can assemble in js. We can then wrap that in a @html block in the md to escape the curlies. displayMode renders as a block if true, and inline if omitted or false.

<script> 
    import katex from 'katex';
    export let variables;
    const eqn = katex.renderToString(`x = ${variables.x}`);
</script>

{@html eqn}

{@html katex.renderToString(`x = ${variables.x}`, {displayMode: true})}
ahmed-shariff commented 1 year ago

When I try the above solutions for the following latex

$H = ^1/_{\sqrt{2}}x$

I get the following error

Expecting Unicode escape sequence \\uXXXX

My setup:

I also tried this with rehype-katex-svelte but I get the same result. Any suggestions on how I might approach this?


Math.svelte

<script> 
 import katex from 'katex';
 export let eqn;
 const eqnText = katex.renderToString(eqn, {
     block: true,
     throwOnError: false,
     output: 'html'
 });
</script>

{@html eqnText}

test.md

<script>
  import Math from "$lib/Math.svelte";
</script>

<Math eqn="H = ^1/_{\sqrt{2}}x"/>

Full log:

{
  name: 'ParseError',
  id: 'D:/Projects/ahmed-shariff.github.io/svelte/src/posts/2018-09-10-quantum_computing.md',
  message: 'D:/Projects/ahmed-shariff.github.io/svelte/src/posts/2018-09-10-quantum_computing.md:6:21 Expecting Unicode escape sequence \\uXXXX',
  frame: ' 4 |  \n' +
    ' 5 |  \n' +
    ' 6 |  <Math eqn="H = ^1/_{\\sqrt{2}}x"/>\n' +
    '                           ^',
  code: 'parse-error',
  stack: '',
  loc: {
    line: 6,
    column: 21,
    file: 'D:/Projects/ahmed-shariff.github.io/svelte/src/posts/2018-09-10-quantum_computing.md'
  },
  plugin: 'vite-plugin-svelte',
  pluginCode: '<script>\r\n' +
    '  import Math from "$lib/Math.svelte";\r\n' +
    '</script>\r\n' +
    '\r\n' +
    '<Math eqn="H = ^1/_{\\sqrt{2}}x"/>\r\n' +
    '\r\n'
}
ian-viri commented 10 months ago

@kwshi thank you for your effort on rehype-katex-svelte -- it worked well for my use case!

For anyone else who tries it and things are rendering twice, don't forget to bring in the rehype-katex css (it's in @kwshi 's README, I just missed it the first time)