-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
404 additions
and
0 deletions.
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,72 @@ | ||
# gatsby-source-store | ||
|
||
Plugin for sourcing the store-api data layer into Gatsby. | ||
|
||
## Install | ||
``` | ||
yarn add @vtex/gatsby-source-vtex @vtex/store-api | ||
``` | ||
|
||
# How to use | ||
```js | ||
// In your gatsby-config.js | ||
const { getSchema } = require('@vtex/store-api') | ||
|
||
const options = { | ||
platform: 'vtex', | ||
account: 'my-vtex-account', | ||
environment: 'vtexcommercestable' | ||
} | ||
|
||
module.exports = { | ||
plugins: [ | ||
// other plugins ... | ||
{ | ||
resolve: '@vtex/gatsby-source-store', | ||
options: { | ||
getSchema: () => getSchema(options) | ||
} | ||
}, | ||
], | ||
} | ||
``` | ||
|
||
# Options | ||
This plugin brings additional options for you to control how the nodes are sourced. | ||
| Options | type | effect | | ||
|:-----------------:|:-------:|:-----------------------------------:| | ||
| sourceProducts | boolean | false for not sourcing products | | ||
| sourceCollections | boolean | false for not sourcing collections | | ||
| maxNumProducts | number | max number of products to source | | ||
| maxNumCollections | number | max number of collections to source | | ||
|
||
> Tip: While sourcing large ecommerces, add the maxNumProducts and maxNumCollections so you can develop whithout waiting for the whole dataset to be downloaded. Maybe try something like: | ||
```js | ||
const { getSchema } = require('@vtex/store-api') | ||
|
||
const options = { | ||
platform: 'vtex', | ||
account: 'my-vtex-account', | ||
environment: 'vtexcommercestable' | ||
} | ||
|
||
const isProduction = process.env.NODE_ENV === 'production' | ||
|
||
module.exports = { | ||
plugins: [ | ||
// other plugins ... | ||
{ | ||
resolve: '@vtex/gatsby-source-store', | ||
options: { | ||
getSchema: () => getSchema(options) | ||
// Source less products is development for better DX | ||
maxNumProducts: isProduction ? undefined : 100, | ||
maxNumCollections: isProduction ? undefined : 100, | ||
} | ||
}, | ||
], | ||
} | ||
``` | ||
|
||
## How to contribute | ||
Feel free to open issues in our repo. Also, there is a general contributing guideline in there |
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,45 @@ | ||
{ | ||
"name": "@vtex/gatsby-source-store", | ||
"version": "1.1.1", | ||
"description": "Gatsby source plugin for building websites using a FastStore compatible server", | ||
"author": "Store Framework", | ||
"license": "MIT", | ||
"main": "dist/index.js", | ||
"module": "dist/gatsby-source-store.esm.js", | ||
"typings": "dist/index.d.ts", | ||
"repository": { | ||
"directory": "packages/gatsby-source-store", | ||
"url": "https://github.com/vtex/faststore", | ||
"type": "git" | ||
}, | ||
"files": [ | ||
"dist", | ||
"gatsby-*", | ||
"index.js", | ||
"src" | ||
], | ||
"engines": { | ||
"node": ">=10" | ||
}, | ||
"scripts": { | ||
"develop": "tsdx watch", | ||
"build": "tsdx build", | ||
"test": "tsdx test", | ||
"lint": "tsdx lint" | ||
}, | ||
"peerDependencies": { | ||
"gatsby": "^3.11.1", | ||
"graphql": "^15.0.0" | ||
}, | ||
"dependencies": { | ||
"@graphql-tools/delegate": "^7.1.5", | ||
"@graphql-tools/wrap": "^7.0.8", | ||
"gatsby-graphql-source-toolkit": "^2.0.1" | ||
}, | ||
"devDependencies": { | ||
"gatsby": "^3.11.1", | ||
"tsdx": "^0.14.1", | ||
"tslib": "^2.3.1", | ||
"typescript": "^4.3.3" | ||
} | ||
} |
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,66 @@ | ||
import { printSchema } from 'graphql' | ||
import type { | ||
CreateSchemaCustomizationArgs, | ||
PluginOptionsSchemaArgs, | ||
SourceNodesArgs, | ||
} from 'gatsby' | ||
import type { GraphQLSchema } from 'graphql' | ||
|
||
import { sourceCollections } from './sourceCollections' | ||
import { sourceProducts } from './sourceProducts' | ||
|
||
export interface Options { | ||
sourceProducts?: boolean | ||
sourceCollections?: boolean | ||
maxNumProducts?: number | ||
maxNumCollections?: number | ||
getSchema: () => Promise<GraphQLSchema> | ||
} | ||
|
||
export const pluginOptionsSchema = ({ Joi }: PluginOptionsSchemaArgs) => | ||
Joi.object({ | ||
sourceProducts: Joi.boolean(), | ||
sourceCollections: Joi.boolean(), | ||
maxNumProducts: Joi.number(), | ||
maxNumCollections: Joi.number(), | ||
getSchema: Joi.function().required(), | ||
}) | ||
|
||
export const createSchemaCustomization = async ( | ||
gatsbyApi: CreateSchemaCustomizationArgs, | ||
options: Options | ||
) => { | ||
const { actions } = gatsbyApi | ||
const schema = await options.getSchema() | ||
const typeDefs = printSchema(schema) | ||
.replace('type StoreCollection {', 'type StoreCollection implements Node {') | ||
.replace(`type StoreProduct {`, `type StoreProduct implements Node {`) | ||
.replace(/(\w*)Connection/g, 'Browser$1Connection') | ||
|
||
actions.createTypes(typeDefs) | ||
} | ||
|
||
export const sourceNodes = async ( | ||
gatsbyApi: SourceNodesArgs, | ||
options: Options | ||
) => { | ||
const { reporter } = gatsbyApi | ||
const lastBuildTime = await gatsbyApi.cache.get(`LAST_BUILD_TIME`) | ||
|
||
await gatsbyApi.cache.set(`LAST_BUILD_TIME`, Date.now()) | ||
|
||
if (lastBuildTime) { | ||
reporter.info( | ||
'[gatsby-source-vtex]: CACHE FOUND! We are about to go FAST! Skipping FETCH' | ||
) | ||
} else { | ||
reporter.info( | ||
'[gatsby-source-vtex]: No cache found. Sourcing all data from scratch' | ||
) | ||
} | ||
|
||
await Promise.all([ | ||
sourceProducts(gatsbyApi, options), | ||
sourceCollections(gatsbyApi, options), | ||
]) | ||
} |
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 @@ | ||
export * as GatsbyNode from './gatsby-node' |
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,46 @@ | ||
import type { IPaginationAdapter } from 'gatsby-graphql-source-toolkit' | ||
|
||
const DEFAULT_PAGE_SIZE = 99 | ||
|
||
export interface IRelayPage { | ||
edges: Array<{ cursor: string; node: unknown | null }> | ||
pageInfo: { hasNextPage: boolean } | ||
} | ||
|
||
export const RelayForward = ( | ||
maxItems: number | ||
): IPaginationAdapter<IRelayPage, unknown> => ({ | ||
name: 'RelayForward', | ||
expectedVariableNames: [`first`, `after`], | ||
start() { | ||
return { | ||
variables: { first: DEFAULT_PAGE_SIZE, after: undefined }, | ||
hasNextPage: true, | ||
} | ||
}, | ||
next(state, page) { | ||
const tail = page.edges[page.edges.length - 1] | ||
const first = Number(state.variables.first) ?? DEFAULT_PAGE_SIZE | ||
const after = tail?.cursor | ||
|
||
return { | ||
variables: { first, after }, | ||
hasNextPage: Boolean( | ||
page?.pageInfo?.hasNextPage && Number(after) < maxItems | ||
), | ||
} | ||
}, | ||
concat(acc, page) { | ||
return { | ||
...acc, | ||
edges: { | ||
...acc.edges, | ||
...page.edges, | ||
}, | ||
pageInfo: page.pageInfo, | ||
} | ||
}, | ||
getItems(pageOrResult) { | ||
return pageOrResult.edges.map((edge) => (edge ? edge.node : null)) | ||
}, | ||
}) |
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,37 @@ | ||
import type { SourceNodesArgs } from 'gatsby' | ||
|
||
import { sourceStoreType } from './sourceStore' | ||
import type { Options } from './gatsby-node' | ||
|
||
export const sourceCollections = async ( | ||
gatsbyApi: SourceNodesArgs, | ||
options: Options | ||
) => { | ||
const { maxNumCollections = Infinity } = options | ||
const gatsbyNodeTypes = [ | ||
{ | ||
remoteTypeName: `StoreCollection`, | ||
queries: ` | ||
query LIST_COLLECTIONS($first: Int!, $after: String!) { | ||
allCollections(first: $first, after: $after) { | ||
edges { | ||
node { | ||
..._CollectionFragment_ | ||
} | ||
cursor | ||
} | ||
pageInfo { | ||
hasNextPage | ||
} | ||
} | ||
} | ||
fragment _CollectionFragment_ on StoreCollection { | ||
id | ||
__typename | ||
} | ||
`, | ||
}, | ||
] | ||
|
||
await sourceStoreType(gatsbyApi, options, gatsbyNodeTypes, maxNumCollections) | ||
} |
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,37 @@ | ||
import type { SourceNodesArgs } from 'gatsby' | ||
|
||
import { sourceStoreType } from './sourceStore' | ||
import type { Options } from './gatsby-node' | ||
|
||
export const sourceProducts = async ( | ||
gatsbyApi: SourceNodesArgs, | ||
options: Options | ||
) => { | ||
const { maxNumProducts = Infinity } = options | ||
const gatsbyNodeTypes = [ | ||
{ | ||
remoteTypeName: `StoreProduct`, | ||
queries: ` | ||
query LIST_PRODUCTS($first: Int!, $after: String!) { | ||
allProducts(first: $first, after: $after) { | ||
edges { | ||
node { | ||
..._ProductFragment_ | ||
} | ||
cursor | ||
} | ||
pageInfo { | ||
hasNextPage | ||
} | ||
} | ||
} | ||
fragment _ProductFragment_ on StoreProduct { | ||
id: productID | ||
__typename | ||
} | ||
`, | ||
}, | ||
] | ||
|
||
await sourceStoreType(gatsbyApi, options, gatsbyNodeTypes, maxNumProducts) | ||
} |
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,64 @@ | ||
import { | ||
buildNodeDefinitions, | ||
compileNodeQueries, | ||
createSchemaCustomization as toolkitCreateSchemaCustomization, | ||
generateDefaultFragments, | ||
sourceAllNodes, | ||
} from 'gatsby-graphql-source-toolkit' | ||
import { execute, parse } from 'graphql' | ||
import type { SourceNodesArgs } from 'gatsby' | ||
import type { | ||
IGatsbyNodeConfig, | ||
ISourcingConfig, | ||
} from 'gatsby-graphql-source-toolkit/dist/types' | ||
|
||
import type { Options } from './gatsby-node' | ||
import { RelayForward } from './paginate' | ||
|
||
export const sourceStoreType = async ( | ||
gatsbyApi: SourceNodesArgs, | ||
options: Options, | ||
gatsbyNodeTypes: IGatsbyNodeConfig[], | ||
maxItems: number | ||
) => { | ||
// Step1. Set up remote schema | ||
const schema = await options.getSchema() | ||
|
||
// Step3. Provide (or generate) fragments with fields to be fetched | ||
const fragments = generateDefaultFragments({ schema, gatsbyNodeTypes }) | ||
|
||
// Step4. Compile sourcing queries | ||
const documents = compileNodeQueries({ | ||
schema, | ||
gatsbyNodeTypes, | ||
customFragments: fragments, | ||
}) | ||
|
||
const config: ISourcingConfig = { | ||
gatsbyApi, | ||
schema, | ||
execute: async (args) => { | ||
const response = await execute({ | ||
operationName: args.operationName, | ||
document: parse(args.query), | ||
variableValues: args.variables, | ||
schema, | ||
}) | ||
|
||
if (response.errors?.length) { | ||
response.errors.forEach((e) => console.error(e)) | ||
} | ||
|
||
return response | ||
}, | ||
gatsbyTypePrefix: ``, | ||
gatsbyNodeDefs: buildNodeDefinitions({ gatsbyNodeTypes, documents }), | ||
paginationAdapters: [RelayForward(maxItems)], | ||
} | ||
|
||
// Step5. Add explicit types to gatsby schema | ||
await toolkitCreateSchemaCustomization(config) | ||
|
||
// Step6. Source nodes | ||
await sourceAllNodes(config) | ||
} |
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 @@ | ||
test.todo('add tests') |
Oops, something went wrong.