Skip to content

Commit 762b146

Browse files
axe312gerLekoArts
andauthored
MDXv2: remove default layouts and add support for pageQueries (#35983)
* WIP * WIP#2 * ensure loader actually picks up mdx file path and prepare query parsing * avoid issue with false-flag query duplicates * properly inject compiled MDX as children * fix: chunk names now should no more exceed max file path length * fix too long chunk names * fix: ensure page component validation uses clear path * fix: properly set clean path on all page component validations * test: add unit test for chunk name shortening * fix: improve chunk name shortening * fix: (re)support MDX pages automatically created out of /pages directory * chore: add comments to mdx-layout loader to explain what the AST transformations do * chore: remove @todo comment * refactor: convert pluginOptions into MdxPluginOptions instead of extending PluginOptions * refactor: rename __mdxPath to __contentFilePath * refactor: move page component path splitting logic to gatsby-core-utils * refactor: shorten chunk name to 60 characters and hash it * fix indentation * remove unused prop * tmp * feat: add caching to frontmatter extraction * feat: support page component URIs in page tree rendering * perf: ensure frontmatter is parsed as yaml only * build: downgrade acorn to version compatible with acorn-jsx and yarn-deduplicate * fix import * use murmurhash * change splitComponentPath to check for stricter than only ? * fix tests * silence non-page component warning * use parse-component-path helpers Co-authored-by: LekoArts <lekoarts@gmail.com>
1 parent c32adb0 commit 762b146

File tree

25 files changed

+428
-166
lines changed

25 files changed

+428
-166
lines changed

benchmarks/gabe-fs-mdx/gatsby-config.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ module.exports = {
1414
},
1515
{
1616
resolve: `gatsby-plugin-mdx`,
17-
options: {
18-
defaultLayouts: {
19-
articles: path.resolve(`./src/templates/blog-post.js`),
20-
},
21-
},
2217
},
2318
!process.env.CI && `gatsby-plugin-webpack-bundle-analyser-v2`,
2419
].filter(Boolean),

