Has anybody successfully integrated storybook docs with gatsby? - reactjs

In my Gatsby themes project, I am trying to integrate the storybook using .mdx format.
But the webpack of storybook is not able to convert the .mdx files.
It keeps throwing different errors.
I have tried using with storybook presets and without presets, but there was no solution.
Card Component
import React from 'react';
const Card = () => {
return (
<div className="laptopUp:max-w-lg max-w-sm mx-auto bg-white shadow-lg rounded-lg overflow-hidden">
<div className="sm:flex sm:items-center px-6 py-4">
<img
className="block mx-auto sm:mx-0 sm:flex-shrink-0 h-16 sm:h-24 rounded-full"
src="https://randomuser.me/api/portraits/women/17.jpg"
alt="Woman's Face"
/>
<div className="mt-4 sm:mt-0 sm:ml-4 text-center sm:text-left">
<p className="text-xl leading-tight">Erin Lindford</p>
<p className="text-sm leading-tight text-gray-600">
Customer Support Specialst
</p>
<div className="mt-4">
<button className="text-purple-500 hover:text-white hover:bg-purple-500 border border-purple-500 text-xs font-semibold rounded-full px-4 py-1 leading-normal">
Message
</button>
</div>
</div>
</div>
</div>
);
};
export {Card};
Card Story:
import { Meta, Story, Preview } from '#storybook/addon-docs/blocks';
import {Card} from './card.js';
<Meta title="MDX|Card" component={Card} />
With `MDX` we can define a story for `Card` right in the middle of our
markdown documentation.
<Preview>
<Story name="Demo Card">
<Card />
</Story>
</Preview>
.storybook/config.js
import { configure, addParameters } from '#storybook/react';
import { DocsPage, DocsContainer } from '#storybook/addon-docs/blocks';
import { action } from '#storybook/addon-actions';
import '../main.css';
addParameters({
docs: {
container: DocsContainer,
page: DocsPage,
prepareForInline: (storyFn) => storyFn(),
},
});
// Gatsby's Link overrides:
// Gatsby defines a global called ___loader to prevent its method calls from creating console errors you override it here
global.___loader = {
enqueue: () => {},
hovering: () => {}
};
// Gatsby internal mocking to prevent unnecessary errors in storybook testing environment
global.__PATH_PREFIX__ = '';
// This is to utilized to override the window.___navigate method Gatsby defines and uses to report what path a Link would be taking us to if it wasn't inside a storybook
window.___navigate = pathname => {
action('NavigateTo:')(pathname);
};
configure(require.context('../src', true, /\.stories\.(js|mdx)$/), module);
My webpack config:
// module.exports = ({ config, mode }) => {
// // Transpile Gatsby module because Gastby includes un-transpiled ES6 code.
// config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
// // use installed babel-loader which is v8.0-beta (which is meant to work with #babel/core#7)
// config.module.rules[0].use[0].loader = require.resolve('babel-loader')
// // The next two lines should always reflect the config in jest-preprocess.js until there is a way for Gatsby to expose an internal webpack.config
// // use #babel/preset-react for JSX and env (instead of staged presets)
// config.module.rules[0].use[0].options.presets = [
// require.resolve('#babel/preset-react'),
// require.resolve('#babel/preset-env'),
// ]
// // use #babel/plugin-proposal-class-properties for class arrow functions
// config.module.rules[0].use[0].options.plugins = [
// require.resolve('#babel/plugin-proposal-class-properties'),
// ]
// // https://github.com/gatsbyjs/gatsby/issues/10662:
// // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
// config.resolve.mainFields = ["browser", "module", "main"]
// return config
// }
/* eslint-disable no-param-reassign */
const path = require('path')
const webpack = require('webpack')
const createCompiler = require('#storybook/addon-docs/mdx-compiler-plugin');
// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
const isProduction = mode
// Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
// use installed babel-loader which is v8.0-beta (which is meant to work with #babel/core#7)
config.module.rules[0].use[0].loader = require.resolve('babel-loader')
// use #babel/preset-react for JSX and env (instead of staged presets)
config.module.rules[0].use[0].options.presets = [
require.resolve('#babel/preset-react'),
require.resolve('#babel/preset-env')
]
// use #babel/plugin-proposal-class-properties for class arrow functions
config.module.rules[0].use[0].options.plugins = [
require.resolve('#babel/plugin-proposal-class-properties'),
require.resolve('babel-plugin-remove-graphql-queries')
]
config.module.rules = config.module.rules.filter(
f => f.test.toString() !== '/\\.css$/'
)
config.module.rules.push(
{
test: /\.(ttf|woff|woff2|eot|svg)$/,
use: 'file-loader?name=[name].[ext]',
exclude: /\.inline.svg$/
},
{
test: /\.(jpg|png|jpeg|jpg)$/,
loader: 'file-loader',
include: path.resolve(__dirname, '../static/')
},
{
test: /\.css$/,
exclude: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
localIdentName: 'mod-[hash:base64:8]'
}
},
'postcss-loader'
],
include: path.resolve(__dirname, '../')
},
{
test: /\.story\.mdx$/,
exclude: [/node_modules/],
include: [
path.resolve(__dirname, '../src'),
],
use: [
{
loader: 'babel-loader',
options: {
plugins: ['#babel/plugin-transform-react-jsx']
}
},
{
loader: '#mdx-js/loader',
options: {
compilers: [createCompiler({})]
}
}
],
},
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[local]-[hash:base64:5]'
}
},
'postcss-loader'
],
include: path.resolve(__dirname, '../src')
}
)
config.plugins.push(
new webpack.DefinePlugin({
STORYBOOK: JSON.stringify(true),
PRODUCTION: JSON.stringify(isProduction)
})
)
config.resolve.alias['#'] = path.resolve(__dirname, '../src/')
config.resolve.mainFields = ['browser', 'module', 'main']
return config
}
I expect to be able to see the props and mdx stor has a normal story.
Instead getting various errors.
https://user-images.githubusercontent.com/43405939/66821716-83e17300-ef60-11e9-8a89-fc99591954aa.png
Github Issue: https://github.com/storybookjs/storybook/issues/8414
Github repo to reproduce: https://github.com/vinayg-cp/storybook-poc.git

