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

Plugins are not working #188

Closed
mucsi96 opened this issue Jun 23, 2018 · 11 comments · Fixed by #305
Closed

Plugins are not working #188

mucsi96 opened this issue Jun 23, 2018 · 11 comments · Fixed by #305
Labels
help wanted 🙏 This could use your insight or help

Comments

@mucsi96
Copy link

mucsi96 commented Jun 23, 2018

Thanks for creating this amazing package! This is a really awesome idea.

I would like to ask for some help with plugins. For some reason the don't do anything.

My code

import React from "react";
import { render } from "react-dom";
const ReactMarkdown = require("react-markdown");
const toc = require("remark-toc");

const input = `
# Alpha

## Table of Contents

## Bravo

### Charlie

## Delta
`;

const App = () => <ReactMarkdown source={input} plugins={[toc]} />;

render(<App />, document.getElementById("root"));

codesandbox: https://codesandbox.io/s/340pq1r2l6

The output:

<div id="root">
    <div>
        <h1>Alpha</h1>
        <h2>Table of Contents</h2>
        <h2>Bravo</h2>
        <h3>Charlie</h3>
        <h2>Delta</h2>
    </div>
</div>

The table of contents is not created also slugs are not added to headings.

@miklschmidt
Copy link

Can't get remark-autolink-headings to work either. The resulting AST transform function in the plugin is never called.

@shcheklein
Copy link

shcheklein commented Jul 13, 2018

So, turned out this version support only parser plugins. Basically, if you take a look at this diagram only first stage (namely, parse()) is called during the processing and most of the react-* are actually transformers that are applied in the second run() stage.

Probably, it could be fixed by just running run() in the ReactMarkdown function itself after initial parse call. I haven't tried that.

For me the workaround that did the job was to use astPlugins parameter (which is not documented for some reason, may be even a good one). It takes plugins in a very similar format:

import linker from '../src/Documentation/remark-linker'
...
astPlugins={[linker()]}

Note, that function call is made to actually get the transformer from the plugin description.

I'm not sure this is 100% compatible with all the plugins. In my case I wrote the plugin I needed for the dvc documentation site:

function linker() {

  function transformer(tree) {
    visit(tree, 'inlineCode', function(node, index, parent) {
      if (parent.type !== 'link' && /dvc [a-z-.]+/.test(node.value)) {
        parent.children[index] = {
          type: 'link',
          url: 'https://dvc.org/doc/commands-reference/' + node.value.split(' ')[1],
          children: [node],
          position: node.position
        };
      }
    })
    return tree
  }

  return transformer
}

sloria added a commit to sloria/jrnl-render that referenced this issue Jul 26, 2018
react-markdown doesn't support transformer plugins
(remarkjs/react-markdown#188), so we can't use
remark-ping with it. My hand-coded @tag plugin was
buggy--better to use remark-ping
@sloria
Copy link

sloria commented Aug 3, 2018

@rexxars Any thoughts on a solution or workaround for this? @shcheklein 's analysis is correct--transformer plugins do not work with react-markdown.

I ran into this while trying to integrate remark-ping for @mention syntax. It doesn't work with react-markdown, so I ended up using remark/rehype directly.

// render-markdown.js
import remark from "remark";
import remarkPing from "remark-ping";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import rehypeHighlight from "rehype-highlight";

export default function renderMarkdown(source) {
  const plugins = [
    [
      remarkPing,
      {
        //..config...
      },
    ],
    remarkRehype,
    rehypeStringify,
    rehypeHighlight
  ];
  const remarkInst = remark().use(plugins);
  return new Promise((resolve, reject) => {
    remarkInst.process(source, (err, rendered) => {
      err ? reject(err) : resolve(rendered.contents);
    });
  });
}
// Markdown.jsx
import React from "react";
import t from "prop-types";
import renderMarkdown from "./render-markdown";

export default class Markdown extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rendered: ""
    };
  }
  componentDidMount() {
    const { source } = this.props;
    renderMarkdown(source).then(rendered => {
      this.setState({ rendered });
    });
  }
  render() {
    const { source, ...rest } = this.props;
    return (
      <div
        dangerouslySetInnerHTML={{ __html: this.state.rendered }}
        {...rest}
      />
    );
  }
}
Markdown.propTypes = {
  source: t.string.isRequired
};

