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

MDX compilation error: Adjacent JSX elements must be wrapped #10367

Closed
RaviDesai opened this issue Apr 9, 2020 · 11 comments
Closed

MDX compilation error: Adjacent JSX elements must be wrapped #10367

RaviDesai opened this issue Apr 9, 2020 · 11 comments

Comments

@RaviDesai
Copy link

Describe the bug
Trying to compile any component.stories.mdx file in 5.3.18 fails with the following error in build-storybook:

WARN ./src/components/sanitize/sanitize.stories.mdx
WARN Module build failed (from ./node_modules/@mdx-js/loader/index.js):
WARN SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (2:0)
WARN     at Object._raise (/Users/ravi/GitHub/ce-web-components/node_modules/@babel/parser/lib/index.js:723:17)
WARN     at Object.raiseWithData (/Users/ravi/GitHub/ce-web-components/node_modules/@babel/parser/lib/index.js:716:17)

<<< elided a bunch of the stack trace >>>

To Reproduce
Steps to reproduce the behavior:

  1. Update my build environment as specified here: https://github.com/storybookjs/storybook/blob/next/addons/docs/README.md#installation
  2. Add a very simple MDX story to one of my components
  3. run ./node_module/.bin/build-storybook

Expected behavior
The MDX story is added to the storybook

Code snippets
My main.js looks like this:

module.exports = {
  addons: [
    "@storybook/addon-notes/register",
    "@storybook/addon-knobs/register",
    "@storybook/addon-actions/register",
    "@storybook/addon-docs/register"
  ],
  stories: ["../src/components/**/*.stories.*"]
};

My webpack.js looks like this:

const fs = require("fs");
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const WriteFilePlugin = require("write-file-webpack-plugin");
const OUTPUT_DIR = path.resolve(__dirname, "../dist");
const PROJECT_NAME = "ce-web-components";
const createCompiler = require("@storybook/addon-docs/mdx-compiler-plugin");

module.exports = async ({ config }) => {
  fs.readdirSync(path.join(OUTPUT_DIR, PROJECT_NAME)).map(file => {
    try {
      const jsFilePath = path.join(
        OUTPUT_DIR,
        `collection/components/${file}/${file}.js`
      );
      if (fs.existsSync(jsFilePath)) {
        config.entry.push(jsFilePath);
      }
    } catch (err) {
      console.error(err);
    }

    try {
      const cssFilePath = path.join(
        OUTPUT_DIR,
        `collection/components/${file}/${file}.css`
      );
      if (fs.existsSync(cssFilePath)) {
        config.entry.push(cssFilePath);
      }
    } catch (err) {
      console.error(err);
    }
  });

  config.plugins.push(
    new CopyPlugin([
      {
        from: "**/*",
        to: "./",
        context: OUTPUT_DIR
      }
    ])
  );

  config.plugins.push(new WriteFilePlugin());

  config.module.rules.push({
    test: /\.(stories|story)\.mdx$/,
    use: [
      {
        loader: "babel-loader",
        // may or may not need this line depending on your app's setup
        options: {
          plugins: ["@babel/plugin-transform-react-jsx"]
        }
      },
      {
        loader: "@mdx-js/loader",
        options: {
          compilers: [createCompiler({})]
        }
      }
    ]
  });
  config.module.rules.push({
    test: /\.(stories|story)\.[tj]sx?$/,
    loader: require.resolve("@storybook/source-loader"),
    exclude: [/node_modules/],
    enforce: "pre"
  });

  return config;
};

I have a .babelrc that looks like this:

{
  "plugins": [
    "@babel/plugin-syntax-jsx",
    [
      "@babel/plugin-transform-react-jsx",
      {
        "pragma": "h"
      }
    ]
  ]
}

The story I'm compiling - sanitize.stories.mdx looks like this:

import { Meta, Story, Preview } from "@storybook/addon-docs/blocks";
<Meta title="MDX/Sanitize" />
<Preview>
  <Story name="sanitize header">
    <ce-sanitize html="<h1>Header</h1>"></ce-sanitize>
  </Story>
</Preview>

System:
Environment Info:

System:
OS: macOS 10.15.4
CPU: (8) x64 Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz
Binaries:
Node: 10.17.0 - /usr/local/bin/node
Yarn: 1.2.1 - /usr/local/bin/yarn
npm: 6.11.3 - /usr/local/bin/npm
Browsers:
Chrome: 80.0.3987.163
Firefox: 72.0.1
Safari: 13.1
npmPackages:
@storybook/addon-actions: ^5.3.18 => 5.3.18
@storybook/addon-docs: ^5.3.18 => 5.3.18
@storybook/addon-events: ^5.3.18 => 5.3.18
@storybook/addon-knobs: ^5.3.18 => 5.3.18
@storybook/addon-notes: ^5.3.18 => 5.3.18
@storybook/addon-viewport: ^5.3.18 => 5.3.18
@storybook/html: ^5.3.18 => 5.3.18
@storybook/web-components: ^5.3.18 => 5.3.18