Related

Issues with style-loader lazyloading for multiple elements in shadow-dom

I'm currently working with webpack and style-loader to inject my styles into components that use shadow-dom. However, the issue happens when I try to use multiple instances of the element (the styles stop injecting). I was able to properly solve this issue with another component by adding the unuse function to my disconnectCallback for that component. Unfortunately, for this component below, I expect it to appear multiple times at once on a page. Am I doing something wrong?
Component.tsx:
import React from 'react';
import { createRoot } from 'react-dom/client';
// Styles
import styles from '../styles/contentScript.css';
// Images
const icon = chrome.runtime.getURL('assets/icon.png');
export default class CustomButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Functions
this.handleShow = this.handleShow.bind(this);
}
handleShow = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
...
};
connectedCallback() {
// Inject Styles
styles.use({ target: this.shadowRoot });
// Inject Component into ShadowRoot
createRoot(this.shadowRoot).render(this.render());
}
render() {
return (
<div className='absolute inset-0'>
<button className='main-button group' onClick={this.handleShow}>
<img src={icon} className='w-7' />
<span className='main-button-tooltip group-hover:scale-100'>
Open Popup
</span>
</button>
</div>
);
}
disconnectedCallback() {
styles.unuse();
}
}
customElements.define('custom-button', CustomButton);
webpack.config.js
// Imports...
module.exports = {
entry: {
...
},
module: {
rules: [
{
use: 'ts-loader',
test: /\.tsx?$/,
exclude: /node_modules/,
},
{
use: [
{
loader: 'style-loader',
options: {
injectType: 'lazyStyleTag',
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;
parent.appendChild(element);
},
},
},
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
indent: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
test: /\.css$/i,
},
{
type: 'asset/resource',
test: /\.(png|jpg|jpeg|gif)$/i,
},
]
},
resolve: {
...
},
plugins: [
...
],
output: {
filename: '[name].js',
clean: true,
},
optimization: {
...
},
}
I should also note (in case it's important) I am using tailwind for styling so I've included postcss and autoprefixer. This is also for a chrome extension so I'm creating this component in my contentScript. I have also tried it without the unuse call in my disconnectCallback and faced the same issue.
to follow the discussion on github, if you're only browser target is Chrome, then I really suggest you to use the CSSStyleSheet class.
In that case, you should drop from your webpack configuration the style-loader, as it's not needed anymore:
{
loader: 'style-loader',
options: {
injectType: 'lazyStyleTag',
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;
parent.appendChild(element);
},
},
},
Then modify the configuration of the css-loader to have the option exportType = "css-style-sheet" (https://webpack.js.org/loaders/css-loader/#exporttype).
In this way, the exported element is already an object of type CSSStyleSheet, and you can use it directly on your web component:
import sheet from "./styles.css" assert { type: "css" };
document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];
Normally, the 'postcss' step should not pose problems.
No need anymore to use "use / unuse" then (because that's an API of style-loder that you should remove with this solution)

rendering an html file within react

I am getting an html file from an external source and wanting to render it within a modal in react. It looks like it is receiving the file properly but I am getting this error.
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| <script language="javascript" ...
Here is my webpack.config,js file
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const isProduction = process.env.NODE_ENV == 'production';
const stylesHandler = isProduction ? MiniCssExtractPlugin.loader : 'style-loader';
const config = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
},
plugins: [
// Add your plugins here
// Learn more about plugins from https://webpack.js.org/configuration/plugins/
],
module: {
rules: [
{
test: /\.(js|jsx)$/i,
loader: 'babel-loader',
},
{
test: /\.css$/i,
use: [stylesHandler,'css-loader'],
},
{
test: /\.s[ac]ss$/i,
use: [stylesHandler, 'css-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset',
},
{
test: /\.html$/i,
loader: "html-loader",
},
// Add your rules for custom modules here
// Learn more about loaders from https://webpack.js.org/loaders/
],
},
};
module.exports = () => {
if (isProduction) {
config.mode = 'production';
config.plugins.push(new MiniCssExtractPlugin());
} else {
config.mode = 'development';
}
return config;
};
and here is my App.js file where my react code is located.
import './App.css';
import DOMPurify from 'dompurify';
import Modal from 'react-modal';
import htmlFile from './payee-verification-dropin.html'
import { useState } from 'react';
function App() {
const [showModal, setShowModal]= useState(false);
const myHTML = htmlFile;
const mySafeHTML = DOMPurify.sanitize(myHTML);
return (
<div className="App">
<Modal
isOpen={showModal}
onRequestClose={() => setShowModal(false)}
style={{
overlay: {},
content: {
position: "absolute",
top: "10%",
left: "25%",
width: "839px",
height: "81%",
borderRadius: "10px",
backgroundColor: "#FAFAFA",
padding: "0px",
},
}}
>
<div dangerouslySetInnerHTML={{_html: mySafeHTML }} />
<h1>Hello</h1>
</Modal>
<button onClick={() => setShowModal(true)}>CLick</button>
</div>
);
}
export default App;
Lert me know if you need more info to diagnose this problem.
Thank you!
I ran npx webpack init in order to set up webpack and I ran npm install --save-dev html-loader to try and install an html loader.

