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] import names across MDX content collide #17119

Closed
ChristopherBiscardi opened this issue Aug 27, 2019 · 4 comments
Closed

Comments

@ChristopherBiscardi
Copy link
Contributor

Description

When using MDX content from nodes, the imports have the potential to collide.

Steps to reproduce

Two MDX nodes, both used to do whatever but filtered through the node system via some source (doesn't matter which source, just have to get Mdx nodes to exist). The content of both nodes must have an import whose name conflicts with the other. This can easily be achieved with default exports since they can be re-named whenever.

import Thing from 'some/module'
import Thing from 'other-place'

Expected result

Each node, when rendered gets the appropriately named component.

Actual result

Only one of the components "survives", both renderings get the same one of the two Things.

Notes

This rarely happens in practice because of the way most of the ecosystem works. It will, however, increasingly happen as more and more people use MDX because we'll start hitting edge cases that few people use.

Path forward

We basically want to associate some Mdx content with a set of imports in gatsby-plugin-mdx. We could do this by forcing the mandatory usage of id in MDXRenderer.

<MDXRenderer mdxId={node.id}>{node.body}</MDXRenderer>

I want to find a "more automatic" way of doing this. Maybe through something that I've talked about a few times that is the ability to return components from the GraphQL API such that:

{
  mdx {
    Component
  }
}

could be used directly as

<div>
  <data.mdx.Component/>
</div>

Where the Component return is really a bootstrapped MDXRenderer with the content and the id, etc. AS a side note, this would also solve an issue with GraphQL interfaces sourced from multiple locations with different primary content types (like a BlogPost with html strings and Mdx.body strings, because the usage would be to render both with Component).

Workarounds

Typically the problem arises when the culture of an eng org is such that exports are named and destructured similarly, such as

import { Button } from 'button-red'
import { Button } from 'button-blue'

Because this is typically a cultural thing, asking the team to change habits for export naming, etc is a non-starter. The imports can be imported as such inside Mdx files instead:

import * as buttonRed from 'button-red';
import * as buttonBlue from 'button-blue';

<buttonRed.Button>Click me!</buttonRed.Button>
@siddharthkp
Copy link
Contributor

siddharthkp commented Aug 28, 2019

Hi!

Thanks for taking the time to write this up. I'm following the workaround right now.

To add some context, I wanted to add the use case I'm running into, to validate/challenge some of the assumptions made:

This rarely happens in practice because of the way most of the ecosystem works. It will, however, increasingly happen as more and more people use MDX because we'll start hitting edge cases that few people use.

When you are working with user created content (example a gatsby theme), the theme itself has little control over how the mdx is authored. If there are components imported, conflicts can happen.

Typically the problem arises when the culture of an eng org is such that exports are named and destructured similarly

In my case, I'm trying to make use of the Component Story Format by the storybook team. You would see this typically in styleguides/component docs. I have seen folks handle this in different ways in modulz and docz.

Here's an example of what that looks like

import React from 'react'
import { Input } from 'your-library'

export default { title: 'Input' }

export const Simple = () => (
   <Input type="text" placeholder="Enter some text" />
)

export const Disabled = () => (
   <Input type="text" disabled={true} placeholder="Enter some text" />
)

export const WithIcon = () => (
   <Input type="text" icon="copy" value="secret-token" />
)

For your documentation, you would want to import some of these examples to showcase them.

import { Simple, WithIcon } from './input.stories'

<Simple />

## Examples

You can add icons to the input which defaults to the right side of the input.

<WithIcon />

The workaround works pretty great in this scenario, but does require some education for the user first.

import * as InputExamples from './input.stories'

<InputExamples.Simple />

## Examples

You can add icons to the input which defaults to the right side of the input.

<InputExamples.WithIcon />

@csr632
Copy link
Contributor

csr632 commented Sep 3, 2019

Related issue: #16799
I reproduce this bug with "Gatsby Default Starter":
https://github.com/csr632/reproduce-gatsby-mdx-issue

@patrickarlt
Copy link

patrickarlt commented May 6, 2020

I also created a reproduction of this in https://github.com/patrickarlt/gatsby-issue-17119-reproduction based on the MDX starter before I found this issue.

My use case is different then the above bases using Button. We are using Gatsby + MDX to build out a fairly large chunk of documentation using programatically generated pages. Some sections are repeated across multiple documents like so:

features
├── feature-a
│   ├── _faq.mdx
│   ├── _shared.mdx
│   └── index.mdx
└── feature-b
    ├── _faq.mdx
    ├── _shared.mdx
    └── index.mdx

we might share the _faq.mdx and _shared.mdx among many pages but never outside their respective feature-a and feature-b sections.

So in index.mdx an author would go:

import FAQ from "./faq.mdx";

Some Markdown content in `feature-a/index.mdx`...

<FAQ />

and

import FAQ from "./faq.mdx";

Some Markdown content in `feature-b/index.mdx`...

<FAQ />

But end up with the wrong <FAQ /> content in one file.

Right now our recommendation is to simply have authors use unique names for all imports (like below) but this definitely feels like a "gotcha" that I would expect to work.

import FeatureBFAQ from "./faq.mdx";

Some Markdown content in `feature-b/index.mdx`...

<FeatureBFAQ />

@johno
Copy link
Contributor

johno commented Jun 18, 2020

Going to close this in favor of the related umbrella issue (#25069). @pieh is currently working towards some new webpack APIs that gatsby-plugin-mdx will be able to use that will address these problems with global scope.

@johno johno closed this as completed Jun 18, 2020
@LekoArts LekoArts removed the not stale label Jul 3, 2020
LukeShu added a commit to telepresenceio/telepresence.io that referenced this issue Jun 4, 2021
They're only warnings and not errors because gatsby-plugin-mdx has broken
imports that end up being global so it doesn't *really* matter, but I like
not seeing warnings.

gatsbyjs/gatsby#17119
LukeShu added a commit to datawire/ambassador-docs that referenced this issue Jun 28, 2021
They're only warnings and not errors because gatsby-plugin-mdx has broken
imports that end up being global so it doesn't *really* matter, but I like
not seeing warnings.

gatsbyjs/gatsby#17119
LukeShu added a commit to datawire/ambassador-docs that referenced this issue Jun 28, 2021
They're only warnings and not errors because gatsby-plugin-mdx has broken
imports that end up being global so it doesn't *really* matter, but I like
not seeing warnings.

gatsbyjs/gatsby#17119
LukeShu added a commit to datawire/ambassador-docs that referenced this issue Jun 28, 2021
They're only warnings and not errors because gatsby-plugin-mdx has broken
imports that end up being global so it doesn't *really* matter, but I like
not seeing warnings.

gatsbyjs/gatsby#17119
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

7 participants