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?
Yes
Seems like using components that are also already imported into docs file in live preview is more straight forward.
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>
\```
PR welcome
Great, will try taking a look 馃憤
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? https://github.com/ChristopherBiscardi/gatsby-mdx/issues/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
Any clues where should I try going with this? Or any other ideas?
Any updates on this?
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
@docusaurus/theme-live-codeblock is installed and configured in your docusaurus configurationdocusaurus swizzle @docusaurus/theme-classic MDXComponentssrc/theme/MDXComponents/index.js and pass your scope to the CodeBlock componentimport * 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.
@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
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.
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
@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!
Try ExecutionEnvironment.canUseDOM()
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.
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.
I've written an article on DEV which covers this scenario and more.
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.
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 ReactLiveScopeI'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.
Most helpful comment
You can add your own scope by overwriting the MDX's code component. The
<CodeBlock />component Docusaurus uses to render the live editor accepts ascopeprop that will make your own modules available in the live editor.Step-by-step guide
@docusaurus/theme-live-codeblockis installed and configured in your docusaurus configurationdocusaurus swizzle @docusaurus/theme-classic MDXComponentssrc/theme/MDXComponents/index.jsand pass your scope to the CodeBlock componentThe scope will be passed through to react-live's LiveProvider (more info) and your own components will be available in the live editor.