Can't render an img with react and webpack

Hi guys I'm new to Webpack so I'm having some problems when trying to add the src of an img tag because I'm getting an error, I already tried some solutions that I saw in other similar questions like adding the url-loader but I still can't get it to work
I'm getting this error in my code
ERROR in ./client/src/img/logo.png 1:0
[0] Module parse failed: Unexpected character '�' (1:0)
[0] You may need an appropriate loader to handle this file type, currently no loaders are
configured to process this file. See https://webpack.js.org/concepts#loaders
[0] (Source code omitted for this binary file)
[0] # ./client/src/pages/Homepage.js 108:9-35
[0] # ./client/src/App.js 3:0-40 9:38-46
[0] # ./client/src/index.js 3:0-24 4:50-53
My Webpack.config.js code
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: path.join(__dirname, 'client/src/index.js')
},
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js'
},
plugins: [new HtmlWebpackPlugin({
title: 'Ig Scraper',
template: path.join(__dirname, 'client/templates/index.ejs'),
filename: 'index.html'
})],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|express)/,
use: {
loader: 'babel-loader',
options: {
presets: [
"#babel/preset-env",
"#babel/preset-react"
]
},
}
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
options: {
attrs: [':data-src']
}
}
},
// {
// test: /\.(png|jpg)$/,
// include: path.join(__dirname, '/client/img'),
// loader: 'file-loader'
// },
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
use: [
{
loader: 'url-loader?limit=100000'
}
]
}
]
},
devServer: {},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
resolveLoader: {
extensions: ["babel-loader"]
},
devtool: 'source-map',
mode: 'development',
resolve: {
fallback: {
fs: false
}
}
};
My Homepage.js code
import React, { useState } from "react";
import axios from "axios";
import '../assets/Homepage.css'
// import logo from '../img/instagramLogo.png'
const Homepage = () => {
return (
<>
<div className="container">
<div className="homepage">
<div className="homepage__igAssets">
<img src={require('../img/logo.png')} alt="" className="ig__logo" />
{/* <img src="./assets/instagram.png" alt="" className="ig__text" /> */}
</div>
<h1 className="homepage__title">¡Let's scrape your instagram account! </h1>
<div className="homepage__elements">
<input className="homepage__input" placeholder="Username..." value= {username} onChange={onChange} />
<button className="homepage__button" onClick={onClick}>Get instagram followers!</button>
</div>
{renderData()}
</div>
</div>
</>
);
};
export default Homepage;
My files organization
Most likely, this error comes from Homepage.js, on the line:
<img src={require('../img/logo.png')} ... />
Require is not meant for images, but for js modules (learn more here).
Erratum: Above is about require in nodejs, it may not be the way to go, but require seems to work fine with webpack.
The way to use images with react would be:
// First, import the image file
import image from './path-to-image.png';
// Later, use it as source in the render
<img src={image} ... />
Your webpack.config.js looks fine (although i'm no expert at such things).
Add: Here is an other question highly related that might help you

ReferenceError: document is not defined when refresh nextjs page

i am trying to create a simple UI library using react for Nextjs 9.4, here what i am doing
// input.js in React UI Lib
import React from "react";
import styled from "./input.module.scss";
const Input = React.forwardRef((props, ref) => (
<>
{props.label && <label className={styled.label}>{props.label}</label>}
<input className={styled.input} {...props} ref={ref} />
</>
));
export default Input;
and made an index to export all modules for simplicity
// app.js the index file for the lib
import PrimaryButton from "./components/button/primaryButton";
import TextInput from "./components/input/input";
import PasswordInput from "./components/passwordInput/password";
import CheckBox from "./components/checkbox/checkbox";
export {
PrimaryButton,
TextInput,
PasswordInput,
CheckBox
};
also here is my webpack config to build for SSR Next
const path = require("path");
const autoprefixer = require("autoprefixer");
const nodeExternals = require("webpack-node-externals");
const CSSLoader = {
loader: "css-loader",
options: {
modules: "global",
importLoaders: 2,
sourceMap: false,
},
};
const CSSModlueLoader = {
loader: "css-loader",
options: {
modules: true,
importLoaders: 2,
sourceMap: false,
},
};
const PostCSSLoader = {
loader: "postcss-loader",
options: {
ident: "postcss",
sourceMap: false,
plugins: () => [autoprefixer()],
},
};
const SassLoader = {
loader: "sass-loader",
options: {
// Prefer `dart-sass`
implementation: require("sass"),
},
};
module.exports = {
target: "node",
entry: "./src/app.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
chunkFilename: "[id].js",
publicPath: "",
library: "",
libraryTarget: "commonjs",
},
externals: [nodeExternals()],
resolve: {
extensions: [".js", ".jsx"],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.(sa|sc|c)ss$/i,
exclude: [/node_modules/, /\.module\.(sa|sc|c)ss$/i],
use: ["style-loader", CSSLoader, PostCSSLoader, SassLoader],
},
{
test: /\.module\.(sa|sc|c)ss$/i,
exclude: /node_modules/,
use: ["style-loader", CSSModlueLoader, PostCSSLoader, SassLoader],
},
{
test: /\.(png|jpe?g|gif)$/,
loader: "url-loader?limit=10000&name=img/[name].[ext]",
},
],
},
};
1-i build
2-publush on npm
3-import in Nextjs
then everything works well , but the problem is when i try to refresh (F5) the page during development i get the error
Unhandled Runtime Error
ReferenceError: document is not defined
how can i fix that ?
try to render component only in client side you can do with:
typeof window !== 'undefined' ? <Component /> : null
you are using style-loader in your webpack config, it will inject styles into head using document.createElement that is not availabe in SSR, you can choose other options like mini-css-extract-plugin
const Example = dynamic( () => import('example'), { ssr: false } )
https://github.com/elrumordelaluz/reactour/issues/130
try to check component in client side rendering ex:
const isBrowser = typeof window !== 'undefined';
isBrowser ? <Component/> : null;
another option is try to render using ssr false:
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
Thanks..
You may not always want to include a module on server-side. For example, when the module includes a library that only works in the browser.
Take a look at the following example:
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
function Home() {
return (
<div>
<Header />
<DynamicComponentWithNoSSR />
<p>HOME PAGE is here!</p>
</div>
)
}
export default Home

