mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-12 00:27:21 +02:00
feat(v2): render Markdown on server-side instead (#1077)
* feat(v2): render Markdown on server-side instead * move to folder
This commit is contained in:
parent
d479f42ff5
commit
6cec7ce982
6 changed files with 173 additions and 177 deletions
|
@ -8,96 +8,10 @@
|
|||
/* eslint-disable */
|
||||
|
||||
import React from 'react';
|
||||
import Markdown from 'remarkable';
|
||||
import Helmet from 'react-helmet';
|
||||
import hljs from 'highlight.js';
|
||||
import chalk from 'chalk';
|
||||
import escapeHtml from 'escape-html';
|
||||
import anchors from './anchors';
|
||||
|
||||
class MarkdownBlock extends React.Component {
|
||||
content() {
|
||||
if (this.props.source) {
|
||||
return (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: this.renderMarkdown(this.props.source),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return React.Children.map(this.props.children, child => {
|
||||
if (typeof child === 'string') {
|
||||
return (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{__html: this.renderMarkdown(child)}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
renderMarkdown(source) {
|
||||
const alias = {
|
||||
js: 'jsx',
|
||||
};
|
||||
const {siteConfig} = this.props;
|
||||
const md = new Markdown({
|
||||
langPrefix: 'hljs css language-',
|
||||
highlight: function(str, rawLang) {
|
||||
// Default language fallback
|
||||
const defaultLang =
|
||||
siteConfig.highlight && siteConfig.highlight.defaultLang;
|
||||
|
||||
// No syntax highlighting
|
||||
if (rawLang === 'text' || (!rawLang && !defaultLang)) {
|
||||
return escapeHtml(str);
|
||||
}
|
||||
|
||||
// User's own hljs function to register additional languages
|
||||
if (siteConfig.highlight && siteConfig.highlight.hljs) {
|
||||
siteConfig.highlight.hljs(hljs);
|
||||
}
|
||||
|
||||
// Syntax highlighting
|
||||
const lang = rawLang.toLowerCase() || defaultLang;
|
||||
try {
|
||||
if (hljs.getLanguage(lang)) {
|
||||
return hljs.highlight(lang, str).value;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
chalk.yellow(
|
||||
`Highlight.js syntax highlighting for language "${lang}" is not supported.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
return hljs.highlightAuto(str).value;
|
||||
},
|
||||
html: true,
|
||||
linkify: true,
|
||||
});
|
||||
|
||||
// Register anchors plugin
|
||||
md.use(anchors);
|
||||
|
||||
// Allow client sites to register their own plugins
|
||||
if (siteConfig.markdownPlugins) {
|
||||
siteConfig.markdownPlugins.forEach(plugin => {
|
||||
md.use(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
const html = md.render(source);
|
||||
|
||||
// Ensure fenced code blocks use Highlight.js hljs class
|
||||
// https://github.com/jonschlinkert/remarkable/issues/224
|
||||
return html.replace(/<pre><code>/g, '<pre><code class="hljs">');
|
||||
}
|
||||
|
||||
render() {
|
||||
const {siteConfig} = this.props;
|
||||
function Markdown(props) {
|
||||
const {siteConfig} = props;
|
||||
const highlight = Object.assign(
|
||||
{},
|
||||
{
|
||||
|
@ -119,14 +33,13 @@ class MarkdownBlock extends React.Component {
|
|||
<Helmet>
|
||||
<link rel="stylesheet" type="text/css" href={highlightThemeURL} />
|
||||
</Helmet>
|
||||
{this.content()}
|
||||
<div>{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MarkdownBlock.defaultProps = {
|
||||
Markdown.defaultProps = {
|
||||
siteConfig: {},
|
||||
};
|
||||
|
||||
export default MarkdownBlock;
|
||||
export default Markdown;
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
input#search_input_react {
|
||||
align-self: center;
|
||||
background-color: #c6cbd1;
|
||||
background-color: #f2f3f5;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: #fff;
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 20px;
|
||||
|
@ -44,26 +44,27 @@ input::placeholder {
|
|||
|
||||
/* Bottom border of each suggestion */
|
||||
.algolia-docsearch-suggestion {
|
||||
border-bottom-color: #3A3DD1;
|
||||
border-bottom-color: #3a3dd1;
|
||||
}
|
||||
/* Main category headers */
|
||||
.algolia-docsearch-suggestion--category-header {
|
||||
background-color: #4B54DE;
|
||||
background-color: #4b54de;
|
||||
}
|
||||
/* Highlighted search terms */
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
color: #3A33D1;
|
||||
color: #3a33d1;
|
||||
}
|
||||
/* Highligted search terms in the main category headers */
|
||||
.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight {
|
||||
background-color: #4D47D5;
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background-color: #4d47d5;
|
||||
}
|
||||
/* Currently selected suggestion */
|
||||
.aa-cursor .algolia-docsearch-suggestion--content {
|
||||
color: #272296;
|
||||
}
|
||||
.aa-cursor .algolia-docsearch-suggestion {
|
||||
background: #EBEBFB;
|
||||
background: #ebebfb;
|
||||
}
|
||||
|
||||
/* For bigger screens, when displaying results in two columns */
|
||||
|
@ -75,8 +76,8 @@ input::placeholder {
|
|||
/* Left column, with secondary category header */
|
||||
.algolia-docsearch-suggestion--subcategory-column {
|
||||
border-right-color: #7671df;
|
||||
background-color: #F2F2FF;
|
||||
color: #4E4726;
|
||||
background-color: #f2f2ff;
|
||||
color: #4e4726;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,12 +107,12 @@ input::placeholder {
|
|||
.searchbox__input {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition: box-shadow .4s ease, background .4s ease;
|
||||
transition: box-shadow .4s ease, background .4s ease;
|
||||
-webkit-transition: box-shadow 0.4s ease, background 0.4s ease;
|
||||
transition: box-shadow 0.4s ease, background 0.4s ease;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
box-shadow: inset 0 0 0 1px #CCCCCC;
|
||||
background: #FFFFFF !important;
|
||||
box-shadow: inset 0 0 0 1px #cccccc;
|
||||
background: #ffffff !important;
|
||||
padding: 0;
|
||||
padding-right: 26px;
|
||||
padding-left: 32px;
|
||||
|
@ -125,7 +126,10 @@ input::placeholder {
|
|||
appearance: none;
|
||||
}
|
||||
|
||||
.searchbox__input::-webkit-search-decoration, .searchbox__input::-webkit-search-cancel-button, .searchbox__input::-webkit-search-results-button, .searchbox__input::-webkit-search-results-decoration {
|
||||
.searchbox__input::-webkit-search-decoration,
|
||||
.searchbox__input::-webkit-search-cancel-button,
|
||||
.searchbox__input::-webkit-search-results-button,
|
||||
.searchbox__input::-webkit-search-results-decoration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -133,26 +137,27 @@ input::placeholder {
|
|||
box-shadow: inset 0 0 0 1px #b3b3b3;
|
||||
}
|
||||
|
||||
.searchbox__input:focus, .searchbox__input:active {
|
||||
.searchbox__input:focus,
|
||||
.searchbox__input:active {
|
||||
outline: 0;
|
||||
box-shadow: inset 0 0 0 1px #AAAAAA;
|
||||
background: #FFFFFF;
|
||||
box-shadow: inset 0 0 0 1px #aaaaaa;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.searchbox__input::-webkit-input-placeholder {
|
||||
color: #AAAAAA;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input::-moz-placeholder {
|
||||
color: #AAAAAA;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input:-ms-input-placeholder {
|
||||
color: #AAAAAA;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input::placeholder {
|
||||
color: #AAAAAA;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__submit {
|
||||
|
@ -184,7 +189,8 @@ input::placeholder {
|
|||
content: '';
|
||||
}
|
||||
|
||||
.searchbox__submit:hover, .searchbox__submit:active {
|
||||
.searchbox__submit:hover,
|
||||
.searchbox__submit:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -196,7 +202,7 @@ input::placeholder {
|
|||
width: 14px;
|
||||
height: 14px;
|
||||
vertical-align: middle;
|
||||
fill: #6D7E96;
|
||||
fill: #6d7e96;
|
||||
}
|
||||
|
||||
.searchbox__reset {
|
||||
|
@ -236,8 +242,8 @@ input::placeholder {
|
|||
display: block;
|
||||
-webkit-animation-name: sbx-reset-in;
|
||||
animation-name: sbx-reset-in;
|
||||
-webkit-animation-duration: .15s;
|
||||
animation-duration: .15s;
|
||||
-webkit-animation-duration: 0.15s;
|
||||
animation-duration: 0.15s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sbx-reset-in {
|
||||
|
@ -266,7 +272,6 @@ input::placeholder {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
@ -341,7 +346,7 @@ input::placeholder {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu [class^="ds-dataset-"] {
|
||||
.algolia-autocomplete .ds-dropdown-menu [class^='ds-dataset-'] {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
|
@ -368,13 +373,21 @@ input::placeholder {
|
|||
padding: 0.1em 0.05em;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl0 .algolia-docsearch-suggestion--highlight,
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl1 .algolia-docsearch-suggestion--highlight {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--category-header-lvl0
|
||||
.algolia-docsearch-suggestion--highlight,
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--category-header-lvl1
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
color: inherit;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--text
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
padding: 0 0 1px;
|
||||
background: inherit;
|
||||
box-shadow: inset 0 -2px 0 0 rgba(69, 142, 225, 0.8);
|
||||
|
@ -445,7 +458,9 @@ input::placeholder {
|
|||
right: 0;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column .algolia-docsearch-suggestion--highlight {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--subcategory-column
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -456,7 +471,7 @@ input::placeholder {
|
|||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--title {
|
||||
margin-bottom: 4px;
|
||||
color: #02060C;
|
||||
color: #02060c;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -465,7 +480,7 @@ input::placeholder {
|
|||
display: block;
|
||||
line-height: 1.2em;
|
||||
font-size: 0.85em;
|
||||
color: #63676D;
|
||||
color: #63676d;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
|
@ -478,7 +493,9 @@ input::placeholder {
|
|||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--no-results .algolia-docsearch-suggestion--text {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--no-results
|
||||
.algolia-docsearch-suggestion--text {
|
||||
color: #ffffff;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
@ -492,24 +509,31 @@ input::placeholder {
|
|||
font-size: 90%;
|
||||
border: none;
|
||||
color: #222222;
|
||||
background-color: #EBEBEB;
|
||||
background-color: #ebebeb;
|
||||
border-radius: 3px;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion
|
||||
code
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
|
||||
.algolia-docsearch-suggestion--category-header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--subcategory-column {
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary
|
||||
.algolia-docsearch-suggestion--subcategory-column {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-footer {
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
|
|
|
@ -10,7 +10,7 @@ const CSSExtractPlugin = require('mini-css-extract-plugin');
|
|||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const path = require('path');
|
||||
|
||||
const mdLoader = require.resolve('./loader/markdown');
|
||||
const mdLoader = require.resolve('./loaders/markdown');
|
||||
|
||||
const CSS_REGEX = /\.css$/;
|
||||
const CSS_MODULE_REGEX = /\.module\.css$/;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import toSlug from './toSlug';
|
||||
const toSlug = require('./toSlug');
|
||||
|
||||
export default function anchors(md) {
|
||||
function anchors(md) {
|
||||
const originalRender = md.renderer.rules.heading_close;
|
||||
|
||||
// eslint-disable-next-line
|
||||
|
@ -26,3 +26,5 @@ export default function anchors(md) {
|
|||
return originalRender(tokens, idx, options, env);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = anchors;
|
|
@ -5,9 +5,15 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const fm = require('front-matter');
|
||||
const {getOptions} = require('loader-utils');
|
||||
const path = require('path');
|
||||
const fm = require('front-matter');
|
||||
const Remarkable = require('remarkable');
|
||||
const hljs = require('highlight.js');
|
||||
const chalk = require('chalk');
|
||||
const escapeHtml = require('escape-html');
|
||||
|
||||
const anchors = require('./anchors');
|
||||
|
||||
module.exports = function(fileString) {
|
||||
const options = getOptions(this);
|
||||
|
@ -88,13 +94,64 @@ module.exports = function(fileString) {
|
|||
content = lines.join('\n');
|
||||
}
|
||||
|
||||
const md = new Remarkable({
|
||||
langPrefix: 'hljs css language-',
|
||||
highlight(str, rawLang) {
|
||||
// Default language fallback
|
||||
const defaultLang =
|
||||
siteConfig.highlight && siteConfig.highlight.defaultLang;
|
||||
|
||||
// No syntax highlighting
|
||||
if (rawLang === 'text' || (!rawLang && !defaultLang)) {
|
||||
return escapeHtml(str);
|
||||
}
|
||||
|
||||
// User's own hljs function to register additional languages
|
||||
if (siteConfig.highlight && siteConfig.highlight.hljs) {
|
||||
siteConfig.highlight.hljs(hljs);
|
||||
}
|
||||
|
||||
// Syntax highlighting
|
||||
const lang = rawLang.toLowerCase() || defaultLang;
|
||||
try {
|
||||
if (hljs.getLanguage(lang)) {
|
||||
return hljs.highlight(lang, str).value;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
chalk.yellow(
|
||||
`Highlight.js syntax highlighting for language "${lang}" is not supported.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
return hljs.highlightAuto(str).value;
|
||||
},
|
||||
html: true,
|
||||
linkify: true,
|
||||
});
|
||||
|
||||
// Register anchors plugin
|
||||
md.use(anchors);
|
||||
|
||||
// Allow client sites to register their own plugins
|
||||
if (siteConfig.markdownPlugins) {
|
||||
siteConfig.markdownPlugins.forEach(plugin => {
|
||||
md.use(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure fenced code blocks use Highlight.js hljs class
|
||||
// https://github.com/jonschlinkert/remarkable/issues/224
|
||||
const html = md
|
||||
.render(content)
|
||||
.replace(/<pre><code>/g, '<pre><code class="hljs">');
|
||||
/* Return a React component */
|
||||
return `
|
||||
import React from 'react';
|
||||
import Markdown from '@theme/Markdown';
|
||||
export default () => (
|
||||
<Markdown siteConfig={${JSON.stringify(siteConfig)}}>
|
||||
{${JSON.stringify(content)}}
|
||||
<div dangerouslySetInnerHTML={{__html: ${JSON.stringify(html)}}} />
|
||||
</Markdown>
|
||||
);`;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue