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

Docusaurus does not run ScalaJS snippets #588

Open
vincenzobaz opened this issue Nov 26, 2021 · 2 comments
Open

Docusaurus does not run ScalaJS snippets #588

vincenzobaz opened this issue Nov 26, 2021 · 2 comments

Comments

@vincenzobaz
Copy link

vincenzobaz commented Nov 26, 2021

ScalaJS snippets

Markdown files containing snippets with the modifier scala mdoc:js are transformed into markdown files which end with two script tags

<script type="text/javascript" src="../assets/somePath/someFile.md.js" defer></script>
<script type="text/javascript" src="../assets/somePath/mdoc.js" defer></script>

where someFile.md.js contains the snippet compiled to Javascript via ScalaJS.

If I run docs/mdoc --watch the web UI allows to open the new file and the JS is executed.

The problem

However when Docusaurus v2 (now default) is used with sbt-mdoc, these scripts are not executed.
This is connected to Docusaurus being a React-based SPA.

It is a pity not to use this very nice feature of mdoc!

Some ideas to solve the problem

Docusaurus accepts MDXv1 files as we can read here. This means two things:

  1. We can include JSX code into the markdown files that mdoc generates
  2. We can include JSX code that invokes the Javascript file produced by ScalaJS

In particular we can can modify this section to add JSX code.

My first idea was to inject something like this at the end of the generated markdown:

export const MdocDiv = () => {
  const divRef = React.useRef(null);
  React.useEffect(() => fun(divRef.current));
  
  return(<div ref={divRef}></div>);
}

<MdocDiv />

were fun is the function exported in the Javascript file created by ScalaJS.

This is the tricky part, where I am stuck, on how to make this function available here:

First approach: proper imports

Change ScalaJS settings to compile an ESModule and import the function here using raw-loader. However this does not seem to be supported

Second approach: dirty dom manipulation

This approach follows the current implementation (it mimics mdoc.js):

  1. Create a script tag pointing to the compiled js script
  2. eval the function name to load the function
  3. Use the function when the node div is ready

Because Docusaurus uses react this is particularly tricky. It could like this:

export const MdocDiv = () => {
  const script = document.createElement('script');
  script.setAttribute('src',"../assets/somePath/someFile.md.js");
  document.head.appendChild(script);
  const divRef = React.useRef(null);
  React.useEffect(() => {
   const fun = eval("mdoc_js_run0");
   fun(divRef.current);
  });
  
  return(<div ref={divRef}></div>);
}

import BrowserOnly from '@docusaurus/BrowserOnly';

<BrowserOnly>
  {() => {
    return(<MdocDiv />)
  }}
</BrowserOnly>

where BrowserOnly is needed to delay execution to when document will be available.

We then to make sure that someFIle.md.js can be accessed statically (I had to copy to another folder to be able to download it).
But this is not working yet maybe because of webpack not including it, but I am not sure. I see that:

  • No code is executed (console.logs inside the useEffect hook are never executed)
  • The script is not added

You can experiment modifying the generated markdown that is watched by Docusaurus without modifying the source of mdoc

@olafurpg
Copy link
Member

Thank you for the detailed report! One workaround for now is to use Docusaurus v1.

I'm happy to merge any PR that adds a custom code path to generate Docusaurus v2 compatible JS. The option can be read around here

(ctx.site.get("js-classpath"), ctx.site.get("js-scalac-options")) match {

We can also automatically pass the option from the sbt DocusaurusPlugin here

"js-out-prefix" -> "assets"

@vincenzobaz
Copy link
Author

I experimented a bit with alternative site generators and I found that using the new scaladoc with mdoc provides a very lightweight strategy to fix this.

You can see an example here rendered here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants