The production-app.js file is the entry point to Webpack. It yields the app-[contenthash].js file, which is responsible for all navigation and page loading subsequent to the loading of the initial HTML in the browser. On first load, the HTML loads immediately; it includes a CDATA
section (indicating a portion of unescaped text) that injects page information into the window
object such that it’s available in JavaScript straight away. In this example output, we have just refreshed the browser on a Gatsby site’s /blog/3 page:
<![
CDATA[ */
window.page={
"path": "/blog/3.js",
"componentChunkName": "component---src-blog-3-js",
"jsonName": "blog-3-995"
};
window.dataPath="621/path---blog-3-995-a74-dwfQIanOJGe2gi27a9CLKHjamc";
*/ ]
]>
Thereafter, the application, webpack-runtime
, component, shared libraries, and data JSON bundles are loaded through <link>
and <script>
elements, upon which the production-app.js code initializes.
The very first thing the application does in the browser is execute the onClientEntry
browser API, which enables plugins to perform any important operations prior to any other page-loading logic (e.g., rehydration performed by gatsby-plugin-glamor
). The browser API executor differs considerably from api-runner-node
, which runs Node APIs. api-runner-browser.js iterates through the site’s browser plugins that have been registered and executes them one by one (after retrieving the plugins list from ./cache/api-runner-browser-plugins.js, generated early in the Gatsby bootstrap).
Second, the bundle executes hydrate
, a ReactDOM function that behaves the same way as render
, with the exception that rather than generating an entirely new DOM tree and inserting it into the document, hydrate
expects a ReactDOM tree to be present on the page already sharing precisely the same structure. Upon identifying the matching tree, it traverses the tree to attach required event listeners to “enliven” the React DOM. This hydration process operates on the <div id="___gatsby">...</div>
element found in cache-dir/default-html.js.
Third, the production-app.js file uses @reach/router
to replace the existing DOM with a RouteHandler
component that utilizes PageRenderer
to create the page to which the user has just navigated and load the page resources for that path. However, on first load, the page resources for the given path will already be available in the page’s initial HTML thanks to the <link rel="preload" ... />
element. These resources include the imported component, which Gatsby leverages to generate the page component by executing React.createElement()
. Then, the element is presented to the RouteHandler
for @reach/router
to execute rendering.
Prior to rehydration, Gatsby begins the process of loading background resources ahead of time—namely, page resources that will be required once the user begins to navigate through links and other elements on the page. This loading of page resources occurs in cache-dir/loader.js, whose main function is getResourcesForPathname
. This function accepts a path, discovers the associated page, and imports the component module’s JSON query results. Access to that information is furnished by async-requires.js, which includes a list of every page on the Gatsby site and each associated dataPath
. The fetchPageResourcesMap
function is responsible for retrieving that file, which happens upon the first invocation of getResourcesForPathname
.
NOTE
To provide global state, Gatsby attaches state variables to the window
object such that they can be used by plugins, such as window.___loader
, window.___emitter
, window.___chunkMapping, window.___push
, window.___replace
, and window.___navigate
. For more information about these, consult the Gatsby documentation’s guide to window
variables.
Leave a Reply