benchmarks/gabe-fs-mdx/gatsby-node.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const path = require("path")
2+
13
exports.createPages = async ({ graphql, actions }) => {
24
const { createPage } = actions
35

@@ -34,7 +36,9 @@ exports.createPages = async ({ graphql, actions }) => {
3436

3537
createPage({
3638
path: slug,
37-
component: parent.absolutePath,
39+
component: `${path.resolve(
40+
`./src/templates/blog-post.js`
41+
)}?__contentFilePath=${parent.absolutePath}`,
3842
context: {
3943
id,
4044
slug,

benchmarks/gabe-fs-mdx/src/templates/blog-post.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const Article = ({ children, pageContext }) => {
1515
}
1616

1717
export const pageQuery = graphql`
18-
query MdxQuery($id: String!) {
18+
query($id: String!) {
1919
mdx(id: { eq: $id }) {
2020
id
2121
frontmatter {

packages/gatsby-cli/src/reporter/loggers/ink/components/pageTree.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import React, { ReactElement, useContext } from "react"
33
import { Box, Text, BoxProps, Spacer } from "ink"
44
import path from "path"
5+
import { getPathToLayoutComponent } from "gatsby-core-utils"
56
import StoreStateContext from "../context"
67
import {
78
generatePageTree,
@@ -117,7 +118,8 @@ const ConnectedPageTree: React.FC = function ConnectedPageTree() {
117118
const componentWithPages = new Map<string, IComponentWithPageModes>()
118119

119120
for (const { componentPath, pages } of state.pageTree!.components.values()) {
120-
const pagesByMode = {
121+
const layoutComponent = getPathToLayoutComponent(componentPath)
122+
const pagesByMode = componentWithPages.get(layoutComponent) || {
121123
SSG: new Set<string>(),
122124
DSG: new Set<string>(),
123125
SSR: new Set<string>(),
@@ -128,8 +130,7 @@ const ConnectedPageTree: React.FC = function ConnectedPageTree() {
128130

129131
pagesByMode[gatsbyPage!.mode].add(pagePath)
130132
})
131-
132-
componentWithPages.set(componentPath, pagesByMode)
133+
componentWithPages.set(layoutComponent, pagesByMode)
133134
}
134135

135136
for (const {

packages/gatsby-cli/src/reporter/loggers/yurnalist/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
IComponentWithPageModes,
1818
} from "../../../util/generate-page-tree"
1919
import { IRenderPageArgs } from "../../types"
20+
import { getPathToLayoutComponent } from "gatsby-core-utils"
2021

2122
interface IYurnalistActivities {
2223
[activityId: string]: {
@@ -34,7 +35,9 @@ function generatePageTreeToConsole(
3435
const root = state.root
3536
const componentWithPages = new Map<string, IComponentWithPageModes>()
3637
for (const { componentPath, pages } of state.components.values()) {
37-
const pagesByMode = {
38+
const layoutComponent = getPathToLayoutComponent(componentPath)
39+
const relativePath = path.posix.relative(root, layoutComponent)
40+
const pagesByMode = componentWithPages.get(relativePath) || {
3841
SSG: new Set<string>(),
3942
DSG: new Set<string>(),
4043
SSR: new Set<string>(),
@@ -46,10 +49,7 @@ function generatePageTreeToConsole(
4649
pagesByMode[gatsbyPage!.mode].add(pagePath)
4750
})
4851

49-
componentWithPages.set(
50-
path.posix.relative(root, componentPath),
51-
pagesByMode
52-
)
52+
componentWithPages.set(relativePath, pagesByMode)
5353
}
5454

5555
for (const {

packages/gatsby-core-utils/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from "./service-lock"
1515
export * from "./site-metadata"
1616
export * from "./page-data"
1717
export * from "./page-html"
18+
export * from "./parse-component-path"
1819
export { listPlugins } from "./list-plugins"
1920
export { createFilePath } from "./filename-utils"
2021
export { readConfigFile, getConfigPath } from "./utils"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Since gatsby-plugin-mdx v4, we are using the resourceQuery feature
2+
// of webpack's loaders to inject a content file into a page component.
3+
// These helper functions are used to simplify working with these new
4+
// page component path URI's.
5+
6+
const CONTENT_FILE_PATH_QUERY = `?__contentFilePath=`
7+
8+
// Split the path component URI without using the expensive URI.parse()
9+
export const splitComponentPath = (componentPath: string): Array<string> => {
10+
// If the path does not include the contentFilePath query, we can assume its a regular path
11+
if (!componentPath.includes(CONTENT_FILE_PATH_QUERY)) {
12+
return [componentPath]
13+
}
14+
15+
const splitPath = componentPath.split(CONTENT_FILE_PATH_QUERY)
16+
17+
// We only support URI paths with the `?__contentFilePath=` parameter
18+
if (splitPath.length !== 2) {
19+
throw new Error(
20+
`The following page component must contain '${CONTENT_FILE_PATH_QUERY}':\n${componentPath}`
21+
)
22+
}
23+
24+
// Other URI parameters are not supported
25+
if (splitPath[1].includes(`&`)) {
26+
throw new Error(
27+
`You can not pass any other parameters to a page component URI as 'contentFilePath'. Remove the ampersand (&):\n${componentPath}`
28+
)
29+
}
30+
return splitPath
31+
}
32+
33+
// Get the path to the actual js page component
34+
export const getPathToLayoutComponent = (componentPath: string): string =>
35+
splitComponentPath(componentPath)[0]
36+
37+
// Get the path to the content file, falling back to the js component if no content file is given.
38+
// Pages directly created from `.mdx` files
39+
export const getPathToContentComponent = (componentPath: string): string => {
40+
const splitPath = splitComponentPath(componentPath)
41+
if (splitPath.length === 1) {
42+
return splitPath[0]
43+
}
44+
return splitPath[1]
45+
}

packages/gatsby-plugin-mdx/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@
6161
"rehype-infer-description-meta": "^1.0.1",
6262
"unified": "^10.1.2",
6363
"unist-util-visit": "^4.1.0",
64-
"vfile": "^5.3.2"
64+
"vfile": "^5.3.2",
65+
"acorn": "^7.4.1",
66+
"acorn-jsx": "^5.3.2",
67+
"astring": "^1.8.3",
68+
"estree-util-build-jsx": "^2.1.0"
6569
},
6670
"devDependencies": {
6771
"@babel/cli": "^7.17.10",
@@ -73,6 +77,7 @@
7377
},
7478
"peerDependencies": {
7579
"@mdx-js/react": "^2.0.0",
80+
"@types/estree": "^0.0.50",
7681
"gatsby": "^4.0.0-next",
7782
"gatsby-source-filesystem": "^4.0.0-next",
7883
"loader-utils": "^3.2.0",

packages/gatsby-plugin-mdx/src/compile-mdx.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import deepmerge from "deepmerge"
2-
import type { NodePluginArgs } from "gatsby"
2+
import type { NodePluginArgs, PluginOptions } from "gatsby"
33
import type { ProcessorOptions } from "@mdx-js/mdx"
44
import type { IFileNode, IMdxMetadata, IMdxNode } from "./types"
55

@@ -77,7 +77,7 @@ export const compileMDXWithCustomOptions = async ({
7777
cache,
7878
mdxNode,
7979
}: {
80-
pluginOptions: IMdxPluginOptions
80+
pluginOptions: PluginOptions
8181
customOptions: Partial<IMdxPluginOptions>
8282
getNode: NodePluginArgs["getNode"]
8383
getNodesByType: NodePluginArgs["getNodesByType"]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import grayMatter from "gray-matter"
2+
3+
const cacheMap = new Map()
4+
5+
export function parseFrontmatter(
6+
cacheKey: string,
7+
source: string
8+
): { body: string; frontmatter: { [key: string]: unknown } } {
9+
if (cacheMap.has(cacheKey)) {
10+
return cacheMap.get(cacheKey)
11+
}
12+
13+
const { content, data } = grayMatter(source, {
14+
language: `yaml`,
15+
// Disable JS(ON) frontmatter parsing.
16+
// See: https://github.com/gatsbyjs/gatsby/pull/35830
17+
engines: {
18+
js: () => {
19+
return {}
20+
},
21+
javascript: () => {
22+
return {}
23+
},
24+
},
25+
})
26+
cacheMap.set(cacheKey, { content, data })
27+
28+
return { body: content, frontmatter: data }
29+
}

0 commit comments

Comments
 (0)