From 34df27a3bd278f49a9b81cdb59146a79e8841669 Mon Sep 17 00:00:00 2001 From: Lennart Date: Tue, 13 Sep 2022 07:54:09 +0200 Subject: [PATCH] fix(gatsby-plugin-mdx): Add React import when not defined (#36595) --- .../src/__tests__/gatsby-layout-loader.ts | 12 ++++--- .../src/gatsby-layout-loader.ts | 32 ++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-plugin-mdx/src/__tests__/gatsby-layout-loader.ts b/packages/gatsby-plugin-mdx/src/__tests__/gatsby-layout-loader.ts index 546051f09e684..a80a348a07cce 100644 --- a/packages/gatsby-plugin-mdx/src/__tests__/gatsby-layout-loader.ts +++ b/packages/gatsby-plugin-mdx/src/__tests__/gatsby-layout-loader.ts @@ -71,7 +71,8 @@ describe(`webpack loader: loads and injects Gatsby layout component`, () => { it(`MDX without layout`, async () => { await expect(parseMDX(exampleMDX)).resolves.toMatchInlineSnapshot(` - "import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; + "import React from \\"react\\"; + import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \\"react/jsx-runtime\\"; function MDXContent(props = {}) { const {wrapper: MDXLayout} = props.components || ({}); @@ -109,7 +110,8 @@ describe(`webpack loader: loads and injects Gatsby layout component`, () => { `import TemplateComponent from "./some-path"\n\n${exampleMDX}\n\nexport default TemplateComponent` ) ).resolves.toMatchInlineSnapshot(` - "import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; + "import React from \\"react\\"; + import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \\"react/jsx-runtime\\"; import TemplateComponent from \\"./some-path\\"; const MDXLayout = TemplateComponent; @@ -146,7 +148,8 @@ describe(`webpack loader: loads and injects Gatsby layout component`, () => { await expect( parseMDX(`${exampleMDX}\n\nexport {default} from "./some-path"`) ).resolves.toMatchInlineSnapshot(` - "import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; + "import React from \\"react\\"; + import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \\"react/jsx-runtime\\"; import MDXLayout from \\"./some-path\\"; function MDXContent(props = {}) { @@ -182,7 +185,8 @@ describe(`webpack loader: loads and injects Gatsby layout component`, () => { await expect( parseMDX(`${exampleMDX}\n\nexport {Layout as default} from "./some-path"`) ).resolves.toMatchInlineSnapshot(` - "import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; + "import React from \\"react\\"; + import GATSBY_COMPILED_MDX from \\"/mocked-layout.ts?contentFilePath=/mocked-content.mdx\\"; import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \\"react/jsx-runtime\\"; import {Layout as MDXLayout} from \\"./some-path\\"; function MDXContent(props = {}) { diff --git a/packages/gatsby-plugin-mdx/src/gatsby-layout-loader.ts b/packages/gatsby-plugin-mdx/src/gatsby-layout-loader.ts index a85733eb584b4..2f58b39bbaaa6 100644 --- a/packages/gatsby-plugin-mdx/src/gatsby-layout-loader.ts +++ b/packages/gatsby-plugin-mdx/src/gatsby-layout-loader.ts @@ -47,6 +47,7 @@ const gatsbyLayoutLoader: LoaderDefinition = async function ( this.addDependency(path.resolve(mdxPath)) const acorn = await cachedImport(`acorn`) + // @ts-ignore - We typecast below const { default: jsx } = await cachedImport(`acorn-jsx`) const { generate } = await cachedImport(`astring`) const { buildJsx } = await cachedImport< @@ -98,6 +99,8 @@ const gatsbyLayoutLoader: LoaderDefinition = async function ( }, }) + let hasClassicReactImport = false + /** * Replace default export with wrapper function that injects compiled MDX as children * Input: @@ -107,6 +110,13 @@ const gatsbyLayoutLoader: LoaderDefinition = async function ( **/ const newBody: Array = [] AST.body.forEach(child => { + if ( + child.type === `ImportDeclaration` && + child.source.value === `react` + ) { + hasClassicReactImport = true + } + if (child.type !== `ExportDefaultDeclaration`) { newBody.push(child) return @@ -137,7 +147,7 @@ const gatsbyLayoutLoader: LoaderDefinition = async function ( type: `Identifier`, name: `GatsbyMDXWrapper`, }, - expression: true, + expression: false, generator: false, async: false, params: [ @@ -207,6 +217,26 @@ const gatsbyLayoutLoader: LoaderDefinition = async function ( }, } as unknown as ExportDefaultDeclaration) }) + + if (!hasClassicReactImport) { + newBody.unshift({ + type: `ImportDeclaration`, + specifiers: [ + { + type: `ImportDefaultSpecifier`, + local: { + type: `Identifier`, + name: `React`, + }, + }, + ], + source: { + type: `Literal`, + value: `react`, + }, + }) + } + AST.body = newBody buildJsx(AST)