-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(docs): Fix docs starting with n #19065
Changes from all commits
4868dec
0693022
6f79f52
6078c2f
3806526
fa730df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,13 +2,13 @@ | |||||
title: Node Creation | ||||||
--- | ||||||
|
||||||
Nodes are created by calling the [createNode](/docs/actions/#createNode) action. Nodes can be any object. | ||||||
Calling the [createNode](/docs/actions/#createNode) action creates nodes. Which can be any object. | ||||||
|
||||||
A node is stored in redux under the `nodes` namespace, whose state is a map of the node ID to the actual node object. | ||||||
Redux stores nodes under the `nodes` namespace, whose state is a map of the node ID to the actual node object. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Sourcing Nodes | ||||||
|
||||||
The creation of nodes occurs primarily in the [sourceNodes](/docs/node-apis/#sourceNodes) bootstrap phase. Nodes created during this phase are top level nodes. I.e, they have no parent. This is represented by source plugins setting the node's `parent` field to `null`. Nodes created via transform plugins (who implement [onCreateNode](/docs/node-apis/#onCreateNode)) will have source nodes as their parents, or other transformed nodes. For a rough overview of what happens when source nodes run, see the [traceID illustration](/docs/how-plugins-apis-are-run/#using-traceid-to-await-downstream-api-calls). | ||||||
The creation of nodes occurs primarily in the [sourceNodes](/docs/node-apis/#sourceNodes) bootstrap phase. Nodes created during this phase are top level nodes. I.e, they have no parent. source plugins setting the node's `parent` field to `null` represents this. Nodes created via transform plugins (who implement [onCreateNode](/docs/node-apis/#onCreateNode)) will have source nodes as their parents, or other transformed nodes. For a rough overview of what happens when source nodes run, see the [traceID illustration](/docs/how-plugins-apis-are-run/#using-traceid-to-await-downstream-api-calls). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Parent/Child/Refs | ||||||
|
||||||
|
@@ -30,13 +30,13 @@ An important note here is that we do not store a distinct collection of each typ | |||||
|
||||||
### Explicitly recording a parent/child relationship | ||||||
|
||||||
This occurs when a transformer plugin implements [onCreateNode](/docs/node-apis/#onCreateNode) in order to create some child of the originally created node. In this case, the transformer plugin will call [createParentChildLink](/docs/actions/#createParentChildLink), with the original node, and the newly created node. All this does is push the child's node ID onto the parent's `children` collection and resave the parent to redux. | ||||||
This occurs when a transformer plugin implements [onCreateNode](/docs/node-apis/#onCreateNode) in order to create some child of the originally created node. In this case, the transformer plugin will call [createParentChildLink](/docs/actions/#createParentChildLink), with the original node, and the created node. All this does is push the child's node ID onto the parent's `children` collection and resave the parent to redux. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Not sure if we need to remove this? |
||||||
|
||||||
This does **not** automatically create a `parent` field on the child node. If a plugin author wishes to allow child nodes to navigate to their parents in GraphQL queries, they must explicitly set `childNode.parent: 'parent.id'` when creating the child node. | ||||||
|
||||||
### Foreign Key reference (`___NODE`) | ||||||
|
||||||
We've established that child nodes are stored at the top level in redux, and are referenced via ids in their parent's `children` collection. The same mechanism drives foreign key relationships. Foreign key fields have a `___NODE` suffix on the field name. At query time, Gatsby will take the field's value as an ID, and search redux for a matching node. This is explained in more detail in [schema gqlTypes](/docs/schema-gql-type#foreign-key-reference-___node). | ||||||
We've established that child nodes are stored at the top level in redux, and are referenced via ids in their parent's `children` collection. The same mechanism drives foreign key relationships. Foreign key fields have a `___NODE` suffix on the field name. At query time, Gatsby will take the field's value as an ID, and search redux for a matching node. [Schema gqlTypes](/docs/schema-gql-type#foreign-key-reference-___node) explains this in more detail. | ||||||
|
||||||
### Plain objects at creation time | ||||||
|
||||||
|
@@ -51,25 +51,25 @@ Let's say you create the following node by passing it to `createNode` | |||||
} | ||||||
``` | ||||||
|
||||||
The value for `baz` is itself an object. That value's parent is the top level object. In this case, Gatsby simply saves the top level node as is to redux. It doesn't attempt to extract `baz` into its own node. It does however track the subobject's root NodeID using [Node Tracking](/docs/node-tracking/) | ||||||
The value for `baz` is itself an object. That value's parent is the top level object. In this case, Gatsby simply saves the top level node as is to redux. It doesn't attempt to extract `baz` into its node. But it tracks the subobject's root NodeID using [Node Tracking](/docs/node-tracking/) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would revert this change? I don't think this is in the scope of the issue that we mean to address? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, reverting this. |
||||||
|
||||||
During schema compilation, Gatsby will infer the sub object's type while [creating the gqlType](/docs/schema-gql-type#plain-object-or-value-field). | ||||||
|
||||||
## Fresh/stale nodes | ||||||
|
||||||
Every time a build is re-run, there is a chance that a node that exists in the redux store no longer exists in the original data source. E.g. a file might be deleted from disk between runs. We need a way to indicate that fact to Gatsby. | ||||||
Every time a build is re-run, there is a chance that a node that exists in the redux store no longer exists in the original data source. E.g. a file might be deleted from disk between runs. We need a way to state that fact to Gatsby. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reverting it. |
||||||
|
||||||
To track this, there is a redux `nodesTouched` namespace that tracks whether a particular node ID has been touched. This occurs whenever a node is created (handled by [CREATE_NODE](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/redux/reducers/nodes-touched.js)), or an explicit call to [touchNode](/docs/actions/#touchNode). | ||||||
|
||||||
When a `source-nodes` plugin runs again, it generally recreates nodes (which automatically touches them too). But in some cases, such as [transformer-screenshot](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-transformer-screenshot/src/gatsby-node.js#L56), a node might not change, but we still want to keep it around for the build. In these cases, we must explicitly call `touchNode`. | ||||||
|
||||||
Any nodes that aren't touched by the end of the `source-nodes` phase, are deleted. This is performed via a diff between the `nodesTouched` and `nodes` redux namespaces, in [source-nodes.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/source-nodes.js) | ||||||
Any nodes that aren't touched by the end of the `source-nodes` phase are deleted. This is performed via a diff between the `nodesTouched` and `nodes` redux namespaces, in [source-nodes.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/source-nodes.js) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Changing a node's fields | ||||||
|
||||||
From a site developer's point of view, nodes are immutable. In the sense that if you simply change a node object, those changes will not be seen by other parts of Gatsby. To make a change to a node, it must be persisted to redux via an action. | ||||||
From a site developer's point of view, nodes are immutable. In the sense that if you simply change a node object, other parts of Gatsby will not see those changes. To make a change to a node, it must be persisted to redux via an action. | ||||||
|
||||||
So, how do you add a field to an existing node? E.g. perhaps in onCreateNode, you want to add a transformer specific field? You can call [createNodeField](/docs/actions/#createNodeField) and this will simply add your field to the node's `node.fields` object and then persists it to redux. This can then be referenced by other parts of your plugin at later stages of the build. | ||||||
So, how do you add a field to an existing node? E.g. in onCreateNode, you want to add a transformer specific field? You can call [createNodeField](/docs/actions/#createNodeField) and this will simply add your field to the node's `node.fields` object and then persists it to redux. Then the other parts of your plugin at later stages of the build can reference this. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure if this is necessary? I personally find the current state more readable 🤷♂ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought it would be better to convert from passive voice.
Sounded rather cleaner to me than:
I'm not a native speaker, and I'm not sure about any of these changes. Please let me know which one is actually better, I will revert it asap. |
||||||
|
||||||
## Node Tracking | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -23,6 +23,8 @@ internal: { | |||||
...other fields specific to this type of node | ||||||
``` | ||||||
|
||||||
## Node Types | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
### `parent` | ||||||
|
||||||
Reserved for plugins who wish to extend other nodes. | ||||||
|
@@ -35,27 +37,27 @@ The digest should be unique to the content of this node since it's used for cach | |||||
|
||||||
### `mediaType` | ||||||
|
||||||
Optional [media type](https://en.wikipedia.org/wiki/Media_type) to indicate to transformer plugins this node has data they can further process. | ||||||
Optional [media type](https://en.wikipedia.org/wiki/Media_type) to notify the transformer plugins this node has data they can further process. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure if this is necessary |
||||||
|
||||||
### `type` | ||||||
|
||||||
A globally unique node type chosen by the plugin owner. | ||||||
|
||||||
### `owner` | ||||||
|
||||||
The plugin which created this node. This field is added by gatsby itself (and not the plugin). | ||||||
The plugin which created this node. Gatsby adds this field itself (not the plugin). | ||||||
|
||||||
### `fieldOwners` | ||||||
|
||||||
Stores which plugins created which fields. This field is added by gatsby itself (and not the plugin). | ||||||
Stores which plugins created which fields. Gatsby adds this field itself (not the plugin). | ||||||
|
||||||
### `content` | ||||||
|
||||||
Optional field exposing the raw content for this node that transformer plugins can take and further process. | ||||||
|
||||||
## Source plugins | ||||||
|
||||||
New nodes are added to Gatsby by "source" plugins. A common one that many Gatsby | ||||||
`Source` plugins adds new nodes to Gatbsy. A common one that many Gatsby | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
sites use is the [Filesystem source plugin](/packages/gatsby-source-filesystem/) | ||||||
which turns files on disk into File nodes. | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -47,15 +47,15 @@ Its sub objects are `foo` (value = `{ myfile: "blog/my-blog.md", b: 2}`), and th | |||||
|
||||||
## Find Root Nodes | ||||||
|
||||||
To access this information, `node-tracking.js` provides the [findRootNodeAncestor()](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/schema/node-tracking.js#L52) function. It takes an object, and looks up its parent's nodeID in `rootNodeMap`. It then finds the actual node in redux. It then gets that node's `parent` ID, and gets the parent node from redux. And continues in this way until the root node is found. | ||||||
To access this information, `node-tracking.js` provides the [findRootNodeAncestor()](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/schema/node-tracking.js#L52) function. It takes an object, and looks up its parent's nodeID in `rootNodeMap`. It then finds the actual node in redux. It then gets that node's `parent` ID, and gets the parent node from redux. And continues in this way until it founds the root node. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
In the above example, `nodeA` has parent `id1`. So `findRootNodeAncestor({ blog: "blog/my-blog.md", b: 2 })` would return the node for `id1` (the parent). | ||||||
|
||||||
## Why/Where? | ||||||
|
||||||
Where is node-tracking used? First up, nodes are tracked in 2 places. Firstly, in [createNode](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/redux/actions.js#L539), every time a node is created, we link all its sub objects to the new NodeID. Nodes are also tracked whenever they are resolved in [run-sift](/docs/schema-sift/#3-resolve-inner-query-fields-on-all-nodes). This is necessary because [custom plugin fields](/docs/schema-input-gql/#inferring-input-filters-from-plugin-fields/) might return new objects that weren't created when the node was initially made. | ||||||
Where is node-tracking used? First up, nodes are tracked in 2 places. Firstly, in [createNode](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/redux/actions.js#L539), every time a node is created, Gatsby links all its subobjects to the new NodeID. Nodes are also tracked whenever they are resolved in [run-sift](/docs/schema-sift/#3-resolve-inner-query-fields-on-all-nodes). This is necessary because [custom plugin fields](/docs/schema-input-gql/#inferring-input-filters-from-plugin-fields/) might return new objects that weren't created when the node was initially made. | ||||||
|
||||||
Now, where do we use this information? In 2 places. | ||||||
Now, where do you use this information? In 2 places. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
1. In the `File` type resolver. It is used to lookup the node's root, which should be of type `File`. We can then use that root node's base directory attribute to create the full path of the resolved field's value, and therefore find the actual `File` node that the string value is describing. See [File GqlType inference](/docs/schema-gql-type/#file-types) for more info. | ||||||
1. In the `File` type resolver. It is used to lookup the node's root, which should be of type `File`. You can then use that root node's base directory attribute to create the full path of the resolved field's value, and therefore find the actual `File` node that the string value is describing. See [File GqlType inference](/docs/schema-gql-type/#file-types) for more info. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
1. To recursively look up node descriptions in [type-conflict-reporter.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/schema/type-conflict-reporter.js) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.