diff --git a/.circleci/config.yml b/.circleci/config.yml index b9d39a3f86996..320c3de5f3488 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -518,7 +518,7 @@ jobs: nvm install 18.0.0 nvm alias default 18.0.0 nvm use 18.0.0 - choco install yarn + choco install yarn -y - run: name: Rebuild packages for windows command: | diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index ab797c737fa7f..95097fbf722d4 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -744,12 +744,15 @@ Ignored if layout = FLUID.", }, "linkedFrom": "ContentfulLinkedFrom", "richText": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "richTextLocalized": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "richTextValidated": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "sys": Object { diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 5a01ebeefa76b..f5343924629a6 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -2,6 +2,7 @@ import type { GatsbyNode, NodePluginSchema, CreateSchemaCustomizationArgs, + IGatsbyResolverContext, } from "gatsby" import { GraphQLFieldConfig, @@ -31,15 +32,29 @@ import type { } from "./types/contentful" import { detectMarkdownField, makeContentTypeIdMap } from "./utils" import { restrictedNodeFields } from "./config" +import { Document } from "@contentful/rich-text-types" type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] interface IContentfulGraphQLField - extends Omit>, "type"> { + extends Omit< + Partial< + GraphQLFieldConfig< + IContentfulEntry, + IGatsbyResolverContext + > + >, + "type" + > { type: string | GraphQLType id?: string } +interface IRichTextFieldStructure { + richTextData: Document + spaceId: string +} + // Contentful content type schemas const ContentfulDataTypes: Map< string, @@ -112,7 +127,18 @@ const ContentfulDataTypes: Map< [ `RichText`, (): IContentfulGraphQLField => { - return { type: `ContentfulRichText` } + return { + type: `ContentfulRichText`, + resolve: (source, args, context, info): IRichTextFieldStructure => { + const richTextData = context.defaultFieldResolver( + source, + args, + context, + info + ) + return { richTextData, spaceId: source.sys.spaceId } + }, + } }, ], ]) @@ -599,16 +625,13 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const makeRichTextLinksResolver = (nodeType, entityType) => async ( - source, + source: IRichTextFieldStructure, _args, context ): Promise | null> => { - const links = getRichTextEntityLinks(source, nodeType)[entityType].map( - ({ id }) => id - ) - - const node = context.nodeModel.findRootNodeAncestor(source) - if (!node) return null + const links = getRichTextEntityLinks(source.richTextData, nodeType)[ + entityType + ].map(({ id }) => id) const res = await context.nodeModel.findAll({ query: { @@ -617,7 +640,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] id: { in: links, }, - spaceId: { eq: node.sys.spaceId }, + spaceId: { eq: source.spaceId }, }, }, }, @@ -693,8 +716,8 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { json: { type: `JSON`, - resolve(source) { - return source + resolve(source: IRichTextFieldStructure) { + return source.richTextData }, }, links: { diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index 462493bdee73b..f9d2ae97a2d45 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -2,6 +2,7 @@ import type { GatsbyNode } from "gatsby" import origFetch from "node-fetch" import fetchRetry from "@vercel/fetch-retry" import { polyfillImageServiceDevRoutes } from "gatsby-plugin-utils/polyfill-remote-file" +import { hasFeature } from "gatsby-plugin-utils/has-feature" import { CODES } from "./report" import { maskText } from "./plugin-options" @@ -47,6 +48,17 @@ export const onPreInit: GatsbyNode["onPreInit"] = async ( { store, reporter, actions }, pluginOptions ) => { + // gatsby version is too old + if (!hasFeature(`track-inline-object-opt-out`)) { + reporter.panic({ + id: CODES.GatsbyPluginMissing, + context: { + // TODO update message to reflect the actual version with track-inline-object-opt-out support + sourceMessage: `Used gatsby version is too old and doesn't support required features. Please update to gatsby@>=5.X.0`, + }, + }) + } + // if gatsby-plugin-image is not installed try { await import(`gatsby-plugin-image/graphql-utils.js`) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 45b7a29af6937..31c1eaf39f74e 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -788,6 +788,7 @@ export const createNodesForContentType = ({ type: makeTypeName(contentTypeItemId, contentTypePrefix), // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: entryItem.sys.updatedAt as string, + trackInlineObjects: false, }, // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field @@ -944,6 +945,7 @@ export const createAssetNodes = async ({ type: `ContentfulAsset`, // The content of an asset is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: assetItem.sys.updatedAt, + trackInlineObjects: false, }, // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field diff --git a/packages/gatsby-source-contentful/src/report.ts b/packages/gatsby-source-contentful/src/report.ts index 1de95e68dde21..dbd796ae78c3e 100644 --- a/packages/gatsby-source-contentful/src/report.ts +++ b/packages/gatsby-source-contentful/src/report.ts @@ -10,6 +10,7 @@ export const CODES = { ContentTypesMissing: `111006`, FetchTags: `111007`, GenericContentfulError: `111008`, + GatsbyTooOld: `111009`, } interface IErrorMap { @@ -57,4 +58,9 @@ export const ERROR_MAP: IErrorMap = { level: `ERROR`, category: `THIRD_PARTY`, }, + [CODES.GatsbyTooOld]: { + text: context => context.sourceMessage, + level: `ERROR`, + category: `USER`, + }, } diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index ca252cbf48bc9..7e33201c4c329 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -23,6 +23,7 @@ export type AvailableFeatures = | "content-file-path" | "stateful-source-nodes" | "adapters" + | "track-inline-object-opt-out" export { Link, @@ -34,6 +35,8 @@ export { export * from "gatsby-script" +export { IGatsbyResolverContext } from "./dist/schema/type-definitions" + export { AdapterInit, IAdapter, @@ -1777,6 +1780,7 @@ export interface NodeInput { contentDigest: string description?: string contentFilePath?: string + trackInlineObjects?: boolean } [key: string]: unknown } diff --git a/packages/gatsby/scripts/__tests__/api.js b/packages/gatsby/scripts/__tests__/api.js index dc1c6ce7ca41e..665dd8db02cb0 100644 --- a/packages/gatsby/scripts/__tests__/api.js +++ b/packages/gatsby/scripts/__tests__/api.js @@ -37,6 +37,7 @@ it("generates the expected api output", done => { "slices", "stateful-source-nodes", "adapters", + "track-inline-object-opt-out", ], "node": Object { "createPages": Object {}, diff --git a/packages/gatsby/scripts/output-api-file.js b/packages/gatsby/scripts/output-api-file.js index 8f3cf1b5f7c32..826a04429c123 100644 --- a/packages/gatsby/scripts/output-api-file.js +++ b/packages/gatsby/scripts/output-api-file.js @@ -41,7 +41,7 @@ async function outputFile() { }, {}) /** @type {Array} */ - output.features = ["image-cdn", "graphql-typegen", "content-file-path", "slices", "stateful-source-nodes", "adapters"]; + output.features = ["image-cdn", "graphql-typegen", "content-file-path", "slices", "stateful-source-nodes", "adapters", "track-inline-object-opt-out"]; return fs.writeFile( path.resolve(OUTPUT_FILE_NAME), diff --git a/packages/gatsby/src/joi-schemas/joi.ts b/packages/gatsby/src/joi-schemas/joi.ts index cb5402fd55295..352e31ee49899 100644 --- a/packages/gatsby/src/joi-schemas/joi.ts +++ b/packages/gatsby/src/joi-schemas/joi.ts @@ -177,6 +177,7 @@ export const nodeSchema: Joi.ObjectSchema = Joi.object() ignoreType: Joi.boolean(), counter: Joi.number(), contentFilePath: Joi.string(), + trackInlineObjects: Joi.boolean(), }) .unknown(false), // Don't allow non-standard fields }) diff --git a/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap b/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap index afeb90d39d48f..1cbf2b5b40dcd 100644 --- a/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap +++ b/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap @@ -2016,6 +2016,7 @@ type Internal { owner: String! type: String! contentFilePath: String + trackInlineObjects: Boolean } \\"\\"\\" @@ -2356,6 +2357,7 @@ input InternalFilterInput { owner: StringQueryOperatorInput type: StringQueryOperatorInput contentFilePath: StringQueryOperatorInput + trackInlineObjects: BooleanQueryOperatorInput } input BooleanQueryOperatorInput { @@ -2452,6 +2454,7 @@ input InternalFieldSelector { owner: FieldSelectorEnum type: FieldSelectorEnum contentFilePath: FieldSelectorEnum + trackInlineObjects: FieldSelectorEnum } type FileGroupConnection { @@ -2566,6 +2569,7 @@ input InternalSortInput { owner: SortOrderEnum type: SortOrderEnum contentFilePath: SortOrderEnum + trackInlineObjects: SortOrderEnum } type DirectoryConnection { diff --git a/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap b/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap index e8ca70911a884..a59ab4f0debc2 100644 --- a/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap +++ b/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap @@ -215,6 +215,7 @@ type Internal { owner: String! type: String! contentFilePath: String + trackInlineObjects: Boolean } \\"\\"\\" @@ -555,6 +556,7 @@ input InternalFilterInput { owner: StringQueryOperatorInput type: StringQueryOperatorInput contentFilePath: StringQueryOperatorInput + trackInlineObjects: BooleanQueryOperatorInput } input BooleanQueryOperatorInput { @@ -651,6 +653,7 @@ input InternalFieldSelector { owner: FieldSelectorEnum type: FieldSelectorEnum contentFilePath: FieldSelectorEnum + trackInlineObjects: FieldSelectorEnum } type FileGroupConnection { @@ -765,6 +768,7 @@ input InternalSortInput { owner: SortOrderEnum type: SortOrderEnum contentFilePath: SortOrderEnum + trackInlineObjects: SortOrderEnum } type DirectoryConnection { diff --git a/packages/gatsby/src/schema/node-model.js b/packages/gatsby/src/schema/node-model.js index b7e5824745a03..649137161b74d 100644 --- a/packages/gatsby/src/schema/node-model.js +++ b/packages/gatsby/src/schema/node-model.js @@ -498,6 +498,9 @@ class LocalNodeModel { * @param {Node} node Root Node */ trackInlineObjectsInRootNode(node) { + if (node.internal.trackInlineObjects === false) { + return + } if (!this._trackedRootNodes.has(node)) { addRootNodeToInlineObject( this._rootNodeMap, diff --git a/packages/gatsby/src/schema/types/node-interface.ts b/packages/gatsby/src/schema/types/node-interface.ts index 5769947f3381e..4f5f6019a2b99 100644 --- a/packages/gatsby/src/schema/types/node-interface.ts +++ b/packages/gatsby/src/schema/types/node-interface.ts @@ -27,6 +27,7 @@ const getOrCreateNodeInterface = ( owner: `String!`, type: `String!`, contentFilePath: `String`, + trackInlineObjects: `Boolean`, }) // TODO: Can be removed with graphql-compose 5.11 tc.getInputTypeComposer()