diff --git a/docs/docs/how-to/previews-deploys-hosting/adapters.md b/docs/docs/how-to/previews-deploys-hosting/adapters.md index 20bd9449f3138..4b2210755aa09 100644 --- a/docs/docs/how-to/previews-deploys-hosting/adapters.md +++ b/docs/docs/how-to/previews-deploys-hosting/adapters.md @@ -30,6 +30,13 @@ Can't find an adapter for your platform? Consider [creating an adapter](/docs/ho ## Using adapters +If you use one of the [supported deployment platforms](/docs/how-to/previews-deploys-hosting/zero-configuration-deployments/#supported-deployment-platforms), Gatsby's [zero-configuration deployments](/docs/how-to/previews-deploys-hosting/zero-configuration-deployments/) will automatically install and use the correct adapter when you deploy your project. + +If would like to use a custom adapter, specify adapter options or disable adapters, you can do so via the [Gatsby Config API](/docs/reference/config-files/gatsby-config/#adapter). + +> [!NOTE] +> If you plan on staying on a specific deployment platform, it is recommended to install the platform adapter to your `dependencies` as it will give you faster and more robust installs. + Use the `adapter` option inside `gatsby-config`: ```js:title=gatsby-config.js @@ -52,6 +59,19 @@ module.exports = { } ``` +## Disabling Adapters + +> [!NOTE} +> Support for disabling adapters was added in `gatsby@5.12.5`. + +Use the `adapter` option inside `gatsby-config`: + +```js:title=gatsby-config.js +module.exports = { + adapter: false +} +``` + ## Additional resources - [Zero-Configuration Deployments](/docs/how-to/previews-deploys-hosting/zero-configuration-deployments/) diff --git a/docs/docs/how-to/previews-deploys-hosting/zero-configuration-deployments.md b/docs/docs/how-to/previews-deploys-hosting/zero-configuration-deployments.md index 33480d27c9bae..60f44bfb7b248 100644 --- a/docs/docs/how-to/previews-deploys-hosting/zero-configuration-deployments.md +++ b/docs/docs/how-to/previews-deploys-hosting/zero-configuration-deployments.md @@ -16,12 +16,14 @@ Gatsby currently supports these platforms for zero-configuration deployments: ### Manually installing the adapter -If you plan on staying on a specific deployment platform, consider installing the adapter to your `dependencies`. This will give you faster and more robust installs. - If your adapter provides options that you can set, you must manually install the adapter to your `dependencies` to change any of the values. Read the [adapters guide](/docs/how-to/previews-deploys-hosting/adapters/) to learn how to use an adapter. If you plan on using a specific deployment platform for a long period of time, you may also want to install the adapter to your `dependencies`. This will give you faster and more robust installs. +### Disabling adapters + +Zero-configuration deployments are intended to simplify and improve the build and deploy experience. However, if you find that you need more control over your process, you can [disable adapters](/docs/how-to/previews-deploys-hosting/adapters/#disabling-adapters). + ## Adding additional adapters Gatsby's zero-configuration deployment setup is controlled through an [`adapters.js`](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/adapters.js) file. If you followed the [Creating an Adapter guide](/docs/how-to/previews-deploys-hosting/creating-an-adapter/) and want to add your adapter to this manifest, you can open a pull request. diff --git a/docs/docs/reference/config-files/gatsby-config.md b/docs/docs/reference/config-files/gatsby-config.md index 9ee07e3740af8..4ef7c625b82f6 100644 --- a/docs/docs/reference/config-files/gatsby-config.md +++ b/docs/docs/reference/config-files/gatsby-config.md @@ -230,7 +230,7 @@ By default, `graphqlTypegen` is only run during `gatsby develop`. Set this optio > Support added in `gatsby@5.12.0` -You can set an [adapter](/docs/how-to/previews-deploys-hosting/adapters/) or configure [zero-configuration deployments](/docs/how-to/previews-deploys-hosting/zero-configuration-deployments/) through the `adapter` setting. +You can set an [adapter](/docs/how-to/previews-deploys-hosting/adapters/), [disable adapters](/docs/how-to/previews-deploys-hosting/adapters/#disabling-adapters), or configure [zero-configuration deployments](/docs/how-to/previews-deploys-hosting/zero-configuration-deployments/) through the `adapter` setting. ```js:title=gatsby-config.js const adapter = require("gatsby-adapter-foo") @@ -242,6 +242,14 @@ module.exports = { } ``` +> Support added in `gatsby@5.12.5` + +```js:title=gatsby-config.js +module.exports = { + adapter: false // disable adapters +} +``` + Read the [adapters guide](/docs/how-to/previews-deploys-hosting/adapters/) to learn more. ## headers diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index 00bb8ed93ef5f..a927a8d8682a8 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -391,7 +391,7 @@ export interface GatsbyConfig { * Adapters are responsible for taking the production output from Gatsby and turning it into something your deployment platform understands. They make it easier to build and deploy Gatsby on any deployment platform. * @see http://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/adapters/ */ - adapter?: IAdapter + adapter?: IAdapter | false } /** diff --git a/packages/gatsby/src/joi-schemas/__tests__/joi.ts b/packages/gatsby/src/joi-schemas/__tests__/joi.ts index 91c65b026ae68..861bd9c35aa41 100644 --- a/packages/gatsby/src/joi-schemas/__tests__/joi.ts +++ b/packages/gatsby/src/joi-schemas/__tests__/joi.ts @@ -344,6 +344,16 @@ describe(`gatsby config`, () => { expect(result.value?.adapter).toEqual(config.adapter) }) + it(`lets you disable adapters`, () => { + const config = { + adapter: false, + } + + const result = gatsbyConfigSchema.validate(config) + expect(result.error).toBeNil() + expect(result.value?.adapter).toEqual(config.adapter) + }) + it(`throws on incorrect adapter setting`, () => { const configOne = { adapter: `gatsby-adapter-name`, @@ -351,7 +361,7 @@ describe(`gatsby config`, () => { const resultOne = gatsbyConfigSchema.validate(configOne) expect(resultOne.error).toMatchInlineSnapshot( - `[ValidationError: "adapter" must be of type object]` + `[ValidationError: "adapter" must be one of [false, object]]` ) const configTwo = { @@ -364,6 +374,15 @@ describe(`gatsby config`, () => { expect(resultTwo.error).toMatchInlineSnapshot( `[ValidationError: "adapter.adapt" is required]` ) + + const configThree = { + adapter: true, + } + + const resultThree = gatsbyConfigSchema.validate(configThree) + expect(resultThree.error).toMatchInlineSnapshot( + `[ValidationError: "adapter" must be one of [false, object]]` + ) }) }) diff --git a/packages/gatsby/src/joi-schemas/joi.ts b/packages/gatsby/src/joi-schemas/joi.ts index cb5402fd55295..ab3506c4d51d2 100644 --- a/packages/gatsby/src/joi-schemas/joi.ts +++ b/packages/gatsby/src/joi-schemas/joi.ts @@ -103,19 +103,22 @@ export const gatsbyConfigSchema: Joi.ObjectSchema = Joi.object() .unknown(false) ) .default([]), - adapter: Joi.object() - .keys({ - name: Joi.string().required(), - cache: Joi.object() - .keys({ - restore: Joi.func(), - store: Joi.func(), - }) - .unknown(false), - adapt: Joi.func().required(), - config: Joi.func(), - }) - .unknown(false), + adapter: Joi.alternatives( + Joi.boolean().valid(false), + Joi.object() + .keys({ + name: Joi.string().required(), + cache: Joi.object() + .keys({ + restore: Joi.func(), + store: Joi.func(), + }) + .unknown(false), + adapt: Joi.func().required(), + config: Joi.func(), + }) + .unknown(false) + ), }) // throws when both assetPrefix and pathPrefix are defined .when( diff --git a/packages/gatsby/src/redux/types.ts b/packages/gatsby/src/redux/types.ts index 01c409da25475..f6fa5d3b42138 100644 --- a/packages/gatsby/src/redux/types.ts +++ b/packages/gatsby/src/redux/types.ts @@ -141,7 +141,7 @@ export interface IGatsbyConfig { trailingSlash?: TrailingSlash graphqlTypegen?: IGraphQLTypegenOptions headers?: Array - adapter?: IAdapter + adapter?: IAdapter | false } export interface IGatsbyNode { diff --git a/packages/gatsby/src/utils/adapter/__tests__/manager.ts b/packages/gatsby/src/utils/adapter/__tests__/manager.ts index 8fc17c0e90b60..0a63c25b53fa4 100644 --- a/packages/gatsby/src/utils/adapter/__tests__/manager.ts +++ b/packages/gatsby/src/utils/adapter/__tests__/manager.ts @@ -3,9 +3,12 @@ import { getRoutesManifest, getFunctionsManifest, setWebpackAssets, + initAdapterManager, } from "../manager" import { state as stateDefault } from "./fixtures/state" import { IGatsbyState } from "../../../internal" +import { IAdapterManager, IAdapter } from "../types" +import { getAdapterInit } from "../init" jest.mock(`../../../redux`, () => { return { @@ -14,6 +17,7 @@ jest.mock(`../../../redux`, () => { }, store: { getState: jest.fn(), + dispatch: jest.fn(), }, } }) @@ -25,6 +29,34 @@ jest.mock(`../../engines-helpers`, () => { } }) +jest.mock(`../init`) + +const createAdapterMock = (): IAdapter => { + return { + name: `gatsby-adapter-mock`, + adapt: jest.fn(), + config: jest.fn().mockReturnValue({}), + } +} + +const mockNoOpAdapterManager: IAdapterManager = { + adapt: jest.fn(), + restoreCache: jest.fn(), + storeCache: jest.fn(), + config: jest.fn().mockResolvedValue({ + excludeDatastoreFromEngineFunction: false, + pluginsToDisable: [], + }), +} + +jest.mock(`../no-op-manager`, () => { + return { + noOpAdapterManager: jest + .fn() + .mockImplementation(() => mockNoOpAdapterManager), + } +}) + function mockStoreState( state: IGatsbyState, additionalState: Partial = {} @@ -33,6 +65,12 @@ function mockStoreState( ;(store.getState as jest.Mock).mockReturnValue(mergedState) } +function mockGetAdapterInit(adapter: IAdapter | undefined): void { + const mocked = getAdapterInit as jest.MockedFunction + mocked.mockClear() + mocked.mockResolvedValue(adapter ? (): IAdapter => adapter : undefined) +} + const fixturesDir = `${__dirname}/fixtures` let cwdToRestore @@ -127,3 +165,61 @@ describe(`getFunctionsManifest`, () => { `) }) }) + +describe(`initAdapterManager`, () => { + beforeEach(() => { + ;(mockNoOpAdapterManager.config as jest.Mock).mockClear() + }) + + it(`should use noop manager when adapter config is false`, async () => { + const initAdapter = createAdapterMock() + mockStoreState(stateDefault, { + config: { ...stateDefault.config, adapter: false }, + }) + mockGetAdapterInit(initAdapter) + const mgr = await initAdapterManager() + + expect(mgr).not.toBeNull() + expect(mockNoOpAdapterManager.config).toHaveBeenCalledTimes(1) + expect(initAdapter.config).not.toHaveBeenCalled() + }) + + it(`should use noop manager when adapter config is undefined and no adapter resolved`, async () => { + mockStoreState(stateDefault, { + config: { ...stateDefault.config, adapter: undefined }, + }) + mockGetAdapterInit(undefined) + const mgr = await initAdapterManager() + + expect(mgr).not.toBeNull() + expect(mockNoOpAdapterManager.config).toHaveBeenCalledTimes(1) + }) + + it(`should use configured adapter`, async () => { + const configuredAdapter = createAdapterMock() + const initAdapter = createAdapterMock() + mockStoreState(stateDefault, { + config: { ...stateDefault.config, adapter: configuredAdapter }, + }) + mockGetAdapterInit(initAdapter) + const mgr = await initAdapterManager() + + expect(mgr).not.toBeNull() + expect(mockNoOpAdapterManager.config).not.toHaveBeenCalled() + expect(initAdapter.config).not.toHaveBeenCalled() + expect(configuredAdapter.config).toHaveBeenCalledTimes(1) + }) + + it(`should use resolved adapter when adapter config is undefined`, async () => { + const initAdapter = createAdapterMock() + mockStoreState(stateDefault, { + config: { ...stateDefault.config, adapter: undefined }, + }) + mockGetAdapterInit(initAdapter) + const mgr = await initAdapterManager() + + expect(mgr).not.toBeNull() + expect(mockNoOpAdapterManager.config).not.toHaveBeenCalled() + expect(initAdapter.config).toBeCalled() + }) +}) diff --git a/packages/gatsby/src/utils/adapter/manager.ts b/packages/gatsby/src/utils/adapter/manager.ts index 5dd77a631c564..0aaebd80d7a91 100644 --- a/packages/gatsby/src/utils/adapter/manager.ts +++ b/packages/gatsby/src/utils/adapter/manager.ts @@ -129,7 +129,8 @@ export async function initAdapterManager(): Promise { reporter.verbose(`Using adapter ${adapter.name} from gatsby-config`) } else { - const adapterInit = await getAdapterInit() + const adapterInit = + adapterFromGatsbyConfig === false ? false : await getAdapterInit() // If we don't have adapter, use no-op adapter manager if (!adapterInit) {