gatsby
Version:
Blazing fast modern site generator for React
195 lines (149 loc) • 5.76 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.queryRunner = queryRunner;
var _isEmpty2 = _interopRequireDefault(require("lodash/isEmpty"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _reporter = _interopRequireDefault(require("gatsby-cli/lib/reporter"));
var _crypto = _interopRequireDefault(require("crypto"));
var _path = _interopRequireDefault(require("path"));
var _redux = require("../redux");
var _actions = require("../redux/actions");
var _graphqlErrorsCodeframe = require("./graphql-errors-codeframe");
var _errorParser = _interopRequireDefault(require("./error-parser"));
var _pageData = require("../utils/page-data");
var _cacheLmdb = _interopRequireDefault(require("../utils/cache-lmdb"));
let resultHashCache;
function getResultHashCache() {
if (!resultHashCache) {
resultHashCache = new _cacheLmdb.default({
name: `query-result-hashes`,
encoding: `string`
}).init();
}
return resultHashCache;
}
function reportLongRunningQueryJob(queryJob) {
const messageParts = [`This query took more than 15s to run — which is unusually long and might indicate you're querying too much or have some unoptimized code:`, `File path: ${queryJob.componentPath}`];
if (queryJob.isPage) {
const {
path,
context
} = queryJob.context;
messageParts.push(`URL path: ${path}`);
if (!(0, _isEmpty2.default)(context)) {
messageParts.push(`Context: ${JSON.stringify(context, null, 4)}`);
}
}
_reporter.default.warn(messageParts.join(`\n`));
}
function panicQueryJobError(queryJob, errors) {
let urlPath = undefined;
let queryContext = {};
const plugin = queryJob.pluginCreatorId || `none`;
if (queryJob.isPage) {
urlPath = queryJob.context.path;
queryContext = queryJob.context.context;
}
const structuredErrors = errors.map(e => {
const structuredError = (0, _errorParser.default)({
message: e.message,
filePath: undefined,
location: undefined,
error: e
});
structuredError.context = { ...structuredError.context,
codeFrame: (0, _graphqlErrorsCodeframe.getCodeFrame)(queryJob.query, e.locations && e.locations[0].line, e.locations && e.locations[0].column),
filePath: queryJob.componentPath,
...(urlPath ? {
urlPath
} : {}),
...queryContext,
plugin
};
return structuredError;
});
_reporter.default.panicOnBuild(structuredErrors);
}
async function startQueryJob(graphqlRunner, queryJob, parentSpan) {
let isPending = true; // Print out warning when query takes too long
const timeoutId = setTimeout(() => {
if (isPending) {
reportLongRunningQueryJob(queryJob);
}
}, 15000);
return graphqlRunner.query(queryJob.query, queryJob.context, {
parentSpan,
queryName: queryJob.id,
componentPath: queryJob.componentPath
}).finally(() => {
isPending = false;
clearTimeout(timeoutId);
});
}
async function queryRunner(graphqlRunner, queryJob, parentSpan) {
const {
program
} = _redux.store.getState();
_redux.store.dispatch(_actions.actions.queryStart({
path: queryJob.id,
componentPath: queryJob.componentPath,
isPage: queryJob.isPage
})); // Run query
let result; // Nothing to do if the query doesn't exist.
if (!queryJob.query || queryJob.query === ``) {
result = {};
} else {
result = await startQueryJob(graphqlRunner, queryJob, parentSpan);
}
if (result.errors) {
// If there's a graphql error then log the error and exit
panicQueryJobError(queryJob, result.errors);
} // Add the page context onto the results.
if (queryJob && queryJob.isPage) {
result[`pageContext`] = Object.assign({}, queryJob.context);
} // Delete internal data from pageContext
if (result.pageContext) {
delete result.pageContext.path;
delete result.pageContext.internalComponentName;
delete result.pageContext.component;
delete result.pageContext.componentChunkName;
delete result.pageContext.updatedAt;
delete result.pageContext.pluginCreator___NODE;
delete result.pageContext.pluginCreatorId;
delete result.pageContext.componentPath;
delete result.pageContext.context;
delete result.pageContext.isCreatedByStatefulCreatePages;
delete result.pageContext.matchPath;
delete result.pageContext.mode;
}
const resultJSON = JSON.stringify(result);
const resultHash = _crypto.default.createHash(`sha1`).update(resultJSON).digest(`base64`);
const resultHashCache = getResultHashCache();
if (resultHash !== (await resultHashCache.get(queryJob.id)) || queryJob.isPage && !(0, _pageData.pageDataExists)(_path.default.join(program.directory, `public`), queryJob.id)) {
await resultHashCache.set(queryJob.id, resultHash);
if (queryJob.isPage) {
// We need to save this temporarily in cache because
// this might be incomplete at the moment
await (0, _pageData.savePageQueryResult)(program.directory, queryJob.id, resultJSON);
_redux.store.dispatch({
type: `ADD_PENDING_PAGE_DATA_WRITE`,
payload: {
path: queryJob.id
}
});
} else {
const resultPath = _path.default.join(program.directory, `public`, `page-data`, `sq`, `d`, `${queryJob.hash}.json`);
await _fsExtra.default.outputFile(resultPath, resultJSON);
}
} // Broadcast that a page's query has run.
_redux.store.dispatch(_actions.actions.pageQueryRun({
path: queryJob.id,
componentPath: queryJob.componentPath,
isPage: queryJob.isPage,
resultHash,
queryHash: queryJob.hash
}));
return result;
}
//# sourceMappingURL=query-runner.js.map