diff --git a/e2e-tests/development-runtime/cypress/integration/eslint-rules/limited-exports-page-templates.js b/e2e-tests/development-runtime/cypress/integration/eslint-rules/limited-exports-page-templates.js index accc4d9b40222..886c557b3a855 100644 --- a/e2e-tests/development-runtime/cypress/integration/eslint-rules/limited-exports-page-templates.js +++ b/e2e-tests/development-runtime/cypress/integration/eslint-rules/limited-exports-page-templates.js @@ -23,7 +23,7 @@ describe(`limited-exports-page-templates`, () => { it(`should initially not log to console`, () => { cy.get(`@hmrConsoleLog`).should( `not.be.calledWithMatch`, - /13:1 {2}warning {2}In page templates only a default export of a valid React component and the named export of a page query is allowed./i + /13:1 {2}warning {2}In page templates only a default export of a valid React component and the named exports of a page query, getServerData or config are allowed./i ) }) it(`should log warning to console for invalid export`, () => { @@ -34,11 +34,11 @@ describe(`limited-exports-page-templates`, () => { cy.get(`@hmrConsoleLog`).should( `be.calledWithMatch`, - /13:1 {2}warning {2}In page templates only a default export of a valid React component and the named export of a page query is allowed./i + /13:1 {2}warning {2}In page templates only a default export of a valid React component and the named exports of a page query, getServerData or config are allowed./i ) cy.get(`@hmrConsoleLog`).should( `not.be.calledWithMatch`, - /15:1 {2}warning {2}In page templates only a default export of a valid React component and the named export of a page query is allowed./i + /15:1 {2}warning {2}In page templates only a default export of a valid React component and the named exports of a page query, getServerData or config are allowed./i ) }) }) diff --git a/packages/gatsby/src/utils/eslint-rules/__tests__/limited-exports-page-templates.ts b/packages/gatsby/src/utils/eslint-rules/__tests__/limited-exports-page-templates.ts index fd806ca28f783..dc4ee7c4e8aa7 100644 --- a/packages/gatsby/src/utils/eslint-rules/__tests__/limited-exports-page-templates.ts +++ b/packages/gatsby/src/utils/eslint-rules/__tests__/limited-exports-page-templates.ts @@ -52,6 +52,7 @@ describe(`no-anonymous-exports-page-templates`, () => { test({ code: `import { graphql } from "gatsby"\nconst Template = () => {}\nconst query = graphql\`test\`\nexport { query }\nexport default Template`, }), + // getServerData test({ code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexport function getServerData() { return { props: { foo: "bar" }}}`, }), @@ -64,6 +65,19 @@ describe(`no-anonymous-exports-page-templates`, () => { test({ code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexports.getServerData = () => { return { props: { foo: "bar" }}}`, }), + // config + test({ + code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexport function config() { return ({ params }) => { defer: true }}`, + }), + test({ + code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexport async function config() { const { data } = graphql\`test\`\nreturn ({ params }) => { defer: true }}`, + }), + test({ + code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexport const config = () => { return ({ params }) => { defer: true }}`, + }), + test({ + code: `import { graphql, Link } from "gatsby"\nconst Template = () => {}\nexport const query = graphql\`test\`\nexport default Template\nexports.config = () => { return ({ params }) => { defer: true }}`, + }), ], invalid: [ test({ diff --git a/packages/gatsby/src/utils/eslint-rules/limited-exports-page-templates.ts b/packages/gatsby/src/utils/eslint-rules/limited-exports-page-templates.ts index a437bf989bce2..cddf1688de728 100644 --- a/packages/gatsby/src/utils/eslint-rules/limited-exports-page-templates.ts +++ b/packages/gatsby/src/utils/eslint-rules/limited-exports-page-templates.ts @@ -18,25 +18,25 @@ import { isPageTemplate } from "../eslint-rules-helpers" const DEFAULT_GRAPHQL_TAG_NAME = `graphql` -function isGetServerData(node: ExportNamedDeclaration): boolean { +function isApiExport(node: ExportNamedDeclaration, name: string): boolean { // check for - // export function getServerData() {} - // export async function getServerData() {} + // export function name() {} + // export async function name() {} if ( node.declaration?.type === `FunctionDeclaration` && - node.declaration.id?.name === `getServerData` + node.declaration.id?.name === name ) { return true } // check for - // export const getServerData = () => {} + // export const name = () => {} if (node.declaration?.type === `VariableDeclaration`) { for (const declaration of node.declaration.declarations) { if ( declaration.type === `VariableDeclarator` && declaration.id.type === `Identifier` && - declaration.id.name === `getServerData` + declaration.id.name === name ) { return true } @@ -113,7 +113,7 @@ const limitedExports: Rule.RuleModule = { meta: { type: `problem`, messages: { - limitedExportsPageTemplates: `In page templates only a default export of a valid React component and the named export of a page query is allowed. + limitedExportsPageTemplates: `In page templates only a default export of a valid React component and the named exports of a page query, getServerData or config are allowed. All other named exports will cause Fast Refresh to not preserve local component state and do a full refresh. Please move your other named exports to another file. Also make sure that you only export page queries that use the "graphql" tag from "gatsby". @@ -225,7 +225,11 @@ const limitedExports: Rule.RuleModule = { return undefined } - if (isGetServerData(node)) { + if (isApiExport(node, `getServerData`)) { + return undefined + } + + if (isApiExport(node, `config`)) { return undefined }