fast-reflexes / better-react-mathjax

MIT License
124 stars 16 forks source link

How do i use mathjaxContext within a web component. Problem being i'm not loading mathjax externally #17

Open brendena opened 2 years ago

brendena commented 2 years ago

My problem is that MathJaxContext is expecting you to load the src from a external file. Is there a way currently a to pass mathjaxcontext a already included mathjax object. What i'm trying to do is create a webcomponent that will have mathjax include inside of it.

I tried to not include MathJaxContext, but there where some state values about loading that caused it to fail.

fast-reflexes commented 2 years ago

Hi there!

With the current setup you have to have a MathJaxContext, it's part of the contract so excluding it will simply not work.

Typical MathJax usage in the browser has the pattern where the source is downloaded and installed on the window object and because simplicity is a virtue, similar usage has been the goal of this package since the start. That being said, it's on my agenda to check whether server-side generation using MathJax could be added to this package, and potentially during this process, it could be investigated whether the MathJax object from the MathJax source package could be added to this package in a way so that the downloading of the MathJax script could be removed / optional.

However, due to this atypical use of MathJax in the browser, it's very hard to say how this would affect the package size of this package, how it would affect tree-shaking and whether any additional manual steps would be needed for the resulting MathJax object to function exactly as it does when installed in the typical way. If the functionality could be added in a seamless way without too much hacking and without it changing the behaviour of this package too much, I would be willing to add it, otherwise perhaps your use-case is so specific it warrants its own custom solution or a package taking care of that specific situation.

I'm not too familiar with web components but is it considered bad practice for them to have ANY external dependencies (such as web fonts, JQuery, pictures etc...) taken from elsewhere upon loading them? If not then downloading MathJax from a CDN shouldn't be a problem. Otherwise, I guess there is no solution to your problem within this package at the current time.

Have you tried downloading the MathJax script from the CDN as a file and then storing it as a local script which you load in the src property? I guess a web component is a bundle and if you store the script inside the bundle, then no external dependency would be needed ...

Will keep this ticket open and tag it properly.

PS! You know you can host your own MathJax script to use with the src property, but I guess that won't change anything in this usecase DS

brendena commented 2 years ago

I'm not the most elegant typescript programmer. So what i was thinking of doing is creating a MathJaxBaseContextPassThrough component. What that would do is basically look for mathjax in the windows context or have some sort of way to pass the mathjax instance into it. The MathJaxContext seems to just primarily set the MathJaxBaseContext. So i thought it would be to hard to do MathJaxContext that didn't handle any of the file loading.

This is something that i think i could probably figure out how to do, i'm just having problems including the library when i build it.

I get this error

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

Which i'm guessing comes down to the fact that i'm using react 16.13 and not the react 18 your using. But whats weird is that it works fine when i just grab it from npm.

Also thanks for the solid quick response. As for loading it externally. I would prefer it to be self contained. But if this turns into a lot of effort. I'll probably do what you suggest and host the file somewhere.

fast-reflexes commented 2 years ago

I'm not seeing your idea super clearly... but what you need to do is replace the injected script call for MathJax with an import from the MathJax package and place that in the MathJaxContext and then also make sure that it works in the same way as it does when installed in the browser (not 100% sure exactly what kind of setup and initialization MathJax performs when fetched that you might have perform manually yourself but I think there are some good explanations on this in the MathJax repo). Not a super easy thing to do...

The best thing would probably be to skip the MathJaxContext altogether and just import MathJaxBaseContext from this package and create your own context provider where you supply MathJax. Remember that you need to import the mathjax package into your dependencies since better-react-mathjax only lists it in devDependencies.

Regarding hooks, this library works with React 16.8 + so the version is not a problem. The problem is that you're using MathJaxContext from a non-functional component which is not allowed for any hook, and thereby not the MathJaxContext either (which makes use of hooks).

Do you have a repo or something where I can see what you're creating and how you're creating it? It's hard to understand from the description exactly what the context is and what you want to achieve? :) I might have a short go at this in the weekend if I have some time.

brendena commented 2 years ago

I will worn you this is not pretty code but i was able to just bypass loading anything. https://github.com/brendena/better-react-mathjax/blob/06f6dbd03e795f65f3ed1be41b2a28f9a72b7a7d/src/MathJaxContext/MathJaxContext.tsx

basically i just used the MathJaxContext for it's react context promise.


  function scriptInjector<T>(res: (mathJax: T) => void, rej: (error: any) => void) {
      const mathJax = (window as any).MathJax
      res(mathJax)
  }

When it comes to actually building mathjax, the team at mathjax has some good starter code. https://github.com/mathjax/MathJax-demos-web/tree/master/custom-component

If you want to see it in action here's the component that i have using it https://github.com/brendena/MathEquations-component/blob/master/src/direflow-components/math-equation-component/components/math-jax-viewer.tsx