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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 16 commits into from
Mar 31, 2022
66 changes: 42 additions & 24 deletions packages/docusaurus-mdx-loader/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

const {readFile} = require('fs-extra');
const mdx = require('@mdx-js/mdx');
const {createCompiler} = require('@mdx-js/mdx');
const emoji = require('remark-emoji');
const {
parseFrontMatter,
Expand All @@ -19,11 +19,19 @@ const unwrapMdxCodeBlocks = require('./remark/unwrapMdxCodeBlocks');
const transformImage = require('./remark/transformImage');
const transformLinks = require('./remark/transformLinks');

const pragma = `
/* @jsxRuntime classic */
/* @jsx mdx */
/* @jsxFrag mdx.Fragment */
`;

const DEFAULT_OPTIONS = {
rehypePlugins: [],
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
};

const compilerCache = new Map();

module.exports = async function docusaurusMdxLoader(fileString) {
const callback = this.async();

Expand All @@ -37,33 +45,41 @@ module.exports = async function docusaurusMdxLoader(fileString) {

const hasFrontMatter = Object.keys(frontMatter).length > 0;

const options = {
...reqOptions,
remarkPlugins: [
...(reqOptions.beforeDefaultRemarkPlugins || []),
...DEFAULT_OPTIONS.remarkPlugins,
[
transformImage,
{staticDir: reqOptions.staticDir, filePath: this.resourcePath},
if (!compilerCache.has(this.query)) {
const options = {
...reqOptions,
remarkPlugins: [
...(reqOptions.beforeDefaultRemarkPlugins || []),
...DEFAULT_OPTIONS.remarkPlugins,
[
transformImage,
{staticDir: reqOptions.staticDir, filePath: this.resourcePath},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this.resourcePath here makes me think this PR is not good enough.

Our remark plugins need to be able to access current file path to check if relative image/asset links are valid etc.

Copy link
Collaborator

@slorber slorber Jun 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently we may be able to access it thanks to the transform(node,vfile) and vfile.history[0]: https://github.com/vfile/vfile#vfilehistory

Will see how to refactor the PR with it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I just took another look at https://github.com/mdx-js/mdx/pull/1468/files and they completely removed the filePath: this.resourcePath from the options object and only used it as parameter in the second argument of compiler.process - so it seems to be the accepted standard way to use that instead of accessing filePath from the options object.

],
[
transformLinks,
{staticDir: reqOptions.staticDir, filePath: this.resourcePath},
],
...(reqOptions.remarkPlugins || []),
],
[
transformLinks,
{staticDir: reqOptions.staticDir, filePath: this.resourcePath},
rehypePlugins: [
...(reqOptions.beforeDefaultRehypePlugins || []),
...DEFAULT_OPTIONS.rehypePlugins,

...(reqOptions.rehypePlugins || []),
],
...(reqOptions.remarkPlugins || []),
],
rehypePlugins: [
...(reqOptions.beforeDefaultRehypePlugins || []),
...DEFAULT_OPTIONS.rehypePlugins,

...(reqOptions.rehypePlugins || []),
],
filepath: this.resourcePath,
};
let result;
filepath: this.resourcePath,
};
compilerCache.set(this.query, [createCompiler(options), options]);
}

const [compiler, options] = compilerCache.get(this.query);

let result;
try {
result = await mdx(content, options);
result = await compiler.process({
contents: content,
path: this.resourcePath,
});
} catch (err) {
return callback(err);
}
Expand Down Expand Up @@ -95,7 +111,9 @@ module.exports = async function docusaurusMdxLoader(fileString) {
return callback(new Error(`Front matter is forbidden in this file`));
}
}

const code = `
${pragma}
import React from 'react';
import { mdx } from '@mdx-js/react';

Expand Down