This really isn't ideal, if only for the impact on bundle size (rehype-highlight alone ends up adding 190 kb to the min/gzip bundle).

@rexxars
Copy link
Collaborator

rexxars commented Aug 9, 2018

The bundle size issue is the reason why I wanted to not include the full remark suite. If we are able to come up with a solution without adding too many bytes to the mix, that would be great. I unfortunately don't have time to dig into this right now, but would be very happy if someone else were to take a stab at it.

@rexxars rexxars added the help wanted 🙏 This could use your insight or help label Oct 2, 2018
@frankieali
Copy link
Contributor

frankieali commented May 10, 2019

I needed to run a plugin for my react project so I dug into this issue a bit. @shcheklein was on the right track. I added the parser.runSync() function to get plugin transforms working. The other issue I came across was that transform generated nodes did not have position which would cause astToReact() to throw an error. I patched that by giving nodes' their parent's positioning. Not sure if that's the best idea, but it got things working. My fork is available here: https://github.com/frankieali/react-markdown. I updated the demo as well to show some third party plugins (remark-behead,remark-toc,remark-sectionize,remark-captions, and remark-linkify-regex) at work. I'll make a PR if you think this works.
My fix adds nothing to the bundle size (excepting the demo, which does not have to be PR'ed in).

@sunknudsen
Copy link

Anyone knows why the remark-slug plugin doesn’t work? According to the above PR, looks like it should... See #397

@bel0v
Copy link

bel0v commented Mar 12, 2020

Did anyone manage to get remark-autolink-headings plugin working?

@wchargin
Copy link

wchargin commented Jun 29, 2020

I’m also having trouble getting remark-external-links working. This is
important because it works around a security hole; the hole is properly
fixed by #350, but that PR hasn’t been merged.

Repro: https://codesandbox.io/s/silly-cherry-bznd3?file=/src/index.js

Note that the pre-rendered output properly includes both target and
rel attributes, whereas the react-markdown output has neither
attribute, suggesting that the plugin is not being called at all. Yet no
error is shown in the UI or console.

Repro code, for posterity
import React from "react"; // v16.13.1
import {render} from "react-dom"; // v16.13.1
import ReactMarkdown from "react-markdown"; // v4.3.1
import remark from "remark"; // v12.0.0
import externalLinks from "remark-external-links"; // v6.1.0
import html from "remark-html"; // v11.0.2

const input = "Here is [an example link](https://example.com).";

async function main() {
  const rendered = await new Promise((resolve, reject) => {
    remark()
      .use(externalLinks)
      .use(html)
      .process(input, (err, file) => {
        if (err != null) {
          reject(err);
        }
        resolve(file);
      });
  });
  const App = () => (
    <div>
      <p>Pre-rendered:</p>
      <pre>
        <code>{rendered}</code>
      </pre>
      <p>
        With <code>ReactMarkdown</code>:
      </p>
      <ReactMarkdown source={input} plugins={[externalLinks]} />
    </div>
  );
  render(<App />, document.getElementById("root"));
}

main();

Perhaps this issue should be reopened?

@nahumzs
Copy link

nahumzs commented Oct 10, 2020

@shcheklein I'm trying to follow your example, I'm pretty new in AST can you point me out from where you are importing the visit function in your code?

    visit(tree, 'inlineCode', function(node, index, parent) {

🙏

@shcheklein
Copy link

@nahumzs hi! sure here is the link - https://github.com/iterative/dvc.org/blob/7f88227d131c5fcf8eead8d7d6c62876152fb395/src/Documentation/Markdown/utils/remark-linker.js (we've updated the plugin since then). I'll edit the existing comment.

@ChristianMurphy
Copy link
Member

Many of these are related to #384, in that they depend on hProperties being supported to add HTML attributes, this will be resolved by #428

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted 🙏 This could use your insight or help
Development

Successfully merging a pull request may close this issue.