Skip to content
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

Adds gatsby-source-swiftype to theme #185

Merged
merged 2 commits into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/gatsby-theme-newrelic/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = ({ newrelic, robots = {}, gaTrackingId }) => {
module.exports = ({ newrelic, swiftype, robots = {}, gaTrackingId }) => {
return {
plugins: [
'gatsby-plugin-emotion',
Expand All @@ -25,6 +25,10 @@ module.exports = ({ newrelic, robots = {}, gaTrackingId }) => {
resolve: 'gatsby-plugin-newrelic',
options: newrelic,
},
swiftype && {
resolve: 'gatsby-source-swiftype',
options: swiftype,
},
{
resolve: 'gatsby-source-filesystem',
options: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const fs = require('fs');
const createRelatedResourceNode = require('./src/createRelatedResourceNode');
const getRelatedResources = require('./src/getRelatedResources');

const writeableData = {};

exports.onPreBootstrap = (_, pluginOptions) => {
const { file } = pluginOptions;

if (!fs.existsSync(file)) {
fs.writeFileSync(file, '{}');
}
};

exports.onCreateNode = async (
{ actions, node, getNodesByType, createNodeId, createContentDigest },
pluginOptions
) => {
const { createNode, createParentChildLink } = actions;
const { filterNode = () => false, getPath } = pluginOptions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this filterNode function do? how does this inline function work

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is being used as a default value in case filterNode isn't specified. If we use this plugin without filterNode, it will just be a function that always returns false.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason that filterNode returns false rather than true is that we want to avoid executing searches on Swiftype for pages that aren't explicitly set as needing related resources. This helps us avoid the cost of executing a query against Swiftype for pages that we don't use this for.


if (node.internal.type !== 'Mdx' || !filterNode({ node })) {
return;
}

const [
{
siteMetadata: { siteUrl },
},
] = getNodesByType('Site');

const pathname = getPath({ node });
const resources = await getRelatedResources({ node, siteUrl }, pluginOptions);

writeableData[pathname] = resources;

resources.forEach((resource) => {
const child = createRelatedResourceNode({
parent: node.id,
resource,
createContentDigest,
createNode,
createNodeId,
});

createParentChildLink({ parent: node, child: child });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing that in order to get the related resources we'll query for the children of the node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is just copying what we had before. I didn't write the original code, but I believe we need to establish a relationship so that we can query related content for a specific page.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This creates a childrenRelatedPages (if I remember correctly) field on the parent so that you can query for it for the current page.

});
};

exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions;

const typeDefs = `
type RelatedResource implements Node {
id: ID!
title: String!
url: String!
}
`;

createTypes(typeDefs);
};

exports.createResolvers = ({ createResolvers }) => {
createResolvers({
Mdx: {
relatedResources: {
args: {
limit: {
type: 'Int',
defaultValue: 5,
},
},
type: ['RelatedResource!'],
resolve: (source, args, context) => {
const { limit } = args;

return context.nodeModel
.getNodesByIds({ ids: source.children })
.slice(0, Math.max(limit, 0));
},
},
},
});
};

exports.onPostBootstrap = (_, pluginOptions) => {
const { refetch, file } = pluginOptions;

if (refetch) {
fs.writeFileSync(file, JSON.stringify(writeableData, null, 2));
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = ({
createNode,
createNodeId,
createContentDigest,
resource,
parent,
}) => {
const node = {
id: createNodeId(`RelatedResource-${resource.url}`),
title: resource.title,
url: resource.url,
parent,
children: [],
plugin: 'gatsby-source-swiftype',
internal: {
type: 'RelatedResource',
content: JSON.stringify(resource),
contentDigest: createContentDigest(resource),
},
};

createNode(node);

return node;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const fs = require('fs');
const search = require('./search');

module.exports = async ({ node, siteUrl }, pluginOptions) => {
const {
refetch,
engineKey,
limit,
file,
getParams = () => ({}),
getPath,
} = pluginOptions;

const pathname = getPath({ node });

if (refetch) {
return search(siteUrl + pathname, getParams({ node }), {
engineKey,
limit,
});
}

const data = JSON.parse(fs.readFileSync(file));

return data[pathname] || [];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const fetch = require('node-fetch');
const { appendTrailingSlash, stripTrailingSlash } = require('./utils/url');

const normalizeUrl = (url) => {
const prefix = url.startsWith('!') ? '!' : '';
const plainUrl = url.replace(/^!/, '');

return [
prefix + appendTrailingSlash(plainUrl),
prefix + stripTrailingSlash(plainUrl),
];
};

const uniq = (arr) => [...new Set(arr)];

module.exports = async (url, params = {}, { engineKey, limit }) => {
const { page: pageFilters = {} } = params.filters || {};

const res = await fetch(
'https://search-api.swiftype.com/api/v1/public/engines/search.json',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...params,
engine_key: engineKey,
per_page: limit,
filters: {
...params.filters,
page: {
...pageFilters,
url: uniq([
...normalizeUrl(`!${url}`),
...(pageFilters.url || []).flatMap(normalizeUrl),
]),
},
},
}),
}
);

const { records } = await res.json();

return records.page;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const hasQueryParams = (urlString) => {
const url = new URL(urlString);

return Boolean(url.search);
};

exports.appendTrailingSlash = (url) => {
if (hasQueryParams(url)) {
return url;
}

return url.endsWith('/') ? url : `${url}/`;
};

exports.stripTrailingSlash = (url) => {
if (hasQueryParams(url)) {
return url;
}

return url.endsWith('/') ? url.replace(/\/$/, '') : url;
};