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

gatsby-plugin-mdx: remark-external-links generates invalid rel #22719

Closed
karlhorky opened this issue Apr 1, 2020 · 29 comments
Closed

gatsby-plugin-mdx: remark-external-links generates invalid rel #22719

karlhorky opened this issue Apr 1, 2020 · 29 comments
Labels
type: bug An issue or pull request relating to a bug in Gatsby

Comments

@karlhorky
Copy link
Contributor

karlhorky commented Apr 1, 2020

Description

Using remark-external-links with gatsby-plugin-mdx generates an invalid rel attribute: nofollow,noopener,noreferrer instead of nofollow noopener noreferrer, how it is supposed to be.

Usage with gatsby-plugin-mdx and remarkPlugins

Screen Shot 2020-04-01 at 18 01 47

Usage alone

Screen Shot 2020-04-01 at 17 50 16

Steps to reproduce

Add the following code to Runkit (you can use this link: https://npm.runkit.com/remark-external-links). This generates the correct rel.

var remark = require('remark')
var externalLinks = require("remark-external-links")
var html = require('remark-html')
var input = '[remark](https://github.com/remarkjs/remark)'
remark().use(externalLinks).use(html).processSync(input).toString()

Try out my gatsby-plugin-mdx sandbox at the link below. This generates an invalid rel:

gatsby-plugin-mdx Sandbox: https://codesandbox.io/s/empty-cdn-u31qb

Expected result

The correct rel should be generated.

Actual result

An invalid rel is generated.

Environment

System:
    OS: Linux 4.19 Debian GNU/Linux 10 (buster) 10 (buster)
    CPU: (12) x64 Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
    Shell: 5.0.3 - /bin/bash
  Binaries:
    Node: 10.18.1 - /tmp/yarn--1585757330032-0.1053501887919337/node
    Yarn: 1.21.1 - /tmp/yarn--1585757330032-0.1053501887919337/yarn
    npm: 6.13.4 - /usr/local/bin/npm
  Languages:
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    gatsby: 2.20.9 => 2.20.9
    gatsby-plugin-mdx: ^1.0.23 => 1.0.23

cc @ChristopherBiscardi

@karlhorky karlhorky added the type: bug An issue or pull request relating to a bug in Gatsby label Apr 1, 2020
@pieh
Copy link
Contributor

pieh commented Apr 2, 2020

Preliminary check on this:

The remark plugin does set rel "prop"/"attribute" to array of things ( https://github.com/remarkjs/remark-external-links/blob/0ba573ae3630a3f2f377d07b4295dfb964b24e8a/index.js#L54 )

I guess it's the AST "stringifier" that is different for mdx here (it joins props with commas , and not spaces)

Will have to dig a bit into gatsby-plugin-mdx to where this is actually happening - is it in gatsby plugin or is it in mdx packages/dependencies

@pieh
Copy link
Contributor

pieh commented Apr 2, 2020

Interestingly the code that MDX produces is this:

/* @jsx mdx */
import { mdx } from '@mdx-js/react';
/* @jsx mdx */
import DefaultLayout from "/Users/misiek/test/i22719/src/components/Layout.js"
export const _frontmatter = {};
const makeShortcode = name => function MDXDefaultShortcode(props) {
  console.warn("Component " + name + " was not imported, exported, or provided by MDXProvider as global scope")
  return <div {...props}/>
};

const layoutProps = {
  _frontmatter
};
const MDXLayout = DefaultLayout
export default function MDXContent({
  components,
  ...props
}) {
  return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">


    <h1>{`Hello, world!`}</h1>
    <p><a parentName="p" {...{
        "href": "https://github.com/remarkjs/remark",
        "target": "_blank",
        "rel": ["nofollow", "noopener", "noreferrer"]
      }}>{`remark`}</a></p>

    </MDXLayout>;
}

;
MDXContent.isMDXComponent = true;

So it didn't do anything to rel props - it kept it as is, and it looks like it's React that insert , between items?

remark-html does make use of this list https://github.com/wooorm/property-information/blob/ac3452348fc694ec8bb2d3f0080b25a9dfa7f8e2/lib/html.js#L206 to know that rel need to be space separated values. I don't know how much work it would need to make mdx handle cases like that similarly, but perhaps as workaround you could fork or vendor that remark plugin and make following change (just make it a string up front):

- props.rel = (rel || defaultRel).concat()
+ props.rel = (rel || defaultRel).join(` `)

@pieh pieh added the topic: MDX label Apr 2, 2020
@github-actions
Copy link

Hiya!

This issue has gone quiet. Spooky quiet. 👻

We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.
If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!
As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contribute for more information about opening PRs, triaging issues, and contributing!

Thanks for being a part of the Gatsby community! 💪💜

@github-actions github-actions bot added the stale? Issue that may be closed soon due to the original author not responding any more. label Apr 23, 2020
@karlhorky karlhorky added not stale and removed stale? Issue that may be closed soon due to the original author not responding any more. labels Apr 23, 2020
@karlhorky
Copy link
Contributor Author

karlhorky commented Apr 23, 2020

@wooorm or @johno, you wouldn't happen to be able to comment on this, would you?

Is this something to fix in gatsby-plugin-mdx or does this belong as an issue in another project?

@wooorm
Copy link

wooorm commented Apr 23, 2020

Think it's something in mdx. Hast uses arrays for attributes with lists, mdx naively assumes those are all space separated (they often are, but this one is comma separated?)

@wooorm
Copy link

wooorm commented Apr 23, 2020

Or: mdx dos not support space separated lists at all 🤔

@karlhorky
Copy link
Contributor Author

Workaround

Use gatsby-remark-external-links instead of remark-external-links, under the gatsbyRemarkPlugins options key of gatsby-plugin-mdx:

// In your gatsby-config.js
plugins: [
  {
    resolve: `gatsby-plugin-mdx`,
    options: {
      gatsbyRemarkPlugins: [
        {
          resolve: `gatsby-remark-external-links`,
        },
      ],
    },
  },
],

@karlhorky
Copy link
Contributor Author

I have opened a pull request warning of this behavior (#23505) in the gatsby-plugin-mdx readme.

@wooorm
Copy link

wooorm commented Apr 26, 2020

Hmm, maybe it’s a good idea instead to fix it in MDX?
Also, why does gatsby-remark-external-links work? It’s a couple lines that essentially packs the normal remark plugin, and passes the same default rel: https://github.com/JLongley/gatsby-remark-external-links/blob/dc1bc39849a5ecd23e24ca95e954dec6cef8ee48/src/index.js. I don’t see why it would work.

@pieh
Copy link
Contributor

pieh commented Apr 28, 2020

It's bit weird - seems like github repository does not match to what is released on npm. On npm that package is using string and not array ( https://unpkg.com/browse/gatsby-remark-external-links@0.0.4/index.js ) and I guess that's why it actually "works"

@karlhorky
Copy link
Contributor Author

karlhorky commented Apr 29, 2020

Interesting, seems like JLongley/gatsby-remark-external-links#6 introduced remark-external-links.

I've asked them to publish, would be interesting to see if it still works afterwards.

@wooorm
Copy link

wooorm commented Apr 29, 2020

It won’t, #22719 (comment), it’s a bug in MDX

@karlhorky
Copy link
Contributor Author

@wooorm If you're certain of this, I'm happy to open an issue in mdx-js/mdx with the details that you can provide. I got the impression that you weren't certain what exactly the issue could be and that it needs some further investigation. That's the only reason I haven't reported yet.

So if you can provide me with the technical details of a reportable issue, I will do the reporting :)

@wooorm
Copy link

wooorm commented Apr 29, 2020

I wasn’t 100% that it was MDX at first, but now I definitely am. I forgot about it, but you reported mdx-js/mdx#715 which lead to mdx-js/mdx#716. Problematic code is here: https://github.com/mdx-js/mdx/blob/9b4f192afd3255ac48780934dd848806912bff44/packages/mdx/mdx-hast-to-jsx.js#L19-L45.

The proper solution will be in MDX2, which I’m working on now!

@wooorm
Copy link

wooorm commented Apr 29, 2020

Here’s the fix on my PR for MDX 2

@karlhorky
Copy link
Contributor Author

karlhorky commented Apr 30, 2020

Ah right, cool! Yeah I forgot about this too 😅

Thanks for the update! If you would guide me, I'd be happy to add this as a test case to your PR.

I guess that this PR can be closed when mdx-js/mdx#1039 lands.

I've also updated #23505 to note that this applies to versions of MDX before v2.

@wooorm
Copy link

wooorm commented May 1, 2020

That PR is pretty big and hard to read already, so I think a separate PR when it lands with more integration tests is a good idea, and a very welcome addition! (I’d like to do more of that too, e.g., SVG/MathML and more integration tests!)

I’m heavily biased of course, but I think the quality of gatsby-remark plugins is sometimes lacking, and I’d want to push towards cooperation instead of separation. Some combination plugins of course make lots of sense (if the plugin is really integrating with Gatsby), but “wrapper” or “copy-paste” plugins leads to the same problems grunt/gulp had, where plugins are out of date leading to issues that are already solved (such as this one), and plugins that implement something in gatsby-remark where it could’ve been a remark plugin too, leads to doing the same things twice in silos.

So, while in this case technically a solution for this issue, I’m not sure pointing people to an unmaintained wrapper plugin at 0.0.4 with other issues is a great solution either.

@karlhorky
Copy link
Contributor Author

a separate PR when it lands with more integration tests is a good idea, and a very welcome addition!

Alright sounds good, let's do it then 👍

the quality of gatsby-remark plugins is sometimes lacking

I’d want to push towards cooperation instead of separation

“wrapper” or “copy-paste” plugins leads to the same problems grunt/gulp had, where plugins are out of date leading to issues that are already solved

...leads to doing the same things twice in silos

Agree on all points, would be nice if the API of Gatsby plugins such as gatsby-plugin-mdx nudged developers towards this - maybe with a different way to hook remark plugins into Gatsby (instead of writing a new plugin).

I’m not sure pointing people to an unmaintained wrapper plugin at 0.0.4 with other issues is a great solution either

Agree, it's not a great solution. But having it break with no recourse for those affected is even worse.

I've experienced a lot of pain and incompatibility in Gatsby already, and I feel strongly about doing my part so that users don't have to go through the same grief that I did.

Again, I totally prefer the method of pushing towards more correct and simple solutions, but if those solutions do not yet exist (or if a project is stuck on an old version for some reason), then it's important to have a way of getting around it until the project can upgrade.

@karlhorky
Copy link
Contributor Author

karlhorky commented May 1, 2020

Just thinking, maybe there's a way to get correctness now and close this issue after all - maybe mdx would accept a PR for v1 for a rel fix similar to my mdx-js/mdx#715 pull request?

That would allow gatsby-plugin-mdx to upgrade to this version without a breaking change and close this issue. Would also be ok to close / revert #23505 at that time too I suppose!

@wooorm
Copy link

wooorm commented May 1, 2020

That should be possible! I’m sure John would be happy to cut a release early for that? Either adding the prop to the list of exceptions, or using hast-to-hyperscript like so to solve everything! (which looks a bit ugly but I wanted to do cleaning up later)

@karlhorky
Copy link
Contributor Author

Looking at your comments in mdx-js/mdx#715 and considering pulling in property-information for this - specifically, the properties that are spaceSeparated in this file: lib/html.js

Then I can create the shouldBeStrings array from that list pretty easily.

Any downsides with this? If not, I'll give it a shot.

@wooorm
Copy link

wooorm commented May 1, 2020

I’d suggest using prop info instead of hardcoding the list for maintainability’s sake, property information is relatively frequently updated with new HTML attributes.

@wooorm
Copy link

wooorm commented May 1, 2020

But as the PR will land soonish, hardcoding for now is fine!

@karlhorky
Copy link
Contributor Author

karlhorky commented May 1, 2020

Ok, open! mdx-js/mdx#1048

Edit: Great, that's been merged now, so as soon as it's published, gatsby-plugin-mdx can have its version bumped and hopefully everything just works!

Then this issue can be closed 🎉

Edit 2: PR in Gatsby open! #23700

@karlhorky
Copy link
Contributor Author

Ok, this has been resolved (CodeSandbox: https://codesandbox.io/s/serverless-snowflake-yo8mt?file=/package.json):

Screen Shot 2020-05-06 at 13 50 52

I've also closed #23505.

Thanks @pieh and @wooorm !

@karlhorky
Copy link
Contributor Author

I've also opened an issue in gatsby-remark-external-links to be removed from Gatsby Plugins and/or marked as deprecated:

JLongley/gatsby-remark-external-links#22

@karlhorky
Copy link
Contributor Author

karlhorky commented May 15, 2020

Ah it looks like publishing additional "wrapper" npm packages to wrap every remark plugin is the recommended way of doing things 😞 At least in 2018 it was like this.

References:

So @wooorm I guess the process of writing extra wrapper packages you described the downsides about in #22719 (comment) is actually recommended 😞

@wooorm
Copy link

wooorm commented May 15, 2020

Ohh. I think that’s unfortunate. I see some upsides in doing that, but mostly short term, I feel like in the long run it would be better to not do wrappers.

@karlhorky
Copy link
Contributor Author

Yes, agree it's unfortunate.

Wonder if the Gatsby team would be open to changing this for Remark plugins (the wrapper bit can also be absorbed into gatsby-transformer-remark, I guess?).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

No branches or pull requests

4 participants