@aaaz/gatsby-plugin-remote-images
Version:
Gatsby plugin to use gatsby-image on remote images from absolute path string fields on other nodes.
314 lines (265 loc) • 11 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
const _require = require(`gatsby-source-filesystem`),
createRemoteFileNode = _require.createRemoteFileNode;
const get = require('lodash/get');
let i = 0;
exports.onCreateNode = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)(function* ({
node,
actions,
store,
cache,
createNodeId,
createContentDigest,
reporter
}, options) {
const createNode = actions.createNode;
const nodeType = options.nodeType,
imagePath = options.imagePath,
_options$name = options.name,
name = _options$name === void 0 ? 'localImage' : _options$name,
_options$auth = options.auth,
auth = _options$auth === void 0 ? {} : _options$auth,
_options$ext = options.ext,
ext = _options$ext === void 0 ? null : _options$ext,
_options$prepareUrl = options.prepareUrl,
prepareUrl = _options$prepareUrl === void 0 ? null : _options$prepareUrl,
_options$type = options.type,
type = _options$type === void 0 ? 'object' : _options$type;
const createImageNodeOptions = {
store,
cache,
createNode,
createNodeId,
createContentDigest,
auth,
ext,
name,
prepareUrl
};
if (node.internal.type === nodeType) {
// Check if any part of the path indicates the node is an array and splits at those indicators
let imagePathSegments = [];
if (imagePath.includes('[].')) {
imagePathSegments = imagePath.split('[].');
}
const downloadingFilesActivity = reporter.activityTimer(`Creating local images for ${nodeType}`);
downloadingFilesActivity.start();
if (imagePathSegments.length) {
yield createImageNodesInArrays(imagePathSegments[0], node, Object.assign({
imagePathSegments
}, createImageNodeOptions));
} else if (type === 'array') {
const urls = getPaths(node, imagePath, ext);
yield createImageNodes(urls, node, createImageNodeOptions);
} else {
const url = getPath(node, imagePath, ext);
yield createImageNode(url, node, createImageNodeOptions);
}
downloadingFilesActivity.end();
}
});
return function (_x, _x2) {
return _ref.apply(this, arguments);
};
}();
function getPaths(node, path, ext = null) {
const value = get(node, path);
return value.map(url => ext ? url + ext : url);
} // Returns value from path, adding extension when supplied
function getPath(node, path, ext = null) {
const value = get(node, path);
return ext ? value + ext : value;
} // Returns a unique cache key for a given node ID
function getCacheKeyForNodeId(nodeId) {
return `gatsby-plugin-remote-images-${nodeId}`;
}
function createImageNodes(_x3, _x4, _x5) {
return _createImageNodes.apply(this, arguments);
} // Creates a file node and associates the parent node to its new child
function _createImageNodes() {
_createImageNodes = (0, _asyncToGenerator2.default)(function* (urls, node, options) {
const name = options.name,
imagePathSegments = options.imagePathSegments,
prepareUrl = options.prepareUrl,
restOfOptions = (0, _objectWithoutPropertiesLoose2.default)(options, ["name", "imagePathSegments", "prepareUrl"]);
let fileNode;
if (!urls) {
return;
}
const fileNodes = (yield Promise.all(urls.map( /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator2.default)(function* (url, index) {
if (typeof prepareUrl === 'function') {
url = prepareUrl(url);
}
try {
fileNode = yield createRemoteFileNode(Object.assign({}, restOfOptions, {
url,
parentNodeId: node.id
}));
} catch (e) {
console.error('gatsby-plugin-remote-images ERROR:', e);
}
return fileNode;
});
return function (_x18, _x19) {
return _ref2.apply(this, arguments);
};
}()))).filter(fileNode => !!fileNode); // Store the mapping between the current node and the newly created File node
if (fileNodes.length) {
// This associates the existing node (of user-specified type) with the new
// File nodes created via createRemoteFileNode. The new File nodes will be
// resolved dynamically through the Gatsby schema customization
// createResolvers API and which File node gets resolved for each new field
// on a given node of the user-specified type is determined by the contents
// of this mapping. The keys are based on the ID of the parent node (of
// user-specified type) and the values are each a nested mapping of the new
// image File field name to the ID of the new File node.
const cacheKey = getCacheKeyForNodeId(node.id);
const existingFileNodeMap = yield options.cache.get(cacheKey);
yield options.cache.set(cacheKey, Object.assign({}, existingFileNodeMap, {
[name]: fileNodes.map(({
id
}) => id)
}));
}
});
return _createImageNodes.apply(this, arguments);
}
function createImageNode(_x6, _x7, _x8) {
return _createImageNode.apply(this, arguments);
} // Recursively traverses objects/arrays at each path part, then operates on targeted leaf node
function _createImageNode() {
_createImageNode = (0, _asyncToGenerator2.default)(function* (url, node, options) {
const name = options.name,
imagePathSegments = options.imagePathSegments,
prepareUrl = options.prepareUrl,
restOfOptions = (0, _objectWithoutPropertiesLoose2.default)(options, ["name", "imagePathSegments", "prepareUrl"]);
let fileNode;
if (typeof prepareUrl === 'function') {
url = prepareUrl(url);
}
try {
fileNode = yield createRemoteFileNode(Object.assign({}, restOfOptions, {
url,
parentNodeId: node.id
}));
} catch (e) {
++i;
console.error('gatsby-plugin-remote-images ERROR:', e);
console.log(`creating fake file node ${i}...`);
fileNode = yield options.createNode({
id: options.createNodeId(`${i}`),
parent: node.id,
internal: {
type: 'File',
mediaType: 'application/octet-stream',
contentDigest: options.createContentDigest(`${i}`)
}
}, {
name: 'gatsby-source-filesystem'
});
} // Store the mapping between the current node and the newly created File node
if (fileNode) {
// This associates the existing node (of user-specified type) with the new
// File nodes created via createRemoteFileNode. The new File nodes will be
// resolved dynamically through the Gatsby schema customization
// createResolvers API and which File node gets resolved for each new field
// on a given node of the user-specified type is determined by the contents
// of this mapping. The keys are based on the ID of the parent node (of
// user-specified type) and the values are each a nested mapping of the new
// image File field name to the ID of the new File node.
const cacheKey = getCacheKeyForNodeId(node.id);
const existingFileNodeMap = yield options.cache.get(cacheKey);
yield options.cache.set(cacheKey, Object.assign({}, existingFileNodeMap, {
[name]: fileNode.id
}));
}
});
return _createImageNode.apply(this, arguments);
}
function createImageNodesInArrays(_x9, _x10, _x11) {
return _createImageNodesInArrays.apply(this, arguments);
}
function _createImageNodesInArrays() {
_createImageNodesInArrays = (0, _asyncToGenerator2.default)(function* (path, node, options) {
if (!path || !node) {
return;
}
const imagePathSegments = options.imagePathSegments,
ext = options.ext;
const pathIndex = imagePathSegments.indexOf(path),
isPathToLeafProperty = pathIndex === imagePathSegments.length - 1,
nextValue = getPath(node, path, isPathToLeafProperty ? ext : null); // grab the parent of the leaf property, if it's not the current value of `node` already
// ex: `parentNode` in `myNodes[].parentNode.leafProperty`
let nextNode = node;
if (isPathToLeafProperty && path.includes('.')) {
const pathToLastParent = path.split('.').slice(0, -1).join('.');
nextNode = get(node, pathToLastParent);
} // @TODO: Need logic to handle if the leaf node is an array to then shift
// to the function of createImageNodes.
return Array.isArray(nextValue) ? // Recursively call function with next path segment for each array element
Promise.all(nextValue.map(item => createImageNodesInArrays(imagePathSegments[pathIndex + 1], item, options))) : // otherwise, handle leaf node
createImageNode(nextValue, nextNode, options);
});
return _createImageNodesInArrays.apply(this, arguments);
}
exports.createResolvers = ({
cache,
createResolvers
}, options) => {
const nodeType = options.nodeType,
_options$name2 = options.name,
name = _options$name2 === void 0 ? 'localImage' : _options$name2,
_options$type2 = options.type,
type = _options$type2 === void 0 ? 'object' : _options$type2;
if (type === 'array') {
const resolvers = {
[nodeType]: {
[name]: {
type: '[File]',
resolve: function () {
var _resolve = (0, _asyncToGenerator2.default)(function* (source, _, context) {
const fileNodeMap = yield cache.get(getCacheKeyForNodeId(source.id));
if (!fileNodeMap || !fileNodeMap[name]) {
return [];
}
return fileNodeMap[name].map(id => context.nodeModel.getNodeById({
id
}));
});
function resolve(_x12, _x13, _x14) {
return _resolve.apply(this, arguments);
}
return resolve;
}()
}
}
};
createResolvers(resolvers);
} else {
const resolvers = {
[nodeType]: {
[name]: {
type: 'File',
resolve: function () {
var _resolve2 = (0, _asyncToGenerator2.default)(function* (source, _, context) {
const fileNodeMap = yield cache.get(getCacheKeyForNodeId(source.id));
return context.nodeModel.getNodeById({
id: fileNodeMap[name]
});
});
function resolve(_x15, _x16, _x17) {
return _resolve2.apply(this, arguments);
}
return resolve;
}()
}
}
};
createResolvers(resolvers);
}
};