mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
feat: mdx loader fallback, allow importing mdx docs from anywhere (#5299)
* move deep filepath test * split markdownPageExample.md * re-org dogfooding content * Add mdx partials fallback synthetic plugin by default * test commit * hide changelog title as it's already included in the partial file * trigger CI * fix changelog sidebar label
This commit is contained in:
parent
780e924a9e
commit
916b82119b
|
|
@ -1309,7 +1309,7 @@ Starting with this release for a proper work of i18n functionality, you need to
|
|||
#### :rocket: New Feature
|
||||
|
||||
- `docusaurus`
|
||||
- [#3932](https://github.com/facebook/docusaurus/pull/3932) feat(v2): Add <Root> theme element ([@slorber](https://github.com/slorber))
|
||||
- [#3932](https://github.com/facebook/docusaurus/pull/3932) feat(v2): Add Root theme element ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-module-type-aliases`, `docusaurus-theme-classic`, `docusaurus-types`, `docusaurus`
|
||||
- [#3916](https://github.com/facebook/docusaurus/pull/3916) feat(v2): Add localeDropdown navbar item type + i18n localeConfigs field ([@slorber](https://github.com/slorber))
|
||||
- `docusaurus-mdx-loader`, `docusaurus-plugin-content-blog`, `docusaurus-plugin-content-docs`, `docusaurus-plugin-content-pages`, `docusaurus-theme-bootstrap`, `docusaurus-theme-classic`, `docusaurus-types`
|
||||
|
|
|
|||
|
|
@ -98,11 +98,16 @@ File at ${filePath} contains FrontMatter that will be ignored: \n${JSON.stringif
|
|||
null,
|
||||
2,
|
||||
)}`;
|
||||
const shouldError = process.env.NODE_ENV === 'test' || process.env.CI;
|
||||
if (shouldError) {
|
||||
return callback(new Error(errorMessage));
|
||||
|
||||
if (options.isMDXPartialFrontMatterWarningDisabled === true) {
|
||||
// no warning
|
||||
} else {
|
||||
console.warn(chalk.yellow(errorMessage));
|
||||
const shouldError = process.env.NODE_ENV === 'test' || process.env.CI;
|
||||
if (shouldError) {
|
||||
return callback(new Error(errorMessage));
|
||||
} else {
|
||||
console.warn(chalk.yellow(errorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
DEFAULT_BUILD_DIR_NAME,
|
||||
DEFAULT_CONFIG_FILE_NAME,
|
||||
GENERATED_FILES_DIR_NAME,
|
||||
STATIC_DIR_NAME,
|
||||
} from '../constants';
|
||||
import loadClientModules from './client-modules';
|
||||
import loadConfig from './config';
|
||||
|
|
@ -24,6 +25,7 @@ import {
|
|||
DocusaurusSiteMetadata,
|
||||
HtmlTagObject,
|
||||
LoadContext,
|
||||
LoadedPlugin,
|
||||
PluginConfig,
|
||||
Props,
|
||||
} from '@docusaurus/types';
|
||||
|
|
@ -36,6 +38,7 @@ import {
|
|||
getPluginsDefaultCodeTranslationMessages,
|
||||
} from './translations/translations';
|
||||
import {mapValues} from 'lodash';
|
||||
import {RuleSetRule} from 'webpack';
|
||||
|
||||
export type LoadContextOptions = {
|
||||
customOutDir?: string;
|
||||
|
|
@ -135,6 +138,104 @@ export function loadPluginConfigs(context: LoadContext): PluginConfig[] {
|
|||
];
|
||||
}
|
||||
|
||||
// Make a fake plugin to:
|
||||
// - Resolve aliased theme components
|
||||
// - Inject scripts/stylesheets
|
||||
function createBootstrapPlugin({
|
||||
siteConfig,
|
||||
}: {
|
||||
siteConfig: DocusaurusConfig;
|
||||
}): LoadedPlugin {
|
||||
const {
|
||||
stylesheets = [],
|
||||
scripts = [],
|
||||
clientModules: siteConfigClientModules = [],
|
||||
} = siteConfig;
|
||||
return {
|
||||
name: 'docusaurus-bootstrap-plugin',
|
||||
content: null,
|
||||
options: {},
|
||||
version: {type: 'synthetic'},
|
||||
getClientModules() {
|
||||
return siteConfigClientModules;
|
||||
},
|
||||
injectHtmlTags: () => {
|
||||
const stylesheetsTags = stylesheets.map((source) =>
|
||||
typeof source === 'string'
|
||||
? `<link rel="stylesheet" href="${source}">`
|
||||
: ({
|
||||
tagName: 'link',
|
||||
attributes: {
|
||||
rel: 'stylesheet',
|
||||
...source,
|
||||
},
|
||||
} as HtmlTagObject),
|
||||
);
|
||||
const scriptsTags = scripts.map((source) =>
|
||||
typeof source === 'string'
|
||||
? `<script src="${source}"></script>`
|
||||
: ({
|
||||
tagName: 'script',
|
||||
attributes: {
|
||||
...source,
|
||||
},
|
||||
} as HtmlTagObject),
|
||||
);
|
||||
return {
|
||||
headTags: [...stylesheetsTags, ...scriptsTags],
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Configurer Webpack fallback mdx loader for md/mdx files out of content-plugin folders
|
||||
// Adds a "fallback" mdx loader for mdx files that are not processed by content plugins
|
||||
// This allows to do things such as importing repo/README.md as a partial from another doc
|
||||
// Not ideal solution though, but good enough for now
|
||||
function createMDXFallbackPlugin({siteDir}: {siteDir: string}): LoadedPlugin {
|
||||
return {
|
||||
name: 'docusaurus-mdx-fallback-plugin',
|
||||
content: null,
|
||||
options: {},
|
||||
version: {type: 'synthetic'},
|
||||
configureWebpack(config, isServer, {getJSLoader}) {
|
||||
// We need the mdx fallback loader to exclude files that were already processed by content plugins mdx loaders
|
||||
// This works, but a bit hacky...
|
||||
// Not sure there's a way to handle that differently in webpack :s
|
||||
function getMDXFallbackExcludedPaths(): string[] {
|
||||
const rules: RuleSetRule[] = config?.module?.rules as RuleSetRule[];
|
||||
return rules.flatMap((rule) => {
|
||||
const isMDXRule =
|
||||
rule.test instanceof RegExp && rule.test.test('x.mdx');
|
||||
return isMDXRule ? (rule.include as string[]) : [];
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /(\.mdx?)$/,
|
||||
exclude: getMDXFallbackExcludedPaths(),
|
||||
use: [
|
||||
getJSLoader({isServer}),
|
||||
{
|
||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||
options: {
|
||||
staticDir: path.join(siteDir, STATIC_DIR_NAME),
|
||||
isMDXPartial: (_filename) => true, // External mdx files are always meant to be imported as partials
|
||||
isMDXPartialFrontMatterWarningDisabled: true, // External mdx files might have frontmatter, let's just disable the warning
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function load(
|
||||
siteDir: string,
|
||||
options: LoadContextOptions = {},
|
||||
|
|
@ -176,49 +277,8 @@ export async function load(
|
|||
`export default ${JSON.stringify(siteConfig, null, 2)};`,
|
||||
);
|
||||
|
||||
// Make a fake plugin to:
|
||||
// - Resolve aliased theme components
|
||||
// - Inject scripts/stylesheets
|
||||
const {
|
||||
stylesheets = [],
|
||||
scripts = [],
|
||||
clientModules: siteConfigClientModules = [],
|
||||
} = siteConfig;
|
||||
plugins.push({
|
||||
name: 'docusaurus-bootstrap-plugin',
|
||||
content: null,
|
||||
options: {},
|
||||
version: {type: 'synthetic'},
|
||||
getClientModules() {
|
||||
return siteConfigClientModules;
|
||||
},
|
||||
injectHtmlTags: () => {
|
||||
const stylesheetsTags = stylesheets.map((source) =>
|
||||
typeof source === 'string'
|
||||
? `<link rel="stylesheet" href="${source}">`
|
||||
: ({
|
||||
tagName: 'link',
|
||||
attributes: {
|
||||
rel: 'stylesheet',
|
||||
...source,
|
||||
},
|
||||
} as HtmlTagObject),
|
||||
);
|
||||
const scriptsTags = scripts.map((source) =>
|
||||
typeof source === 'string'
|
||||
? `<script src="${source}"></script>`
|
||||
: ({
|
||||
tagName: 'script',
|
||||
attributes: {
|
||||
...source,
|
||||
},
|
||||
} as HtmlTagObject),
|
||||
);
|
||||
return {
|
||||
headTags: [...stylesheetsTags, ...scriptsTags],
|
||||
};
|
||||
},
|
||||
});
|
||||
plugins.push(createBootstrapPlugin({siteConfig}));
|
||||
plugins.push(createMDXFallbackPlugin({siteDir}));
|
||||
|
||||
// Load client modules.
|
||||
const clientModules = loadClientModules(plugins);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
---
|
||||
test: 'some test frontmatter'
|
||||
---
|
||||
|
||||
# Docusaurus website dogfooding
|
||||
|
||||
This is where we test edge cases of Docusaurus by using fancy configs, ensuring they all don't fail during a real site build.
|
||||
|
|
@ -12,3 +16,4 @@ Fancy things we can test for here:
|
|||
- \_ prefix convention
|
||||
- Huge sidebars impact
|
||||
- Using folders with spaces on purpose
|
||||
- Importing md docs that are out of content plugin folders as partials (such as this README file!)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
## Page
|
||||
|
||||
Let's import some MDX partial:
|
||||
Let's import a MDX partial at `./_pagePartial.md`:
|
||||
|
||||
```mdx-code-block
|
||||
import PagePartial from "./_pagePartial.md"
|
||||
|
||||
<PagePartial />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Now let's import `../README.md`:
|
||||
|
||||
```mdx-code-block
|
||||
import Readme from "../README.md"
|
||||
|
||||
<Readme />
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
title: Markdown Page tests title
|
||||
description: Markdown Page tests description
|
||||
wrapperClassName: docusaurus-markdown-example
|
||||
---
|
||||
|
||||
# Markdown page tests
|
||||
|
||||
This is a page generated from markdown to illustrate the Markdown page feature and test some edge cases.
|
||||
|
||||
:::info
|
||||
|
||||
Useful information.
|
||||
|
||||
:::
|
||||
|
||||
```jsx live
|
||||
function Button() {
|
||||
return (
|
||||
<button type="button" onClick={() => alert('hey')}>
|
||||
Click me!
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Using absolute path
|
||||
|
||||

|
||||
|
||||
### Tab
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs defaultValue="apple" values={[ {label: 'Apple', value: 'apple'}, {label: 'Orange', value: 'orange'}, {label: 'Banana', value: 'banana'} ]}><TabItem value="apple">This is an apple 🍎</TabItem><TabItem value="orange">This is an orange 🍊</TabItem><TabItem value="banana">This is a banana 🍌</TabItem></Tabs>
|
||||
|
||||
## Comments
|
||||
|
||||
MDX comments can be used with
|
||||
|
||||
```mdx
|
||||
<!--
|
||||
|
||||
My comment
|
||||
|
||||
-->
|
||||
```
|
||||
|
||||
See, nothing is displayed:
|
||||
|
||||
<!--
|
||||
|
||||
My comment
|
||||
|
||||
-->
|
||||
|
||||
## Import code block from source code file
|
||||
|
||||
import MyComponent from "@site/src/pages/examples/\_myComponent"
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Let's say you have a React component.
|
||||
|
||||
You can import and use it in MDX:
|
||||
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import MyComponent from './myComponent';
|
||||
|
||||
<MyComponent />;
|
||||
```
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
|
||||
<MyComponent/>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
But you can also display its source code directly in MDX, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/)
|
||||
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
import MyComponentSource from '!!raw-loader!./myComponent';
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>;
|
||||
```
|
||||
|
||||
import CodeBlock from "@theme/CodeBlock"
|
||||
|
||||
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/\_myComponent';
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Test
|
||||
|
||||
```jsx live
|
||||
function Demo() {
|
||||
React.useEffect(() => console.log('mount'), []);
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## Code block test
|
||||
|
||||
```js title="Title"
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
var timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
// highlight-start
|
||||
{/* prettier-ignore */}
|
||||
long long long long long long long long long long long long line
|
||||
{/* prettier-ignore */}
|
||||
// highlight-end
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```jsx live
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
var timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<CodeBlock className="language-yaml" title="test">
|
||||
test
|
||||
</CodeBlock>
|
||||
|
||||
<code>test</code>
|
||||
|
||||
## direct using of `pre`
|
||||
|
||||
<pre>test</pre>
|
||||
|
||||
<!-- Multi-line text inside `pre` will turn into one-liner, but it's okay (https://github.com/mdx-js/mdx/issues/1095) -->
|
||||
<pre>
|
||||
1
|
||||
2
|
||||
3
|
||||
</pre>
|
||||
|
||||
## Custom heading id {#custom}
|
||||
|
||||
## Children elements inside pre/code elements
|
||||
|
||||
See https://github.com/facebook/docusaurus/pull/1584
|
||||
|
||||
<pre><code>
|
||||
<BrowserWindow url="http://localhost:3000" >
|
||||
Lol bro
|
||||
</BrowserWindow>
|
||||
</code></pre>
|
||||
|
||||
<code>
|
||||
<BrowserWindow url="http://localhost:3000" >
|
||||
Lol bro
|
||||
</BrowserWindow>
|
||||
</code>
|
||||
|
||||
## Pipe
|
||||
|
||||
Code tag + double pipe: <code>||</code>
|
||||
|
||||
Code tag + double pipe: <code>||</code>
|
||||
|
||||
## Images edge cases
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: Docusaurus 2 Changelog
|
||||
hide_title: true
|
||||
sidebar_label: Changelog
|
||||
---
|
||||
|
||||
```mdx-code-block
|
||||
import Changelog from "../../CHANGELOG.md"
|
||||
|
||||
<Changelog />
|
||||
```
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Chapter 1
|
||||
|
||||
Lorem ipsum chapter 1
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Chapter 2
|
||||
|
||||
Lorem ipsum chapter 2
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Markdown Page example title
|
||||
description: Markdown Page example description
|
||||
title: Markdown Page example
|
||||
description: Markdown Page example
|
||||
wrapperClassName: docusaurus-markdown-example
|
||||
---
|
||||
|
||||
|
|
@ -8,225 +8,8 @@ wrapperClassName: docusaurus-markdown-example
|
|||
|
||||
This is a page generated from markdown to illustrate the Markdown page feature.
|
||||
|
||||
It supports all the regular MDX features, as you can see:
|
||||
:::tip
|
||||
|
||||
:::info
|
||||
|
||||
Useful information.
|
||||
Use Markdown pages when you just want to focus on content and the default layout is good enough
|
||||
|
||||
:::
|
||||
|
||||
```jsx live
|
||||
function Button() {
|
||||
return (
|
||||
<button type="button" onClick={() => alert('hey')}>
|
||||
Click me!
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Using absolute path
|
||||
|
||||

|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs defaultValue="apple" values={[ {label: 'Apple', value: 'apple'}, {label: 'Orange', value: 'orange'}, {label: 'Banana', value: 'banana'} ]}><TabItem value="apple">This is an apple 🍎</TabItem><TabItem value="orange">This is an orange 🍊</TabItem><TabItem value="banana">This is a banana 🍌</TabItem></Tabs>
|
||||
|
||||
## Import Mdx and Md files
|
||||
|
||||
```js
|
||||
// *.md file
|
||||
import Chapter1 from './_chapter1.md';
|
||||
|
||||
<Chapter1 />;
|
||||
|
||||
// *.mdx file
|
||||
import Chapter2 from './_chapter2.mdx';
|
||||
|
||||
<Chapter2 />;
|
||||
```
|
||||
|
||||
import Chapter1 from './\_chapter1.md';
|
||||
|
||||
<Chapter1/>
|
||||
|
||||
import Chapter2 from './\_chapter2.mdx';
|
||||
|
||||
<Chapter2/>
|
||||
|
||||
## Comments
|
||||
|
||||
MDX comments can be used with
|
||||
|
||||
```mdx
|
||||
<!--
|
||||
|
||||
My comment
|
||||
|
||||
-->
|
||||
```
|
||||
|
||||
See, nothing is displayed:
|
||||
|
||||
<!--
|
||||
|
||||
My comment
|
||||
|
||||
-->
|
||||
|
||||
## Import code block from source code file
|
||||
|
||||
import MyComponent from "@site/src/pages/examples/\_myComponent"
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Let's say you have a React component.
|
||||
|
||||
You can import and use it in MDX:
|
||||
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import MyComponent from './myComponent';
|
||||
|
||||
<MyComponent />;
|
||||
```
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
|
||||
<MyComponent/>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
But you can also display its source code directly in MDX, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/)
|
||||
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
import MyComponentSource from '!!raw-loader!./myComponent';
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>;
|
||||
```
|
||||
|
||||
import CodeBlock from "@theme/CodeBlock"
|
||||
|
||||
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/\_myComponent';
|
||||
|
||||
<BrowserWindow url="http://localhost:3000">
|
||||
|
||||
<CodeBlock className="language-jsx">{MyComponentSource}</CodeBlock>
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Test
|
||||
|
||||
```jsx live
|
||||
function Demo() {
|
||||
React.useEffect(() => console.log('mount'), []);
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## Code block test
|
||||
|
||||
```js title="Title"
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
var timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
// highlight-start
|
||||
{/* prettier-ignore */}
|
||||
long long long long long long long long long long long long line
|
||||
{/* prettier-ignore */}
|
||||
// highlight-end
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```jsx live
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
var timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
<CodeBlock className="language-yaml" title="test">
|
||||
test
|
||||
</CodeBlock>
|
||||
|
||||
<code>test</code>
|
||||
|
||||
## direct using of `pre`
|
||||
|
||||
<pre>test</pre>
|
||||
|
||||
<!-- Multi-line text inside `pre` will turn into one-liner, but it's okay (https://github.com/mdx-js/mdx/issues/1095) -->
|
||||
<pre>
|
||||
1
|
||||
2
|
||||
3
|
||||
</pre>
|
||||
|
||||
## Custom heading id {#custom}
|
||||
|
||||
## Children elements inside pre/code elements
|
||||
|
||||
See https://github.com/facebook/docusaurus/pull/1584
|
||||
|
||||
<pre><code>
|
||||
<BrowserWindow url="http://localhost:3000" >
|
||||
Lol bro
|
||||
</BrowserWindow>
|
||||
</code></pre>
|
||||
|
||||
<code>
|
||||
<BrowserWindow url="http://localhost:3000" >
|
||||
Lol bro
|
||||
</BrowserWindow>
|
||||
</code>
|
||||
|
||||
## Pipe
|
||||
|
||||
Code tag + double pipe: <code>||</code>
|
||||
|
||||
Code tag + double pipe: <code>||</code>
|
||||
|
||||
## Images edge cases
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
|
|
|||
Loading…
Reference in New Issue