react-styleguidist: Examples not displayed when using react-scripts@5

Current behavior

Examples in .md files is not displayed when using react-styleguidist with react-scripts@5.

To reproduce

https://github.com/malcolm-kee/react-styleguidist-cra5-md-bug

Expected behavior

The examples should be displayed.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 22
  • Comments: 15

Commits related to this issue

Most upvoted comments

Hello Any plans to fix this issue? Still happens on v11.2.0 for me

Same for me

Problem

I debugged this a bit and the problem here seems to be, the way that Webpack 5 is handling assets. It has a new Asset Module mechanism, which determines how webpack will bundle/treat an import. For Markdown files this seems to be asset/resource by default, i.e. it will “copy” the file to a hashed location and make the require return the URL to it.

This is problematic, since react-styleguidist actually specifies a custom inline loader (see getExamples.ts#31 and examples-loader.ts). This loader will return JavaScript, which is now handled by Webpack wrongly as an asset. The solution would be to inform webpack to treat that result as JavaScript via the asset type javascript/auto (see Workaround below).

Also it seems there is a second problem, that in the JavaScript code, that the examples-loader generate absolute paths are used (see examples-loader.ts#19-20). Those seem to no longer resolve properly and will cause those two modules (requireInRuntime and evalInContext) to not resolve properly. It seems relative paths would work fine (see workaround below).

Workaround

Tested with react-styleguidist@11.1.7

To workaround this, you can put the following into your styleguide.config.js:

const webpack = require('webpack');

const webpackConfig = {
  module: {
    rules: [
      {
        test: /\.examples\.md$/, // see comment below!
        type: 'javascript/auto', // Tell webpack to interpret the result from examples-loader as JavaScript
      },
    ],
  },
  plugins: [
    // Rewrites the absolute paths to those two files into relative paths
    new webpack.NormalModuleReplacementPlugin(
      /react-styleguidist\/lib\/loaders\/utils\/client\/requireInRuntime$/,
      'react-styleguidist/lib/loaders/utils/client/requireInRuntime'
    ),
    new webpack.NormalModuleReplacementPlugin(
      /react-styleguidist\/lib\/loaders\/utils\/client\/evalInContext$/,
      'react-styleguidist/lib/loaders/utils/client/evalInContext'
    ),
  ],
};

module.exports = {
  webpackConfig,
  // The rest of your styleguidist config
};

Couple of notes to this workaround:

  • If you already specify a webpackConfig in your styleguide.config.js (e.g. because you are using craco and want to inject its webpack config) make sure to properly merge the rules and plugins into that config.
  • All my styleguide examples end on .examples.md (using the getExampleFilename configuration). You must make sure to write a test that will match your example markdown files (and also not accidentally other markdown files if you have them in your code). If you can’t achieve this with the test option, in the worst case you’d need to use the include and exclude option to include and exclude individual files.

For those struggling to hook up existing webpack config with the workaround, adding the below to the styleguide.config.js worked for me. It’;s not an ideal solution but works for me while waiting for this to get resolved on the styleguidist end.

   dangerouslyUpdateWebpackConfig(config) { 
     config.module.rules.push({
        test: /.\.md$/,
        type: "javascript/auto"
      });
      config.plugins.push(
        new webpack.NormalModuleReplacementPlugin(
          /react-styleguidist\/lib\/loaders\/utils\/client\/requireInRuntime$/,
          "react-styleguidist/lib/loaders/utils/client/requireInRuntime"
        )
      );
      config.plugins.push(
        new webpack.NormalModuleReplacementPlugin(
          /react-styleguidist\/lib\/loaders\/utils\/client\/evalInContext$/,
          "react-styleguidist/lib/loaders/utils/client/evalInContext"
        )
      );
      return config;
    },
   ...the rest of your config

Thanks @timroes for this ❤️

It took me some time to make this work with Typescript and Tailwind CSS but it was totally worth it!

In case someone is interested here is a gist for that.

For those struggling to hook up existing webpack config with the workaround, adding the below to the styleguide.config.js worked for me. It’;s not an ideal solution but works for me while waiting for this to get resolved on the styleguidist end.

   dangerouslyUpdateWebpackConfig(config) { 
     config.module.rules.push({
        test: /.\.md$/,
        type: "javascript/auto"
      });
      config.plugins.push(
        new webpack.NormalModuleReplacementPlugin(
          /react-styleguidist\/lib\/loaders\/utils\/client\/requireInRuntime$/,
          "react-styleguidist/lib/loaders/utils/client/requireInRuntime"
        )
      );
      config.plugins.push(
        new webpack.NormalModuleReplacementPlugin(
          /react-styleguidist\/lib\/loaders\/utils\/client\/evalInContext$/,
          "react-styleguidist/lib/loaders/utils/client/evalInContext"
        )
      );
      return config;
    },
   ...the rest of your config

Thank you for this; very helpful!

But, two remarks:

  • Your comment ...the rest of your config is not 100% obvious. For anyone who is puzzled here: (1) I needed to add const webpack = require("webpack") at the head of the file. (2) This new code goes inside the module.exports = { ... }, followed by rest of the existing content.
  • This fixes the problem of examples not displaying after updating from react-scripts 4.0.3 to 5.0.1. But, even though the content is being served correctly, I still got a FAIL Failed to compile error, followed by many lines of “require stack” and other details. Fixing each just required carefully searching the messages for which dependencies were causing each problem, updating them, and also deleting and rebuilding node_modules.

Hey there. By ‘the rest of your config’ I am referring to any other configuration you use from here. Things like sections, styles etc. You’re right, you do need to import webpack, since you are referring to it in the config overrides. You can see more examples of config for react-styleguidist in the gist that @nebomilic posted above 😃