Skip to content

Commit

Permalink
MDX v2: Support FS routes (#36118)
Browse files Browse the repository at this point in the history
* add feature to flags

* add contentFilePath to node.internal

* add contentFilePath to query and change component in createPage

* update snapshots

* half-broken wip

* fix weird error :D

* remove export query param better

* use better regex in replace

* typo

* add test
  • Loading branch information
LekoArts authored Jul 25, 2022
1 parent 5fda11f commit f262e97
Show file tree
Hide file tree
Showing 19 changed files with 301 additions and 52 deletions.
14 changes: 6 additions & 8 deletions packages/gatsby-core-utils/src/parse-component-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,19 @@ export const splitComponentPath = (componentPath: string): Array<string> => {
return [componentPath]
}

const splitPath = componentPath.split(CONTENT_FILE_PATH_QUERY)
const cleanedComponentPath = componentPath.replace(
/&export=(default|head)$/,
``
)
const splitPath = cleanedComponentPath.split(CONTENT_FILE_PATH_QUERY)

// We only support URI paths with the `?__contentFilePath=` parameter
if (splitPath.length !== 2) {
throw new Error(
`The following page component must contain '${CONTENT_FILE_PATH_QUERY}':\n${componentPath}`
`The following page component must contain '${CONTENT_FILE_PATH_QUERY}':\n${cleanedComponentPath}`
)
}

// Other URI parameters are not supported
if (splitPath[1].includes(`&`)) {
throw new Error(
`You can not pass any other parameters to a page component URI as 'contentFilePath'. Remove the ampersand (&):\n${componentPath}`
)
}
return splitPath
}

Expand Down
3 changes: 2 additions & 1 deletion packages/gatsby-plugin-mdx/src/gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const onCreateWebpackConfig: GatsbyNode["onCreateWebpackConfig"] =
},
{
test: /\.[tj]sx?$/,
resourceQuery: /__contentFilePath=.+\.mdx?$/,
resourceQuery: /__contentFilePath=.+\.mdx?(&export=.*)?$/,
use: [
loaders.js(),
{
Expand Down Expand Up @@ -281,6 +281,7 @@ export const onCreateNode: GatsbyNode<FileSystemNode>["onCreateNode"] = async ({
internal: {
type: `Mdx`,
contentDigest: node.internal.contentDigest,
contentFilePath: node.absolutePath,
},
body,
frontmatter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query from the route with minimal length`, async () => {
Expand All @@ -53,7 +55,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allP{nodes{n,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allP{nodes{n,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query from the route with a prefix variant 1`, async () => {
Expand All @@ -70,7 +74,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query from the route with a prefix variant 2`, async () => {
Expand All @@ -87,7 +93,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query from the route with a prefix variant 3`, async () => {
Expand All @@ -104,7 +112,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query from the route with a postfix`, async () => {
Expand All @@ -121,7 +131,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query with multiple entries`, async () => {
Expand All @@ -138,7 +150,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,color,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,color,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query with multiple entries and different delimiters variant 1`, async () => {
Expand All @@ -155,7 +169,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,color,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,color,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query with multiple entries and different delimiters variant 1`, async () => {
Expand All @@ -172,7 +188,9 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,color,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,color,id,internal{contentFilePath}}}}"`
)
})

it(`will create a basic query with multiple entries and different delimiters variant 1`, async () => {
Expand All @@ -189,6 +207,8 @@ describe(`collectionExtractQueryString`, () => {
reporter
)

expect(query).toMatchInlineSnapshot(`"{allProduct{nodes{name,color,id}}}"`)
expect(query).toMatchInlineSnapshot(
`"{allProduct{nodes{name,color,id,internal{contentFilePath}}}}"`
)
})
})
76 changes: 56 additions & 20 deletions packages/gatsby-plugin-page-creator/src/__tests__/extract-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}.js`)
)
).toBe(`{allThing{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,internal{contentFilePath}}}}"`
)
})

it(`handles lowercased model name`, () => {
Expand All @@ -24,7 +26,9 @@ describe(`extract query`, () => {
`contentfulType`,
compatiblePath(`/foo/{contentfulType.id}.js`)
)
).toBe(`{allContentfulType{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allContentfulType{nodes{id,internal{contentFilePath}}}}"`
)
})

it(`handles model name with underscore`, () => {
Expand All @@ -33,7 +37,9 @@ describe(`extract query`, () => {
`_customType`,
compatiblePath(`/foo/{_customType.id}.js`)
)
).toBe(`{allCustomType{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allCustomType{nodes{id,internal{contentFilePath}}}}"`
)
})

it(`handles model name with number`, () => {
Expand All @@ -42,7 +48,9 @@ describe(`extract query`, () => {
`Type123`,
compatiblePath(`/foo/{Type123.id}.js`)
)
).toBe(`{allType123{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allType123{nodes{id,internal{contentFilePath}}}}"`
)
})

it(`handles fields with number or underscore`, () => {
Expand All @@ -51,13 +59,17 @@ describe(`extract query`, () => {
`_type123`,
compatiblePath(`/foo/{_type123.field123}.js`)
)
).toBe(`{allType123{nodes{field123,id}}}`)
).toMatchInlineSnapshot(
`"{allType123{nodes{field123,id,internal{contentFilePath}}}}"`
)
expect(
generateQueryFromString(
`_type123`,
compatiblePath(`/foo/{_type123._field123}.js`)
)
).toBe(`{allType123{nodes{_field123,id}}}`)
).toMatchInlineSnapshot(
`"{allType123{nodes{_field123,id,internal{contentFilePath}}}}"`
)
})

