gatsby
Version:
Blazing fast modern site generator for React
856 lines (829 loc) • 29.2 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = exports.ProdLoader = exports.PageResourceStatus = exports.BaseLoader = void 0;
exports.getSliceResults = getSliceResults;
exports.getStaticQueryResults = getStaticQueryResults;
exports.setLoader = exports.publicLoader = void 0;
var _reactServerDomWebpack = require("react-server-dom-webpack");
var _prefetch = _interopRequireDefault(require("./prefetch"));
var _emitter = _interopRequireDefault(require("./emitter"));
var _findPath = require("./find-path");
/**
* Available resource loading statuses
*/
const PageResourceStatus = {
/**
* At least one of critical resources failed to load
*/
Error: `error`,
/**
* Resources loaded successfully
*/
Success: `success`
};
exports.PageResourceStatus = PageResourceStatus;
const preferDefault = m => m && m.default || m;
const stripSurroundingSlashes = s => {
s = s[0] === `/` ? s.slice(1) : s;
s = s.endsWith(`/`) ? s.slice(0, -1) : s;
return s;
};
const createPageDataUrl = rawPath => {
const [path, maybeSearch] = rawPath.split(`?`);
const fixedPath = path === `/` ? `index` : stripSurroundingSlashes(path);
return `${__PATH_PREFIX__}/page-data/${fixedPath}/page-data.json${maybeSearch ? `?${maybeSearch}` : ``}`;
};
/**
* Utility to check the path that goes into doFetch for e.g. potential malicious intentions.
* It checks for "//" because with this you could do a fetch request to a different domain.
*/
const shouldAbortFetch = rawPath => rawPath.startsWith(`//`);
function doFetch(url, method = `GET`) {
return new Promise(resolve => {
const req = new XMLHttpRequest();
req.open(method, url, true);
req.onreadystatechange = () => {
if (req.readyState == 4) {
resolve(req);
}
};
req.send(null);
});
}
const doesConnectionSupportPrefetch = () => {
if (`connection` in navigator && typeof navigator.connection !== `undefined`) {
if ((navigator.connection.effectiveType || ``).includes(`2g`)) {
return false;
}
if (navigator.connection.saveData) {
return false;
}
}
return true;
};
// Regex that matches common search crawlers
const BOT_REGEX = /bot|crawler|spider|crawling/i;
const toPageResources = (pageData, component = null, head) => {
var _pageData$slicesMap;
const page = {
componentChunkName: pageData.componentChunkName,
path: pageData.path,
webpackCompilationHash: pageData.webpackCompilationHash,
matchPath: pageData.matchPath,
staticQueryHashes: pageData.staticQueryHashes,
getServerDataError: pageData.getServerDataError,
slicesMap: (_pageData$slicesMap = pageData.slicesMap) !== null && _pageData$slicesMap !== void 0 ? _pageData$slicesMap : {}
};
return {
component,
head,
json: pageData.result,
page
};
};
function waitForResponse(response) {
return new Promise(resolve => {
try {
const result = response.readRoot();
resolve(result);
} catch (err) {
if (Object.hasOwnProperty.call(err, `_response`) && Object.hasOwnProperty.call(err, `_status`)) {
setTimeout(() => {
waitForResponse(response).then(resolve);
}, 200);
} else {
throw err;
}
}
});
}
class BaseLoader {
constructor(loadComponent, matchPaths) {
// Map of pagePath -> Page. Where Page is an object with: {
// status: PageResourceStatus.Success || PageResourceStatus.Error,
// payload: PageResources, // undefined if PageResourceStatus.Error
// }
// PageResources is {
// component,
// json: pageData.result,
// page: {
// componentChunkName,
// path,
// webpackCompilationHash,
// staticQueryHashes
// },
// staticQueryResults
// }
this.pageDb = new Map();
this.inFlightDb = new Map();
this.staticQueryDb = {};
this.pageDataDb = new Map();
this.partialHydrationDb = new Map();
this.slicesDataDb = new Map();
this.sliceInflightDb = new Map();
this.slicesDb = new Map();
this.isPrefetchQueueRunning = false;
this.prefetchQueued = [];
this.prefetchTriggered = new Set();
this.prefetchCompleted = new Set();
this.loadComponent = loadComponent;
(0, _findPath.setMatchPaths)(matchPaths);
}
inFlightNetworkRequests = new Map();
memoizedGet(url) {
let inFlightPromise = this.inFlightNetworkRequests.get(url);
if (!inFlightPromise) {
inFlightPromise = doFetch(url, `GET`);
this.inFlightNetworkRequests.set(url, inFlightPromise);
}
// Prefer duplication with then + catch over .finally to prevent problems in ie11 + firefox
return inFlightPromise.then(response => {
this.inFlightNetworkRequests.delete(url);
return response;
}).catch(err => {
this.inFlightNetworkRequests.delete(url);
throw err;
});
}
setApiRunner(apiRunner) {
this.apiRunner = apiRunner;
this.prefetchDisabled = apiRunner(`disableCorePrefetching`).some(a => a);
}
fetchPageDataJson(loadObj) {
const {
pagePath,
retries = 0
} = loadObj;
const url = createPageDataUrl(pagePath);
return this.memoizedGet(url).then(req => {
const {
status,
responseText
} = req;
// Handle 200
if (status === 200) {
try {
const jsonPayload = JSON.parse(responseText);
if (jsonPayload.path === undefined) {
throw new Error(`not a valid pageData response`);
}
const maybeSearch = pagePath.split(`?`)[1];
if (maybeSearch && !jsonPayload.path.includes(maybeSearch)) {
jsonPayload.path += `?${maybeSearch}`;
}
return Object.assign(loadObj, {
status: PageResourceStatus.Success,
payload: jsonPayload
});
} catch (err) {
// continue regardless of error
}
}
// Handle 404
if (status === 404 || status === 200) {
// If the request was for a 404/500 page and it doesn't exist, we're done
if (pagePath === `/404.html` || pagePath === `/500.html`) {
return Object.assign(loadObj, {
status: PageResourceStatus.Error
});
}
// Need some code here to cache the 404 request. In case
// multiple loadPageDataJsons result in 404s
return this.fetchPageDataJson(Object.assign(loadObj, {
pagePath: `/404.html`,
notFound: true
}));
}
// handle 500 response (Unrecoverable)
if (status === 500) {
return this.fetchPageDataJson(Object.assign(loadObj, {
pagePath: `/500.html`,
internalServerError: true
}));
}
// Handle everything else, including status === 0, and 503s. Should retry
if (retries < 3) {
return this.fetchPageDataJson(Object.assign(loadObj, {
retries: retries + 1
}));
}
// Retried 3 times already, result is an error.
return Object.assign(loadObj, {
status: PageResourceStatus.Error
});
});
}
fetchPartialHydrationJson(loadObj) {
const {
pagePath,
retries = 0
} = loadObj;
const url = createPageDataUrl(pagePath).replace(`.json`, `-rsc.json`);
return this.memoizedGet(url).then(req => {
const {
status,
responseText
} = req;
// Handle 200
if (status === 200) {
try {
return Object.assign(loadObj, {
status: PageResourceStatus.Success,
payload: responseText
});
} catch (err) {
// continue regardless of error
}
}
// Handle 404
if (status === 404 || status === 200) {
// If the request was for a 404/500 page and it doesn't exist, we're done
if (pagePath === `/404.html` || pagePath === `/500.html`) {
return Object.assign(loadObj, {
status: PageResourceStatus.Error
});
}
// Need some code here to cache the 404 request. In case
// multiple loadPageDataJsons result in 404s
return this.fetchPartialHydrationJson(Object.assign(loadObj, {
pagePath: `/404.html`,
notFound: true
}));
}
// handle 500 response (Unrecoverable)
if (status === 500) {
return this.fetchPartialHydrationJson(Object.assign(loadObj, {
pagePath: `/500.html`,
internalServerError: true
}));
}
// Handle everything else, including status === 0, and 503s. Should retry
if (retries < 3) {
return this.fetchPartialHydrationJson(Object.assign(loadObj, {
retries: retries + 1
}));
}
// Retried 3 times already, result is an error.
return Object.assign(loadObj, {
status: PageResourceStatus.Error
});
});
}
loadPageDataJson(rawPath) {
const pagePath = (0, _findPath.findPath)(rawPath);
if (this.pageDataDb.has(pagePath)) {
const pageData = this.pageDataDb.get(pagePath);
if (process.env.BUILD_STAGE !== `develop` || !pageData.stale) {
return Promise.resolve(pageData);
}
}
return this.fetchPageDataJson({
pagePath
}).then(pageData => {
this.pageDataDb.set(pagePath, pageData);
return pageData;
});
}
loadPartialHydrationJson(rawPath) {
const pagePath = (0, _findPath.findPath)(rawPath);
if (this.partialHydrationDb.has(pagePath)) {
const pageData = this.partialHydrationDb.get(pagePath);
if (process.env.BUILD_STAGE !== `develop` || !pageData.stale) {
return Promise.resolve(pageData);
}
}
return this.fetchPartialHydrationJson({
pagePath
}).then(pageData => {
this.partialHydrationDb.set(pagePath, pageData);
return pageData;
});
}
loadSliceDataJson(sliceName) {
if (this.slicesDataDb.has(sliceName)) {
const jsonPayload = this.slicesDataDb.get(sliceName);
return Promise.resolve({
sliceName,
jsonPayload
});
}
const url = `${__PATH_PREFIX__}/slice-data/${sliceName}.json`;
return doFetch(url, `GET`).then(res => {
const jsonPayload = JSON.parse(res.responseText);
this.slicesDataDb.set(sliceName, jsonPayload);
return {
sliceName,
jsonPayload
};
});
}
findMatchPath(rawPath) {
return (0, _findPath.findMatchPath)(rawPath);
}
// TODO check all uses of this and whether they use undefined for page resources not exist
loadPage(rawPath) {
const pagePath = (0, _findPath.findPath)(rawPath);
if (this.pageDb.has(pagePath)) {
const page = this.pageDb.get(pagePath);
if (process.env.BUILD_STAGE !== `develop` || !page.payload.stale) {
if (page.error) {
return Promise.resolve({
error: page.error,
status: page.status
});
}
return Promise.resolve(page.payload);
}
}
if (this.inFlightDb.has(pagePath)) {
return this.inFlightDb.get(pagePath);
}
const loadDataPromises = [this.loadAppData(), this.loadPageDataJson(pagePath)];
if (global.hasPartialHydration) {
loadDataPromises.push(this.loadPartialHydrationJson(pagePath));
}
const inFlightPromise = Promise.all(loadDataPromises).then(allData => {
const [appDataResponse, pageDataResponse, rscDataResponse] = allData;
if (pageDataResponse.status === PageResourceStatus.Error || (rscDataResponse === null || rscDataResponse === void 0 ? void 0 : rscDataResponse.status) === PageResourceStatus.Error) {
return {
status: PageResourceStatus.Error
};
}
let pageData = pageDataResponse.payload;
const {
componentChunkName,
staticQueryHashes: pageStaticQueryHashes = [],
slicesMap = {}
} = pageData;
const finalResult = {};
const dedupedSliceNames = Array.from(new Set(Object.values(slicesMap)));
const loadSlice = slice => {
if (this.slicesDb.has(slice.name)) {
return this.slicesDb.get(slice.name);
} else if (this.sliceInflightDb.has(slice.name)) {
return this.sliceInflightDb.get(slice.name);
}
const inFlight = this.loadComponent(slice.componentChunkName).then(component => {
return {
component: preferDefault(component),
sliceContext: slice.result.sliceContext,
data: slice.result.data
};
});
this.sliceInflightDb.set(slice.name, inFlight);
inFlight.then(results => {
this.slicesDb.set(slice.name, results);
this.sliceInflightDb.delete(slice.name);
});
return inFlight;
};
return Promise.all(dedupedSliceNames.map(sliceName => this.loadSliceDataJson(sliceName))).then(slicesData => {
const slices = [];
const dedupedStaticQueryHashes = [...pageStaticQueryHashes];
for (const {
jsonPayload,
sliceName
} of Object.values(slicesData)) {
slices.push({
name: sliceName,
...jsonPayload
});
for (const staticQueryHash of jsonPayload.staticQueryHashes) {
if (!dedupedStaticQueryHashes.includes(staticQueryHash)) {
dedupedStaticQueryHashes.push(staticQueryHash);
}
}
}
const loadChunkPromises = [Promise.all(slices.map(loadSlice)), this.loadComponent(componentChunkName, `head`)];
if (!global.hasPartialHydration) {
loadChunkPromises.push(this.loadComponent(componentChunkName));
}
// In develop we have separate chunks for template and Head components
// to enable HMR (fast refresh requires single exports).
// In production we have shared chunk with both exports. Double loadComponent here
// will be deduped by webpack runtime resulting in single request and single module
// being loaded for both `component` and `head`.
// get list of components to get
const componentChunkPromises = Promise.all(loadChunkPromises).then(components => {
const [sliceComponents, headComponent, pageComponent] = components;
finalResult.createdAt = new Date();
for (const sliceComponent of sliceComponents) {
if (!sliceComponent || sliceComponent instanceof Error) {
finalResult.status = PageResourceStatus.Error;
finalResult.error = sliceComponent;
}
}
if (!global.hasPartialHydration && (!pageComponent || pageComponent instanceof Error)) {
finalResult.status = PageResourceStatus.Error;
finalResult.error = pageComponent;
}
let pageResources;
if (finalResult.status !== PageResourceStatus.Error) {
finalResult.status = PageResourceStatus.Success;
if (pageDataResponse.notFound === true || (rscDataResponse === null || rscDataResponse === void 0 ? void 0 : rscDataResponse.notFound) === true) {
finalResult.notFound = true;
}
pageData = Object.assign(pageData, {
webpackCompilationHash: appDataResponse ? appDataResponse.webpackCompilationHash : ``
});
if (typeof (rscDataResponse === null || rscDataResponse === void 0 ? void 0 : rscDataResponse.payload) === `string`) {
pageResources = toPageResources(pageData, null, headComponent);
pageResources.partialHydration = rscDataResponse.payload;
const readableStream = new ReadableStream({
start(controller) {
const te = new TextEncoder();
controller.enqueue(te.encode(rscDataResponse.payload));
},
pull(controller) {
// close on next read when queue is empty
controller.close();
},
cancel() {}
});
return waitForResponse((0, _reactServerDomWebpack.createFromReadableStream)(readableStream)).then(result => {
pageResources.partialHydration = result;
return pageResources;
});
} else {
pageResources = toPageResources(pageData, pageComponent, headComponent);
}
}
// undefined if final result is an error
return pageResources;
});
// get list of static queries to get
const staticQueryBatchPromise = Promise.all(dedupedStaticQueryHashes.map(staticQueryHash => {
// Check for cache in case this static query result has already been loaded
if (this.staticQueryDb[staticQueryHash]) {
const jsonPayload = this.staticQueryDb[staticQueryHash];
return {
staticQueryHash,
jsonPayload
};
}
return this.memoizedGet(`${__PATH_PREFIX__}/page-data/sq/d/${staticQueryHash}.json`).then(req => {
const jsonPayload = JSON.parse(req.responseText);
return {
staticQueryHash,
jsonPayload
};
}).catch(() => {
throw new Error(`We couldn't load "${__PATH_PREFIX__}/page-data/sq/d/${staticQueryHash}.json"`);
});
})).then(staticQueryResults => {
const staticQueryResultsMap = {};
staticQueryResults.forEach(({
staticQueryHash,
jsonPayload
}) => {
staticQueryResultsMap[staticQueryHash] = jsonPayload;
this.staticQueryDb[staticQueryHash] = jsonPayload;
});
return staticQueryResultsMap;
});
return Promise.all([componentChunkPromises, staticQueryBatchPromise]).then(([pageResources, staticQueryResults]) => {
let payload;
if (pageResources) {
payload = {
...pageResources,
staticQueryResults
};
finalResult.payload = payload;
_emitter.default.emit(`onPostLoadPageResources`, {
page: payload,
pageResources: payload
});
}
this.pageDb.set(pagePath, finalResult);
if (finalResult.error) {
return {
error: finalResult.error,
status: finalResult.status
};
}
return payload;
})
// when static-query fail to load we throw a better error
.catch(err => {
return {
error: err,
status: PageResourceStatus.Error
};
});
});
});
inFlightPromise.then(() => {
this.inFlightDb.delete(pagePath);
}).catch(error => {
this.inFlightDb.delete(pagePath);
throw error;
});
this.inFlightDb.set(pagePath, inFlightPromise);
return inFlightPromise;
}
// returns undefined if the page does not exists in cache
loadPageSync(rawPath, options = {}) {
const pagePath = (0, _findPath.findPath)(rawPath);
if (this.pageDb.has(pagePath)) {
const pageData = this.pageDb.get(pagePath);
if (pageData.payload) {
return pageData.payload;
}
if (options !== null && options !== void 0 && options.withErrorDetails) {
return {
error: pageData.error,
status: pageData.status
};
}
}
return undefined;
}
shouldPrefetch(pagePath) {
// Skip prefetching if we know user is on slow or constrained connection
if (!doesConnectionSupportPrefetch()) {
return false;
}
// Don't prefetch if this is a crawler bot
if (navigator.userAgent && BOT_REGEX.test(navigator.userAgent)) {
return false;
}
// Check if the page exists.
if (this.pageDb.has(pagePath)) {
return false;
}
return true;
}
prefetch(pagePath) {
if (!this.shouldPrefetch(pagePath)) {
return {
then: resolve => resolve(false),
abort: () => {}
};
}
if (this.prefetchTriggered.has(pagePath)) {
return {
then: resolve => resolve(true),
abort: () => {}
};
}
const defer = {
resolve: null,
reject: null,
promise: null
};
defer.promise = new Promise((resolve, reject) => {
defer.resolve = resolve;
defer.reject = reject;
});
this.prefetchQueued.push([pagePath, defer]);
const abortC = new AbortController();
abortC.signal.addEventListener(`abort`, () => {
const index = this.prefetchQueued.findIndex(([p]) => p === pagePath);
// remove from the queue
if (index !== -1) {
this.prefetchQueued.splice(index, 1);
}
});
if (!this.isPrefetchQueueRunning) {
this.isPrefetchQueueRunning = true;
setTimeout(() => {
this._processNextPrefetchBatch();
}, 3000);
}
return {
then: (resolve, reject) => defer.promise.then(resolve, reject),
abort: abortC.abort.bind(abortC)
};
}
_processNextPrefetchBatch() {
const idleCallback = window.requestIdleCallback || (cb => setTimeout(cb, 0));
idleCallback(() => {
const toPrefetch = this.prefetchQueued.splice(0, 4);
const prefetches = Promise.all(toPrefetch.map(([pagePath, dPromise]) => {
// Tell plugins with custom prefetching logic that they should start
// prefetching this path.
if (!this.prefetchTriggered.has(pagePath)) {
this.apiRunner(`onPrefetchPathname`, {
pathname: pagePath
});
this.prefetchTriggered.add(pagePath);
}
// If a plugin has disabled core prefetching, stop now.
if (this.prefetchDisabled) {
return dPromise.resolve(false);
}
return this.doPrefetch((0, _findPath.findPath)(pagePath)).then(() => {
if (!this.prefetchCompleted.has(pagePath)) {
this.apiRunner(`onPostPrefetchPathname`, {
pathname: pagePath
});
this.prefetchCompleted.add(pagePath);
}
dPromise.resolve(true);
});
}));
if (this.prefetchQueued.length) {
prefetches.then(() => {
setTimeout(() => {
this._processNextPrefetchBatch();
}, 3000);
});
} else {
this.isPrefetchQueueRunning = false;
}
});
}
doPrefetch(pagePath) {
const pageDataUrl = createPageDataUrl(pagePath);
if (global.hasPartialHydration) {
return Promise.all([(0, _prefetch.default)(pageDataUrl, {
crossOrigin: `anonymous`,
as: `fetch`
}).then(() =>
// This was just prefetched, so will return a response from
// the cache instead of making another request to the server
this.loadPageDataJson(pagePath)), (0, _prefetch.default)(pageDataUrl.replace(`.json`, `-rsc.json`), {
crossOrigin: `anonymous`,
as: `fetch`
}).then(() =>
// This was just prefetched, so will return a response from
// the cache instead of making another request to the server
this.loadPartialHydrationJson(pagePath))]);
} else {
return (0, _prefetch.default)(pageDataUrl, {
crossOrigin: `anonymous`,
as: `fetch`
}).then(() =>
// This was just prefetched, so will return a response from
// the cache instead of making another request to the server
this.loadPageDataJson(pagePath));
}
}
hovering(rawPath) {
this.loadPage(rawPath);
}
getResourceURLsForPathname(rawPath) {
const pagePath = (0, _findPath.findPath)(rawPath);
const page = this.pageDataDb.get(pagePath);
if (page) {
const pageResources = toPageResources(page.payload);
return [...createComponentUrls(pageResources.page.componentChunkName), createPageDataUrl(pagePath)];
} else {
return null;
}
}
isPageNotFound(rawPath) {
const pagePath = (0, _findPath.findPath)(rawPath);
const page = this.pageDb.get(pagePath);
return !page || page.notFound;
}
loadAppData(retries = 0) {
return this.memoizedGet(`${__PATH_PREFIX__}/page-data/app-data.json`).then(req => {
const {
status,
responseText
} = req;
let appData;
if (status !== 200 && retries < 3) {
// Retry 3 times incase of non-200 responses
return this.loadAppData(retries + 1);
}
// Handle 200
if (status === 200) {
try {
const jsonPayload = JSON.parse(responseText);
if (jsonPayload.webpackCompilationHash === undefined) {
throw new Error(`not a valid app-data response`);
}
appData = jsonPayload;
} catch (err) {
// continue regardless of error
}
}
return appData;
});
}
}
exports.BaseLoader = BaseLoader;
const createComponentUrls = componentChunkName => (window.___chunkMapping[componentChunkName] || []).map(chunk => __PATH_PREFIX__ + chunk);
class ProdLoader extends BaseLoader {
constructor(asyncRequires, matchPaths, pageData) {
const loadComponent = (chunkName, exportType = `components`) => {
if (!global.hasPartialHydration) {
exportType = `components`;
}
if (!asyncRequires[exportType][chunkName]) {
throw new Error(`We couldn't find the correct component chunk with the name "${chunkName}"`);
}
return asyncRequires[exportType][chunkName]()
// loader will handle the case when component is error
.catch(err => err);
};
super(loadComponent, matchPaths);
if (pageData) {
this.pageDataDb.set((0, _findPath.findPath)(pageData.path), {
pagePath: pageData.path,
payload: pageData,
status: `success`
});
}
}
doPrefetch(pagePath) {
return super.doPrefetch(pagePath).then(result => {
if (result.status !== PageResourceStatus.Success) {
return Promise.resolve();
}
const pageData = result.payload;
const chunkName = pageData.componentChunkName;
const componentUrls = createComponentUrls(chunkName);
return Promise.all(componentUrls.map(_prefetch.default)).then(() => pageData);
});
}
loadPageDataJson(rawPath) {
return super.loadPageDataJson(rawPath).then(data => {
if (data.notFound) {
if (shouldAbortFetch(rawPath)) {
return data;
}
// check if html file exist using HEAD request:
// if it does we should navigate to it instead of showing 404
return doFetch(rawPath, `HEAD`).then(req => {
if (req.status === 200) {
// page (.html file) actually exist (or we asked for 404 )
// returning page resources status as errored to trigger
// regular browser navigation to given page
return {
status: PageResourceStatus.Error
};
}
// if HEAD request wasn't 200, return notFound result
// and show 404 page
return data;
});
}
return data;
});
}
loadPartialHydrationJson(rawPath) {
return super.loadPartialHydrationJson(rawPath).then(data => {
if (data.notFound) {
if (shouldAbortFetch(rawPath)) {
return data;
}
// check if html file exist using HEAD request:
// if it does we should navigate to it instead of showing 404
return doFetch(rawPath, `HEAD`).then(req => {
if (req.status === 200) {
// page (.html file) actually exist (or we asked for 404 )
// returning page resources status as errored to trigger
// regular browser navigation to given page
return {
status: PageResourceStatus.Error
};
}
// if HEAD request wasn't 200, return notFound result
// and show 404 page
return data;
});
}
return data;
});
}
}
exports.ProdLoader = ProdLoader;
let instance;
const setLoader = _loader => {
instance = _loader;
};
exports.setLoader = setLoader;
const publicLoader = {
enqueue: rawPath => instance.prefetch(rawPath),
// Real methods
getResourceURLsForPathname: rawPath => instance.getResourceURLsForPathname(rawPath),
loadPage: rawPath => instance.loadPage(rawPath),
// TODO add deprecation to v4 so people use withErrorDetails and then we can remove in v5 and change default behaviour
loadPageSync: (rawPath, options = {}) => instance.loadPageSync(rawPath, options),
prefetch: rawPath => instance.prefetch(rawPath),
isPageNotFound: rawPath => instance.isPageNotFound(rawPath),
hovering: rawPath => instance.hovering(rawPath),
loadAppData: () => instance.loadAppData()
};
exports.publicLoader = publicLoader;
var _default = publicLoader;
exports.default = _default;
function getStaticQueryResults() {
if (instance) {
return instance.staticQueryDb;
} else {
return {};
}
}
function getSliceResults() {
if (instance) {
return instance.slicesDb;
} else {
return {};
}
}
//# sourceMappingURL=loader.js.map
;