Additional context
I know JSX files will produce this error since you always need an outer wrapper for HTML elements with those. But that limitation makes no sense for MDX files. Is there a configuration I'm missing somewhere to allow for this?

@shilman
Copy link
Member

shilman commented Apr 11, 2020

I think you just need to add newlines:

import { Meta, Story, Preview } from "@storybook/addon-docs/blocks";

<Meta title="MDX/Sanitize" />

<Preview>
  <Story name="sanitize header">
    <ce-sanitize html="<h1>Header</h1>"></ce-sanitize>
  </Story>
</Preview>

@RaviDesai
Copy link
Author

So the blank lines got me a little further (I had to turn off FormatOnSave in my editor to add them, but whatever). I now have the following .mdx:

import { Meta, Story, Preview } from "@storybook/addon-docs/blocks";

<Meta title="MDX/Sanitize" />

<Story name="MDX sanitize header">
    <ce-sanitize html="<h1>Header</h1>"></ce-sanitize>
</Story>

that produces the following error:

Expecting an HTML snippet or DOM node from the story: "MDX sanitize header" of "MDX/Sanitize".
Did you forget to return the HTML snippet from the story?
Use "() => <your snippet or node>" or when defining the story.

@shilman
Copy link
Member

shilman commented Apr 12, 2020

Aha, I didn't see that it's web-components. You need to put quotes around your WC code. Examples: https://raw.githubusercontent.com/storybookjs/storybook/next/examples/web-components-kitchen-sink/stories/addon-docs.stories.mdx

@RaviDesai
Copy link
Author

Weirdly, attempting to use lit-html's html directive resulted in a plethora of new errors. However, just returning the HTML needed for my embedded stencil component as a string worked just fine. The component properly instantiated, and functioned normally. Thanks for working with me on this. The blank line problem was bizarre and very frustrating, but I understand you are still working out the details. Feel free to close this, I can (more or less) get MDX files working to a satisfactory degree.

@shilman
Copy link
Member

shilman commented Apr 12, 2020

I think the blank like thing is a "feature" of MDX itself and nothing todo with storybook's implementation of it, but haven't confirmed. Would be nice if we could give better error messages. At any rate, glad you got it working!

@RaviDesai
Copy link
Author

Thanks. So after a little playing, I can return a node from document.createElement, or I can return a string containing the component I need. But I cannot return something that requires JSX compilation. As far as function, as long as I can use document.createElement, I'm OK because I can add event listeners and the like in my story.

But the ability to use JSX would be SO MUCH BETTER. I can use JSX in my CSF / storiesOf stories by having an import { h } from "jsx.dom" at the top of my stories files (it's a little bit of a hack, but it works great). Do you know if there is any chance of seeing JSX support in the future?

@shilman
Copy link
Member

shilman commented Apr 12, 2020

@RaviDesai can you elaborate and share examples? it will help me understand/answer your question. thanks!

@stale
Copy link

stale bot commented May 4, 2020

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

@stale stale bot added the inactive label May 4, 2020
@stale
Copy link

stale bot commented Jun 3, 2020

Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

@stale stale bot closed this as completed Jun 3, 2020
@coler-j
Copy link

coler-j commented Oct 20, 2022

The example at docs.stories.mdx is a dead link :(

@yairEO
Copy link
Contributor

yairEO commented Nov 30, 2022

I am seeing now same problem in VSCODE after following this guide:

image

I know this is not related to storybook probably, but only putting it here for others to know this issue exists (as of "now")

Update (with fix):

After digging around for hours, (reading countless random Github issues and Stackoverflow pages) I've landed on the correct Github discussion which enlightened me.

I have installed eslint-plugin-mdx and had followed the configuration guide, but the guide did not say the most important thing, which is that since eslint is acting on both all js/jsx/mdx files, it will the same rules to all, and that is unwanted.

So, in eslintrc file, one must use the overrides property and define all the js/jsx rules specifically for those file extensions, and and mdx apply this override:

{
      "files": ["*.mdx"],
      "extends": "plugin:mdx/recommended"
}

Then Eslint will stop bother you with JSX-specific issues for mdx files.

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

No branches or pull requests

4 participants