Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: write graphql schema, fragments and config file to cache (#26829)
* chore: write graphql schema, fragments and config file to cache To provide graphql config baseline support for: - vscode-graphql - graphql-codegen - graphiql 2 (upcoming) - `fragments.graphql` is generated from plugins/core so implicit fragment support works across all config-consuming tooling - `schema.graphql` is written to file to make tooling faster, and to ensure tooling works without `develop` process running - `graphql.config.json` is written to the `.cache` directory, as `endpoints` config used by `vscode-graphql` for executing queries needs to know the current port. each of the tools above can be configured to load `.cache/graphql.config.json` instead of from the root directory this could not be achieved with a plugin, because the existing plugin interfaces don't provide a complete enough schema, or a collation of fragments. * migrate to redux store and plugins * consolidate to a single plugin, use store emitter * chore: address review comments * chore: gitignore index.js
- Loading branch information
Showing
13 changed files
with
361 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": [["babel-preset-gatsby-package"]] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Logs | ||
logs | ||
*.log | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directory | ||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git | ||
node_modules | ||
|
||
decls | ||
dist | ||
|
||
/*.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Logs | ||
logs | ||
*.log | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directory | ||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git | ||
node_modules | ||
*.un~ | ||
yarn.lock | ||
src | ||
flow-typed | ||
coverage | ||
decls | ||
examples |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# gatsby-plugin-graphql-config | ||
|
||
Persists gatsby graphql schema and fragments to the .cache directory, as well as a [graphql config](https://graphql-config.com) file to enable full-featured tooling for: | ||
|
||
- [`vscode-graphql`](https://marketplace.visualstudio.com/items?itemName=Prisma.vscode-graphql), and other IDE extensions that use the official GraphQL LSP | ||
- [`eslint-plugin-graphql`](https://github.com/apollographql/eslint-plugin-graphql) | ||
- [`graphql code generator`](https://graphql-code-generator.com/) for gatsby projects using typescript | ||
- eventually [`graphiql`](https://github.com/graphql/graphiql) will use it, even! | ||
|
||
## Install | ||
|
||
`npm install --save gatsby-plugin-graphql-config` | ||
|
||
## How to use | ||
|
||
First, add it to your plugin configuration: | ||
|
||
```javascript | ||
// In your gatsby-config.js | ||
plugins: [`gatsby-plugin-graphql-config`] | ||
``` | ||
|
||
**simplest setup**: | ||
if you are able to configure your tools to seek a different `basePath` for loading graphql config, point them to `.cache` directory. | ||
|
||
**manual setup for repos with no other graphql projects**: | ||
|
||
If your project is _only_ a gatsby project, you can place a `graphql.config.js` file at the root of your gatsby project like this: | ||
|
||
`<my project>/graphql.config.js`: | ||
|
||
```js | ||
// <my project>/graphql.config.js | ||
module.exports = require("./.cache/graphql.config.json") | ||
``` | ||
|
||
if it's in a subdirectory such as a `site/` folder, you would use this: | ||
|
||
`<my project>/graphql.config.js`: | ||
|
||
```js | ||
module.exports = require("./site/.cache/graphql.config.json") | ||
``` | ||
|
||
**for repositories with multiple graphql projects** | ||
|
||
if your repository has multiple graphql projects including gatsby, you will want a config similar to this at the root: | ||
|
||
`<my project>/graphql.config.js`: | ||
|
||
```js | ||
module.exports = { | ||
projects: { | ||
site: require("packages/site/.cache/graphql.config.json"), | ||
server: { | ||
schema: "packages/server/src/**/*.{graphql,gql}", | ||
documents: "packages/server/src/queries/**/*.{ts,tsx,js,jsx}", | ||
}, | ||
}, | ||
} | ||
``` | ||
|
||
### How it works | ||
|
||
It writes out these files to the gatsby `.cache` directory: | ||
|
||
- `schema.graphql` - a complete representation of the schema, including plugins | ||
- `fragments.graphql` - all user, plugin and gatsby-core provided fragments in one file | ||
- `graphql.config.json` - a graphql-config@3 compatible config file with absolute file resolutions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "gatsby-plugin-graphql-config", | ||
"description": "Gatsby plugin to write out a graphql-config with develop process endpoint configured", | ||
"version": "1.0.0", | ||
"author": "Rikki Schulte <rikki.schulte@gmail.com>", | ||
"bugs": { | ||
"url": "https://github.com/gatsbyjs/gatsby/issues" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.10.3", | ||
"@babel/core": "^7.10.3", | ||
"babel-preset-gatsby-package": "^0.5.2", | ||
"cpx": "^1.5.0", | ||
"cross-env": "^5.2.1", | ||
"rewire": "^4.0.1" | ||
}, | ||
"homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-graphql-config#readme", | ||
"keywords": [ | ||
"gatsby", | ||
"gatsby-plugin", | ||
"graphql", | ||
"config" | ||
], | ||
"license": "MIT", | ||
"main": "index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/gatsbyjs/gatsby.git", | ||
"directory": "packages/gatsby-plugin-graphql-config" | ||
}, | ||
"scripts": { | ||
"build": "babel src --out-dir . --ignore \"**/__tests__\" --extensions \".ts,.js\"", | ||
"watch": "babel -w src --out-dir . --ignore \"**/__tests__\" --extensions \".ts,.js\"", | ||
"prepare": "cross-env NODE_ENV=production npm run build" | ||
}, | ||
"engines": { | ||
"node": ">=10.13.0" | ||
} | ||
} |
122 changes: 122 additions & 0 deletions
122
packages/gatsby-plugin-graphql-config/src/gatsby-node.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import * as fs from "fs-extra" | ||
import { resolve, join } from "path" | ||
import { GraphQLSchema, printSchema } from "graphql" | ||
import type { GatsbyReduxStore } from "gatsby/src/redux" | ||
import type { IStateProgram } from "gatsby/src/internal" | ||
|
||
async function cacheGraphQLConfig(program: IStateProgram): Promise<void> { | ||
try { | ||
const base = program.directory | ||
const configJSONString = JSON.stringify( | ||
{ | ||
schema: resolve(base, `.cache/schema.graphql`), | ||
documents: [ | ||
resolve(base, `src/**/**.{ts,js,tsx,jsx,esm}`), | ||
resolve(base, `.cache/fragments.graphql`), | ||
], | ||
extensions: { | ||
endpoints: { | ||
default: { | ||
url: `${program.https ? `https://` : `http://`}${program.host}:${ | ||
program.port | ||
}/___graphql`, | ||
}, | ||
}, | ||
}, | ||
}, | ||
null, | ||
2 | ||
) | ||
|
||
fs.writeFileSync( | ||
resolve(base, `.cache`, `graphql.config.json`), | ||
configJSONString | ||
) | ||
console.log(`[gatsby-plugin-graphql-config] wrote config file to .cache`) | ||
} catch (err) { | ||
console.error( | ||
`[gatsby-plugin-graphql-config] failed to write config file to .cache` | ||
) | ||
console.error(err) | ||
} | ||
} | ||
|
||
const createFragmentCacheHandler = ( | ||
cacheDirectory: string, | ||
store: GatsbyReduxStore | ||
) => async (): Promise<void> => { | ||
try { | ||
const currentDefinitions = store.getState().definitions | ||
|
||
const fragmentString = Array.from(currentDefinitions.entries()) | ||
.filter(([_, def]) => def.isFragment) | ||
.map(([_, def]) => `# ${def.filePath}\n${def.printedAst}`) | ||
.join(`\n`) | ||
|
||
await fs.writeFile( | ||
join(cacheDirectory, `fragments.graphql`), | ||
fragmentString | ||
) | ||
|
||
console.log(`[gatsby-plugin-graphql-config] wrote fragments file to .cache`) | ||
} catch (err) { | ||
console.error( | ||
`[gatsby-plugin-graphql-config] failed writing fragments file to .cache` | ||
) | ||
console.error(err) | ||
} | ||
} | ||
|
||
const cacheSchema = async ( | ||
cacheDirectory: string, | ||
schema: GraphQLSchema | ||
): Promise<void> => { | ||
try { | ||
console.log(`printing schema`) | ||
const schemaSDLString = printSchema(schema, { commentDescriptions: true }) | ||
|
||
await fs.writeFile(join(cacheDirectory, `schema.graphql`), schemaSDLString) | ||
|
||
console.log(`[gatsby-plugin-graphql-config] wrote SDL file to .cache`) | ||
} catch (err) { | ||
console.error( | ||
`[gatsby-plugin-graphql-config] failed writing schema file to .cache` | ||
) | ||
console.error(err) | ||
} | ||
} | ||
|
||
const createSchemaCacheHandler = ( | ||
cacheDirectory: string, | ||
store: GatsbyReduxStore | ||
) => async (): Promise<void> => { | ||
const { schema } = store.getState() | ||
await cacheSchema(cacheDirectory, schema) | ||
} | ||
|
||
export async function onPostBootstrap({ | ||
store, | ||
emitter, | ||
}: { | ||
store: GatsbyReduxStore | ||
emitter: any | ||
}): Promise<void> { | ||
const { program, schema } = store.getState() | ||
|
||
const cacheDirectory = resolve(program.directory, `.cache`) | ||
|
||
if (!fs.existsSync(cacheDirectory)) { | ||
return | ||
} | ||
// cache initial schema | ||
await cacheSchema(cacheDirectory, schema) | ||
// cache graphql config file | ||
await cacheGraphQLConfig(program) | ||
// Important! emitter.on is an internal Gatsby API. It is highly discouraged to use in plugins and can break without a notice. | ||
// FIXME: replace it with a more appropriate API call when available. | ||
emitter.on( | ||
`SET_GRAPHQL_DEFINITIONS`, | ||
createFragmentCacheHandler(cacheDirectory, store) | ||
) | ||
emitter.on(`SET_SCHEMA`, createSchemaCacheHandler(cacheDirectory, store)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// no-op |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "../../tsconfig.json" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { ActionsUnion, IGatsbyState } from "../types" | ||
|
||
export const definitionsReducer = ( | ||
state: IGatsbyState["definitions"] = new Map(), | ||
action: ActionsUnion | ||
): IGatsbyState["definitions"] => { | ||
switch (action.type) { | ||
case `SET_GRAPHQL_DEFINITIONS`: | ||
return action.payload | ||
default: | ||
return state | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.