it(`works with different file extensions`, () => {
Expand All @@ -66,7 +78,9 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}.tsx`)
)
).toBe(`{allThing{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,internal{contentFilePath}}}}"`
)
})
})

Expand All @@ -77,7 +91,9 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}.js`)
)
).toBe(`{allThing{nodes{id}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,internal{contentFilePath}}}}"`
)
})

it(`always queries id`, () => {
Expand All @@ -86,7 +102,9 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.baz}.js`)
)
).toBe(`{allThing{nodes{baz,id}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{baz,id,internal{contentFilePath}}}}"`
)
})

it(`multiple nodes`, () => {
Expand All @@ -95,13 +113,17 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}/{Thing.name}.js`)
)
).toBe(`{allThing{nodes{id,name}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,name,internal{contentFilePath}}}}"`
)
expect(
generateQueryFromString(
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}-{Thing.name}.js`)
)
).toBe(`{allThing{nodes{id,name}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,name,internal{contentFilePath}}}}"`
)
})

it(`nested nodes`, () => {
Expand All @@ -110,7 +132,9 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}/{Thing.fields__name}.js`)
)
).toBe(`{allThing{nodes{id,fields{name}}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,fields{name},internal{contentFilePath}}}}"`
)
})

it(`multiple nested nodes`, () => {
Expand All @@ -121,7 +145,9 @@ describe(`extract query`, () => {
`/foo/bar/{thing.fields__name}/{thing.fields__description}.js`
)
)
).toBe(`{allThing{nodes{fields{name},fields{description},id}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{fields{name},fields{description},id,internal{contentFilePath}}}}"`
)
})

it(`deeply nested nodes`, () => {
Expand All @@ -130,15 +156,19 @@ describe(`extract query`, () => {
`Thing`,
compatiblePath(`/foo/bar/{Thing.id}/{Thing.fields__name__thing}.js`)
)
).toBe(`{allThing{nodes{id,fields{name{thing}}}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,fields{name{thing}},internal{contentFilePath}}}}"`
)
expect(
generateQueryFromString(
`customType`,
compatiblePath(
`/foo/bar/{customType.id}/{customType.fields__name__thing}.js`
)
)
).toBe(`{allCustomType{nodes{id,fields{name{thing}}}}}`)
).toMatchInlineSnapshot(
`"{allCustomType{nodes{id,fields{name{thing}},internal{contentFilePath}}}}"`
)
})

it(`deeply nested nodes with prefixes`, () => {
Expand All @@ -149,7 +179,9 @@ describe(`extract query`, () => {
`/foo/bar/prefix-{Thing.id}/another-prefix_{Thing.fields__name__thing}.js`
)
)
).toBe(`{allThing{nodes{id,fields{name{thing}}}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,fields{name{thing}},internal{contentFilePath}}}}"`
)
})

it(`deeply nested nodes with postfixes`, () => {
Expand All @@ -160,7 +192,9 @@ describe(`extract query`, () => {
`/foo/bar/{Thing.id}-postfix/{Thing.fields__name__thing}_another-postfix.js`
)
)
).toBe(`{allThing{nodes{id,fields{name{thing}}}}}`)
).toMatchInlineSnapshot(
`"{allThing{nodes{id,fields{name{thing}},internal{contentFilePath}}}}"`
)
})

it(`supports graphql unions`, () => {
Expand All @@ -171,7 +205,9 @@ describe(`extract query`, () => {
`/foo/bar/{UnionQuery.id}/{UnionQuery.parent__(File)__relativePath}.js`
)
)
).toBe(`{allUnionQuery{nodes{id,parent{... on File{relativePath}}}}}`)
).toMatchInlineSnapshot(
`"{allUnionQuery{nodes{id,parent{... on File{relativePath}},internal{contentFilePath}}}}"`
)
})

it(`supports nested graphql unions`, () => {
Expand All @@ -182,8 +218,8 @@ describe(`extract query`, () => {
`/foo/bar/{UnionQuery.id}/{UnionQuery.parent__(File)__parent__(Bar)__relativePath}.js`
)
)
).toBe(
`{allUnionQuery{nodes{id,parent{... on File{parent{... on Bar{relativePath}}}}}}}`
).toMatchInlineSnapshot(
`"{allUnionQuery{nodes{id,parent{... on File{parent{... on Bar{relativePath}}}},internal{contentFilePath}}}}"`
)
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ ${errors.map(error => error.message).join(`\n`)}`.trim(),
// the watcher will use this data to delete the pages if the query changes significantly.
const paths: Array<string> = []
nodes.forEach((node: Record<string, Record<string, unknown>>) => {
const contentFilePath = node.internal?.contentFilePath
// URL path for the component and node
const { derivedPath, errors } = derivePath(
filePath,
Expand All @@ -141,10 +142,14 @@ ${errors.map(error => error.message).join(`\n`)}`.trim(),

const modifiedPath = applyTrailingSlashOption(path, trailingSlash)

const componentPath = contentFilePath
? `${absolutePath}?__contentFilePath=${contentFilePath}`
: absolutePath

actions.createPage({
path: modifiedPath,
matchPath,
component: absolutePath,
component: componentPath,
context: {
...nodeParams,
__params: params,
Expand Down
Loading

0 comments on commit f262e97

Please sign in to comment.