Skip to content

Commit

Permalink
feat(gatsby,gatsby-plugin-utils): feature toggle and availability (#3…
Browse files Browse the repository at this point in the history
  • Loading branch information
wardpeet committed Feb 8, 2022
1 parent e63e934 commit 93a2071
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 8 deletions.
17 changes: 17 additions & 0 deletions packages/gatsby-plugin-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,20 @@ if (isGatsbyNodeLifecycleSupported(`createSchemaCustomization`)) {
}
}
```

### `hasFeature`

Feature detection is now part of Gatsby. As a plugin author you don't know what version of Gatsby a user is using. `hasFeature` allows you to check if the current version of Gatsby has a certain feature.

Here's a list of features:
// TODO

#### Example

```js
const { hasFeature } = require(`gatsby-plugin-utils`)

if (!hasFeature(`image-service`)) {
// You can polyfill image-service here so older versions have support as well
}
```
28 changes: 28 additions & 0 deletions packages/gatsby-plugin-utils/src/__tests__/has-feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { hasFeature } from "../has-feature"
import apis from "gatsby/apis.json"

jest.mock(`gatsby/apis.json`, () => {
return {}
})

describe(`hasFeature`, () => {
it(`should return true if gatsby has the feature`, () => {
apis.features = [`image-service`]
expect(hasFeature(`image-service`)).toBe(true)
})
it(`should return false if the feature has a typo`, () => {
apis.features = [`image-service`]
expect(hasFeature(`image-services`)).toBe(false)
})

it(`should return false if gatsby doesn't have the feature`, () => {
apis.features = []
expect(hasFeature(`image-service`)).toBe(false)
})

it(`should return false if gatsby doesn't support features section yet`, () => {
// @ts-ignore - we want to test old versions too
delete apis.features
expect(hasFeature(`image-service`)).toBe(false)
})
})
16 changes: 16 additions & 0 deletions packages/gatsby-plugin-utils/src/has-feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { AvailableFeatures } from "gatsby"

/**
* Check the readme for a list of available features.
*/
export function hasFeature(name: AvailableFeatures): boolean {
try {
const availableAPIs = require(`gatsby/apis.json`)

return !!availableAPIs?.features?.includes(name)
} catch (e) {
throw new Error(
`Couldn't check available APIs. Make sure you are on gatsby version >=2.13.41`
)
}
}
1 change: 1 addition & 0 deletions packages/gatsby-plugin-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./validate"
export * from "./test-plugin-options-schema"
export * from "./joi"
export * from "./node-api-is-supported"
export * from "./has-feature"
1 change: 1 addition & 0 deletions packages/gatsby-plugin-utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.json",
"include": ["src"],
"exclude": ["**/__tests__/**/*"],
"compilerOptions": {
"skipLibCheck": true
}
Expand Down
24 changes: 16 additions & 8 deletions packages/gatsby/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { GraphQLOutputType } from "graphql"
import { PluginOptionsSchemaJoi, ObjectSchema } from "gatsby-plugin-utils"
import { IncomingMessage, ServerResponse } from "http"

export type AvailableFeatures = never // "image-service"

export {
default as Link,
GatsbyLinkProps,
Expand Down Expand Up @@ -156,21 +158,24 @@ export type GetServerDataProps = {
query?: Record<string, unknown>
params?: Record<string, unknown>
pageContext: Record<string, unknown>
};
}

/**
* The return type (promise payload) from the [getServerData](https://www.gatsbyjs.com/docs/reference/rendering-options/server-side-rendering/) function.
*/
export type GetServerDataReturn<ServerDataType = Record<string, unknown>> = Promise<{
headers?: Map<string, unknown>
props?: ServerDataType
status?: number
}>;
export type GetServerDataReturn<ServerDataType = Record<string, unknown>> =
Promise<{
headers?: Map<string, unknown>
props?: ServerDataType
status?: number
}>

/**
* A shorthand type for combining the props and return type for the [getServerData](https://www.gatsbyjs.com/docs/reference/rendering-options/server-side-rendering/) function.
*/
export type GetServerData<ServerDataType> = (props: GetServerDataProps) => GetServerDataReturn<ServerDataType>;
export type GetServerData<ServerDataType> = (
props: GetServerDataProps
) => GetServerDataReturn<ServerDataType>

/**
* Constructor arguments for the PageRenderer.
Expand Down Expand Up @@ -442,7 +447,7 @@ export interface GatsbyNode<

/** The first API called during Gatsby execution, runs as soon as plugins are loaded, before cache initialization and bootstrap preparation. If you indend to use this API in a plugin, use "onPluginInit" instead. */
onPreInit?(
args: ParentSpanPluginArgs,
args: PreInitArgs,
options: PluginOptions,
callback: PluginCallback<void>
): void | Promise<void>
Expand Down Expand Up @@ -905,6 +910,9 @@ export interface NodePluginSchema {
buildEnumType(config: ComposeEnumTypeConfig): GatsbyGraphQLEnumType
buildScalarType(config: ComposeScalarTypeConfig): GatsbyGraphQLScalarType
}
export interface PreInitArgs extends ParentSpanPluginArgs {
actions: Actions
}

export interface SourceNodesArgs extends ParentSpanPluginArgs {
traceId: "initial-sourceNodes"
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby/scripts/__tests__/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ it("generates the expected api output", done => {
"wrapPageElement": Object {},
"wrapRootElement": Object {},
},
"features": Array [],
"node": Object {
"createPages": Object {},
"createPagesStatefully": Object {},
Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby/scripts/output-api-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ async function outputFile() {
return merged
}, {})

output.features = [];

return fs.writeFile(
path.resolve(OUTPUT_FILE_NAME),
JSON.stringify(output, null, 2),
Expand Down
7 changes: 7 additions & 0 deletions packages/gatsby/src/utils/api-node-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,13 @@ export const onCreateWebpackConfig = true

/**
* The first API called during Gatsby execution, runs as soon as plugins are loaded, before cache initialization and bootstrap preparation.
*
* @param {object} $0
* @param {object} $0.actions
* @example
* exports.onPreInit = ({ actions }) => {
*
* }
*/
export const onPreInit = true

Expand Down

0 comments on commit 93a2071

Please sign in to comment.