perf(mdx-loader): cache mdx/remark compiler instances (#4997)

* (mdx-loader) only create mdx compiler once per webpack config

* type fixes

* fix path

* remove assertion

* docs: add missing Tab/TabItem imports

* fixup

Co-authored-by: slorber <lorber.sebastien@gmail.com>
Co-authored-by: Josh-Cena <sidachen2003@gmail.com>
This commit is contained in:
Lenz Weber-Tronic 2022-03-31 09:42:57 +02:00 committed by GitHub
parent bb55586c20
commit 949a72e6a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 45 deletions

View file

@ -10,8 +10,7 @@ declare module '@mdx-js/mdx' {
import type {Processor} from 'unified'; import type {Processor} from 'unified';
import type {RemarkOrRehypePlugin} from '@docusaurus/mdx-loader'; import type {RemarkOrRehypePlugin} from '@docusaurus/mdx-loader';
namespace mdx { export interface Options {
interface Options {
filepath?: string; filepath?: string;
skipExport?: boolean; skipExport?: boolean;
wrapExport?: string; wrapExport?: string;
@ -19,10 +18,9 @@ declare module '@mdx-js/mdx' {
rehypePlugins?: RemarkOrRehypePlugin[]; rehypePlugins?: RemarkOrRehypePlugin[];
} }
function sync(content: string, options?: Options): string; export function sync(content: string, options?: Options): string;
function createMdxAstCompiler(options?: Options): Processor; export function createMdxAstCompiler(options?: Options): Processor;
function createCompiler(options?: Options): Processor; export function createCompiler(options?: Options): Processor;
}
export default function mdx( export default function mdx(
content: string, content: string,
options?: mdx.Options, options?: mdx.Options,

View file

@ -6,7 +6,7 @@
*/ */
import fs from 'fs-extra'; import fs from 'fs-extra';
import mdx from '@mdx-js/mdx'; import {createCompiler} from '@mdx-js/mdx';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import emoji from 'remark-emoji'; import emoji from 'remark-emoji';
import { import {
@ -23,11 +23,18 @@ import transformImage from './remark/transformImage';
import transformLinks from './remark/transformLinks'; import transformLinks from './remark/transformLinks';
import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
import type {LoaderContext} from 'webpack'; import type {LoaderContext} from 'webpack';
import type {Processor} from 'unified';
const { const {
loaders: {inlineMarkdownImageFileLoader}, loaders: {inlineMarkdownImageFileLoader},
} = getFileLoaderUtils(); } = getFileLoaderUtils();
const pragma = `
/* @jsxRuntime classic */
/* @jsx mdx */
/* @jsxFrag mdx.Fragment */
`;
const DEFAULT_OPTIONS: MDXOptions = { const DEFAULT_OPTIONS: MDXOptions = {
rehypePlugins: [], rehypePlugins: [],
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc], remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
@ -35,6 +42,8 @@ const DEFAULT_OPTIONS: MDXOptions = {
beforeDefaultRehypePlugins: [], beforeDefaultRehypePlugins: [],
}; };
const compilerCache = new Map<string | Options, [Processor, Options]>();
type Options = MDXOptions & { type Options = MDXOptions & {
staticDirs: string[]; staticDirs: string[];
siteDir: string; siteDir: string;
@ -124,6 +133,7 @@ export default async function mdxLoader(
const hasFrontMatter = Object.keys(frontMatter).length > 0; const hasFrontMatter = Object.keys(frontMatter).length > 0;
if (!compilerCache.has(this.query)) {
const options: Options = { const options: Options = {
...reqOptions, ...reqOptions,
remarkPlugins: [ remarkPlugins: [
@ -150,12 +160,20 @@ export default async function mdxLoader(
...DEFAULT_OPTIONS.rehypePlugins, ...DEFAULT_OPTIONS.rehypePlugins,
...(reqOptions.rehypePlugins ?? []), ...(reqOptions.rehypePlugins ?? []),
], ],
filepath: filePath,
}; };
compilerCache.set(this.query, [createCompiler(options), options]);
}
const [compiler, options] = compilerCache.get(this.query)!;
let result: string; let result: string;
try { try {
result = await mdx(content, options); result = await compiler
.process({
contents: content,
path: this.resourcePath,
})
.then((res) => res.toString());
} catch (err) { } catch (err) {
return callback(err as Error); return callback(err as Error);
} }
@ -214,6 +232,7 @@ ${assets ? `export const assets = ${createAssetsExportCode(assets)};` : ''}
`; `;
const code = ` const code = `
${pragma}
import React from 'react'; import React from 'react';
import { mdx } from '@mdx-js/react'; import { mdx } from '@mdx-js/react';

View file

@ -6,7 +6,7 @@
*/ */
import type {Code, Content, Literal} from 'mdast'; import type {Code, Content, Literal} from 'mdast';
import type {Plugin, Transformer} from 'unified'; import type {Plugin} from 'unified';
import type {Node, Parent} from 'unist'; import type {Node, Parent} from 'unist';
import visit from 'unist-util-visit'; import visit from 'unist-util-visit';
import npmToYarn from 'npm-to-yarn'; import npmToYarn from 'npm-to-yarn';
@ -61,9 +61,9 @@ const nodeForImport: Literal = {
const plugin: Plugin<[PluginOptions?]> = (options = {}) => { const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
const {sync = false} = options; const {sync = false} = options;
return (root) => {
let transformed = false; let transformed = false;
let alreadyImported = false; let alreadyImported = false;
const transformer: Transformer = (root) => {
visit(root, (node: Node) => { visit(root, (node: Node) => {
if (isImport(node) && node.value.includes('@theme/Tabs')) { if (isImport(node) && node.value.includes('@theme/Tabs')) {
alreadyImported = true; alreadyImported = true;
@ -87,7 +87,6 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
(root as Parent).children.unshift(nodeForImport); (root as Parent).children.unshift(nodeForImport);
} }
}; };
return transformer;
}; };
// To continue supporting `require('npm2yarn')` without the `.default` ㄟ(▔,▔)ㄏ // To continue supporting `require('npm2yarn')` without the `.default` ㄟ(▔,▔)ㄏ