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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2] Add support for MDX scoped components in live preview #2152

Closed
matmalkowski opened this issue Dec 27, 2019 · 16 comments
Closed

[v2] Add support for MDX scoped components in live preview #2152

matmalkowski opened this issue Dec 27, 2019 · 16 comments
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.

Comments

@matmalkowski
Copy link

馃殌 Feature

I'm trying to use v2 live code editor with MDX files, and seems like the context of MDX is not passed to the LivePreview component. I had a quick glance at the docusaurus-theme-live-codeblock and it seems like it could do something like described in here: https://www.christopherbiscardi.com/post/using-mdx-scope-in-react-live-scope/

Is this something we could add to the theme?

Have you read the Contributing Guidelines on issues?

Yes

Motivation

Seems like using components that are also already imported into docs file in live preview is more straight forward.

Pitch

Similar as in mentioned blog post, I think we just have to add mdx components to the context of the LivePreview in the theme. That would enable usage of live preview like this:

import { Button } from '@material-ui/core'

# Button
Some description

<Button /> 

\```jsx live
<Button variant="solid">test</Button>
\```

@matmalkowski matmalkowski added feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs triage This issue has not been triaged by maintainers labels Dec 27, 2019
@endiliey
Copy link
Contributor

PR welcome

@matmalkowski matmalkowski changed the title Add support for MDX scoped components in live preview [v2] Add support for MDX scoped components in live preview Dec 27, 2019
@matmalkowski
Copy link
Author

Great, will try taking a look 馃憤

@matmalkowski
Copy link
Author

matmalkowski commented Dec 27, 2019

So, had a look into codebase, and seems like its bit bigger than I anticipated. The mentioned solution from the blog doesn't work, since LiveProvider requires passing actual modules into the scope, as in the docs:

import styled from 'styled-components'
const scope = {styled}
const code = `
  const Header = styled.div\`
    color: palevioletred;
  \`
  
  render(<Header>I'm styled!</Header>)
`
<LiveProvider code={code} scope={scope} noInline={true}>
  <LiveEditor />
  <LiveError />
  <LivePreview />
</LiveProvider>

{mdx} scope doesn't contains those by default, so it doesn't work I guess.

I found that gatsby-mdx did the global scope as configuration in the plugin, maybe this should be a way to go? ChristopherBiscardi/gatsby-mdx#138

Another way might be pulling all module imports while parsing and loading them into some context for later use inside of the CodeBlock component. But that seems even more hardcore in implementation than configuration.

One actual live example of how other LiveProvider is used with MDX on documentation framework was docz - but in their case they are parsing document tree with babel and grabbing all imports, extracting the scoped variables and injecting them into their Playground component via node manipulation - this won't work in our case as we don't have component on the MDX to inject stuff into.

Any clues where should I try going with this? Or any other ideas?

@endiliey endiliey added RFC and removed status: needs triage This issue has not been triaged by maintainers labels Jan 1, 2020
@monapasan
Copy link

Any updates on this?

@johnny353535
Copy link

You can add your own scope by overwriting the MDX's code component. The <CodeBlock /> component Docusaurus uses to render the live editor accepts a scope prop that will make your own modules available in the live editor.

Step-by-step guide

  1. Make sure @docusaurus/theme-live-codeblock is installed and configured in your docusaurus configuration
  2. Swizzle MDXComponents by running docusaurus swizzle @docusaurus/theme-classic MDXComponents
  3. Go to src/theme/MDXComponents/index.js and pass your scope to the CodeBlock component
import * as Components from 'MyComponentLibrary';

...

code: props => {
  const { children } = props;

  const scope = {
    ...React,
    ...Components
  };

  if (typeof children === 'string') {
    return <CodeBlock {...props} scope={scope} />;
  }
  return children;
},

...

The scope will be passed through to react-live's LiveProvider (more info) and your own components will be available in the live editor.

@matmalkowski
Copy link
Author

@johnny353535 so for now this is preferred way, or its solution that expected to be followed long term on final product? Asking because current readme discourages users from swizzling components

@johnny353535
Copy link

I'd also consider this a temporary workaround. Especially, because we can't rely on this workaround to also work in the future.

Providing scope to the live-editor should be a first-party feature, but I haven't research the cleanest way of providing this functionality.

@daneah
Copy link

daneah commented Apr 6, 2020

I've tried the temporary workaround described above, and it indeed works for development, but I'm finding that it breaks the production build. We're using web components with React wrappers鈥攏ot sure if that specific use case is what's breaking things?

Error message
ReferenceError: window is not definedReferenceError: window is not definedReferenceError: window is not definedReferenceError: window is not definedReferenceError: window is not definedReferenceError: window is not defined
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
(undefined) ReferenceError: window is not defined
    at Module.<anonymous> (main:18821:1)
    at __webpack_require__ (main:21:30)
    at main:45570:251
Error: Failed to compile with errors.
    at /Users/dhillard/source/pharos-bak/node_modules/@docusaurus/core/lib/commands/build.js:37:24
    at finalCallback (/Users/dhillard/source/pharos-bak/node_modules/webpack/lib/MultiCompiler.js:254:12)
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/MultiCompiler.js:277:6
    at done (/Users/dhillard/source/pharos-bak/node_modules/neo-async/async.js:2931:13)
    at runCompilers (/Users/dhillard/source/pharos-bak/node_modules/webpack/lib/MultiCompiler.js:181:48)
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/MultiCompiler.js:188:7
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/MultiCompiler.js:270:7
    at finalCallback (/Users/dhillard/source/pharos-bak/node_modules/webpack/lib/Compiler.js:257:39)
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/Compiler.js:273:13
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/dhillard/source/pharos-bak/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:42:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/dhillard/source/pharos-bak/node_modules/tapable/lib/Hook.js:154:20)
    at onCompiled (/Users/dhillard/source/pharos-bak/node_modules/webpack/lib/Compiler.js:271:21)
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/Compiler.js:681:15
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/dhillard/source/pharos-bak/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/dhillard/source/pharos-bak/node_modules/tapable/lib/Hook.js:154:20)
    at /Users/dhillard/source/pharos-bak/node_modules/webpack/lib/Compiler.js:678:31

@daneah
Copy link

daneah commented Apr 6, 2020

@yangshun thanks for the quick reply and suggestions. I tried inserting the workaround above only if (ExecutionEnvironment.canUseViewport) and also tried wrapping my jsx live code block in <BrowserOnly />, neither of which seemed to work. Was that what you were suggesting, or am I still missing something? Appreciate the help!

@yangshun
Copy link
Contributor

yangshun commented Apr 6, 2020

Try ExecutionEnvironment.canUseDOM()

@daneah
Copy link

daneah commented Apr 6, 2020

Same results, it appears. Specifically, after import * as Components from '@our/react-package'; is fine, but adding the line scope = {...React, ...Components} causes the error to arise.

@daneah
Copy link

daneah commented Apr 6, 2020

Tracked this down to a piece of code in lit-html, so my suspicion about this being web component-specific was indeed true. Not sure why the ExecutionEnvironment trick isn't working for me, but will continue to tinker.

@mrmuhammadali
Copy link
Contributor

I've written an article on DEV which covers this scenario and more.

@slorber
Copy link
Collaborator

slorber commented Sep 3, 2020

Hey, late to the party but we have provided a way to easily add components to the react-live scope:

https://v2.docusaurus.io/docs/markdown-features/#interactive-code-editor
yarn run swizzle @docusaurus/theme-live-codeblock ReactLiveScope

I've tried to support adding automatically imports of MDX into the react-live scope, so that it can be done "automagically", like Gatsby does, but it's kinda more complex than I thought. Gatsby integration does read mdx files to extract at build time (using a babel plugin as far as I remember) the mdx scope of the mdx file (imports + exports), and reinject them and add the mdxprovider scope to finally get the react-live scope.

@arifszn
Copy link
Contributor

arifszn commented Sep 19, 2020

Hey, late to the party but we have provided a way to easily add components to the react-live scope:

https://v2.docusaurus.io/docs/markdown-features/#interactive-code-editor
yarn run swizzle @docusaurus/theme-live-codeblock ReactLiveScope

I've tried to support adding automatically imports of MDX into the react-live scope, so that it can be done "automagically", like Gatsby does, but it's kinda more complex than I thought. Gatsby integration does read mdx files to extract at build time (using a babel plugin as far as I remember) the mdx scope of the mdx file (imports + exports), and reinject them and add the mdxprovider scope to finally get the react-live scope.

#3466 Can you please look at the issue? Our work has stopped because of this.

@lex111 lex111 closed this as completed Nov 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.
Projects
None yet
Development

No branches or pull requests

10 participants