How to render a foo.md markdown file in react?

I have several .md files (containing long texts) and I want to render them through react. I tried to use markedown-it but the loader returns an error. Here is the webpack.config.js file:
var path = require('path');
var webpack = require('webpack');
var subscript = require('markdown-it');
var superscript = require('markdown-it');
module.exports = {
entry: ['./src/first.jsx'],
devtool: 'cheap-module-eval-source-map',
output: { path: __dirname+"/app", filename: 'bundle.js' },
module: {
loaders: [
{ test: /\.jsx?$/,
loader: 'babel-loader',
query: { presets: ['es2015', 'react'] },
include: path.join(__dirname, 'src')
},
{ test: /\.md/,
loader: 'markdown-it'
}
]
},
'markdown-it': {
preset: 'default',
typographer: true,
use: [subscript, superscript]
}
};
Is there something wrong with that file? How else I can add my *.md files to react?
After reading http://www.shoutinginfrench.com/today-i-made-react-load-markdown/ I tried to use markdown-loader. Following that, I added this to webpack.config file:
{ test: /\.md$/,
loader: "html!markdown"
}
which worked with no problem. Then I tried to add the markdown file to the react component as follow:
import React from 'react';
import { Link } from 'react-router'
import markdownFile from './test-file.md';
export const Test = React.createClass({
rawMarkup(){
return { __html: markdownFile };
},
render() {
return (
<div className="something">
<div className="row">
<div className="col-10">
<div dangerouslySetInnerHtml={this.rawMarkup()} />
</div>
</div>
</div>
);
}
});
But I'm getting the following error:
ERROR in ./src/components/tst.jsx
Module not found: Error: Cannot resolve module 'html' in /Users/..../src/components
# ./src/components/tst.jsx 14:15-39
How can I fix it?!
add { test: /\.md$/, loader: "html!markdown" },{ test: /\.json$/, loader: "json" } to your webpack.config.js .
npm install react-markdown --save-dev

Resources