Skip to content

Commit 9e02abe

Browse files
LBLaurie Barthpvdz
authored
perf(gatsby-plugin-mdx): performance changes (#26004)
Re-submit of #24595 Drops a babel step This Babel step was used to get exports and remark header but we can use the mdast for this purpose, just like for imports. > This cuts off 20 to 30% of the total runtime of a baseline mdx benchmark! Co-authored-by: Laurie Barth <laurie@LauriesrkLaptop.fios-router.home> Co-authored-by: Peter van der Zee <github-public@qfox.nl>
1 parent 33aff39 commit 9e02abe

File tree

6 files changed

+99
-73
lines changed

6 files changed

+99
-73
lines changed

packages/gatsby-plugin-mdx/gatsby/on-create-node.js

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ const babel = require(`@babel/core`)
44
const { createContentDigest } = require(`gatsby-core-utils`)
55

66
const defaultOptions = require(`../utils/default-options`)
7-
const createMDXNode = require(`../utils/create-mdx-node`)
7+
const createMDXNodeWithScope = require(`../utils/mdx-node-with-scope`)
88
const { MDX_SCOPES_LOCATION } = require(`../constants`)
9-
const { findImports } = require(`../utils/gen-mdx`)
109

1110
const contentDigest = val => createContentDigest(val)
1211

@@ -46,18 +45,14 @@ module.exports = async (
4645

4746
const content = await loadNodeContent(node)
4847

49-
const mdxNode = await createMDXNode({
48+
const {
49+
mdxNode,
50+
scopeIdentifiers,
51+
scopeImports,
52+
} = await createMDXNodeWithScope({
5053
id: createNodeId(`${node.id} >>> Mdx`),
5154
node,
5255
content,
53-
})
54-
55-
createNode(mdxNode)
56-
createParentChildLink({ parent: node, child: mdxNode })
57-
58-
// write scope files into .cache for later consumption
59-
const { scopeImports, scopeIdentifiers } = await findImports({
60-
node: mdxNode,
6156
getNode,
6257
getNodes,
6358
reporter,
@@ -69,6 +64,10 @@ module.exports = async (
6964
createNodeId,
7065
...helpers,
7166
})
67+
68+
createNode(mdxNode)
69+
createParentChildLink({ parent: node, child: mdxNode })
70+
7271
await cacheScope({
7372
cache,
7473
scopeIdentifiers,

packages/gatsby-plugin-mdx/loaders/mdx-loader.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const debugMore = require(`debug`)(`gatsby-plugin-mdx-info:mdx-loader`)
2525

2626
const genMdx = require(`../utils/gen-mdx`)
2727
const withDefaultOptions = require(`../utils/default-options`)
28-
const createMDXNode = require(`../utils/create-mdx-node`)
28+
const createMDXNodeWithScope = require(`../utils/mdx-node-with-scope`)
2929
const { createFileNode } = require(`../utils/create-fake-file-node`)
3030

3131
const DEFAULT_OPTIONS = {
@@ -94,6 +94,7 @@ module.exports = async function (content) {
9494
const {
9595
getNode: rawGetNode,
9696
getNodes,
97+
getNodesByType,
9798
reporter,
9899
cache,
99100
pathPrefix,
@@ -121,11 +122,15 @@ module.exports = async function (content) {
121122

122123
let mdxNode
123124
try {
124-
mdxNode = await createMDXNode({
125+
// This node attempts to break the chicken-egg problem, where parsing mdx
126+
// allows for custom plugins, which can receive a mdx node
127+
;({ mdxNode } = await createMDXNodeWithScope({
125128
id: `fakeNodeIdMDXFileABugIfYouSeeThis`,
126129
node: fileNode,
127130
content,
128-
})
131+
options,
132+
getNodesByType,
133+
}))
129134
} catch (e) {
130135
return callback(e)
131136
}
@@ -192,6 +197,7 @@ ${contentWithoutFrontmatter}`
192197
node: { ...mdxNode, rawBody: code },
193198
getNode,
194199
getNodes,
200+
getNodesByType,
195201
reporter,
196202
cache,
197203
pathPrefix,

packages/gatsby-plugin-mdx/loaders/mdx-loader.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ array: [1,2,3]
1616
)`,
1717
namedExports: `export const meta = {author: "chris"}`,
1818
body: `# Some title
19-
19+
2020
a bit of a paragraph
21-
21+
2222
some content`,
2323
}
2424

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,17 @@
1-
const { createContentDigest } = require(`gatsby-core-utils`)
1+
const withDefaultOptions = require(`../utils/default-options`)
2+
const { getNodesByType } = require(`gatsby/dist/redux/nodes.js`)
3+
const createMdxNodeWithScope = require(`../utils/mdx-node-with-scope`)
24

3-
const mdx = require(`../utils/mdx`)
4-
const extractExports = require(`../utils/extract-exports`)
5-
6-
module.exports = async ({ id, node, content }) => {
7-
let code
8-
try {
9-
code = await mdx(content)
10-
} catch (e) {
11-
// add the path of the file to simplify debugging error messages
12-
e.message += `${node.absolutePath}: ${e.message}`
13-
throw e
14-
}
15-
16-
// extract all the exports
17-
const { frontmatter, ...nodeExports } = extractExports(code)
18-
19-
const mdxNode = {
5+
async function createMdxNodeLegacy({ id, node, content } = {}) {
6+
const nodeWithScope = await createMdxNodeWithScope({
207
id,
21-
children: [],
22-
parent: node.id,
23-
internal: {
24-
content: content,
25-
type: `Mdx`,
26-
},
27-
}
28-
29-
mdxNode.frontmatter = {
30-
title: ``, // always include a title
31-
...frontmatter,
32-
}
33-
34-
mdxNode.excerpt = frontmatter.excerpt
35-
mdxNode.exports = nodeExports
36-
mdxNode.rawBody = content
37-
38-
// Add path to the markdown file path
39-
if (node.internal.type === `File`) {
40-
mdxNode.fileAbsolutePath = node.absolutePath
41-
}
42-
43-
mdxNode.internal.contentDigest = createContentDigest(mdxNode)
44-
45-
return mdxNode
8+
node,
9+
content,
10+
getNodesByType,
11+
options: withDefaultOptions({ plugins: [] }),
12+
})
13+
return nodeWithScope.mdxNode
4614
}
15+
16+
// This function is deprecated in favor of createMDXNodeWithScope and slated to be dropped in v3
17+
module.exports = createMdxNodeLegacy

packages/gatsby-plugin-mdx/utils/gen-mdx.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,10 @@ ${code}`
194194
module.exports = genMDX // Legacy API, drop in v3 in favor of named export
195195
module.exports.genMDX = genMDX
196196

197-
async function findImports({
197+
async function findImportsExports({
198198
node,
199+
rawInput,
200+
absolutePath = null,
199201
options,
200202
getNode,
201203
getNodes,
@@ -205,7 +207,7 @@ async function findImports({
205207
pathPrefix,
206208
...helpers
207209
}) {
208-
const { content } = grayMatter(node.rawBody)
210+
const { data: frontmatter, content } = grayMatter(rawInput)
209211

210212
const gatsbyRemarkPluginsAsremarkPlugins = await getSourcePluginsAsRemarkPlugins(
211213
{
@@ -226,7 +228,7 @@ async function findImports({
226228
)
227229

228230
const compilerOptions = {
229-
filepath: node.fileAbsolutePath,
231+
filepath: absolutePath,
230232
...options,
231233
remarkPlugins: [
232234
...options.remarkPlugins,
@@ -236,8 +238,8 @@ async function findImports({
236238
const compiler = mdx.createCompiler(compilerOptions)
237239

238240
const fileOpts = { contents: content }
239-
if (node.fileAbsolutePath) {
240-
fileOpts.path = node.fileAbsolutePath
241+
if (absolutePath) {
242+
fileOpts.path = absolutePath
241243
}
242244

243245
const mdast = await compiler.parse(fileOpts)
@@ -246,16 +248,17 @@ async function findImports({
246248
// we don't need to dedupe the symbols here.
247249
const identifiers = []
248250
const imports = []
251+
const exports = []
249252

250253
mdast.children.forEach(node => {
251-
if (node.type !== `import`) return
252-
253-
const importCode = node.value
254-
255-
imports.push(importCode)
256-
257-
const bindings = parseImportBindings(importCode)
258-
identifiers.push(...bindings)
254+
if (node.type === `import`) {
255+
const importCode = node.value
256+
imports.push(importCode)
257+
const bindings = parseImportBindings(importCode)
258+
identifiers.push(...bindings)
259+
} else if (node.type === `export`) {
260+
exports.push(node.value)
261+
}
259262
})
260263

261264
if (!identifiers.includes(`React`)) {
@@ -264,9 +267,11 @@ async function findImports({
264267
}
265268

266269
return {
270+
frontmatter,
267271
scopeImports: imports,
272+
scopeExports: exports,
268273
scopeIdentifiers: identifiers,
269274
}
270275
}
271276

272-
module.exports.findImports = findImports
277+
module.exports.findImportsExports = findImportsExports
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const { createContentDigest } = require(`gatsby-core-utils`)
2+
3+
const { findImportsExports } = require(`../utils/gen-mdx`)
4+
5+
async function createMdxNodeWithScope({ id, node, content, ...helpers }) {
6+
const {
7+
frontmatter,
8+
scopeImports,
9+
scopeExports,
10+
scopeIdentifiers,
11+
} = await findImportsExports({
12+
node,
13+
rawInput: content,
14+
absolutePath: node.absolutePath,
15+
...helpers,
16+
})
17+
18+
const mdxNode = {
19+
id,
20+
children: [],
21+
parent: node.id,
22+
internal: {
23+
content,
24+
type: `Mdx`,
25+
},
26+
excerpt: frontmatter.excerpt,
27+
exports: scopeExports,
28+
rawBody: content,
29+
frontmatter: {
30+
title: ``, // always include a title
31+
...frontmatter,
32+
},
33+
}
34+
35+
// Add path to the markdown file path
36+
if (node.internal.type === `File`) {
37+
mdxNode.fileAbsolutePath = node.absolutePath
38+
}
39+
40+
mdxNode.internal.contentDigest = createContentDigest(mdxNode)
41+
42+
return { mdxNode, scopeIdentifiers, scopeImports }
43+
}
44+
45+
module.exports = createMdxNodeWithScope

0 commit comments

Comments
 (0)