gatsby-plugin-multi-language-sitemap
Version:
Gatsby plugin that automatically creates a sitemap supporting multi-language for your site
337 lines (259 loc) • 13.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _path = _interopRequireDefault(require("path"));
var _optionsValidation = require("./options-validation");
var _fs = _interopRequireDefault(require("fs"));
var _internals = require("./internals");
var _sitemapxml = require("./sitemapxml");
var _excluded = ["url"];
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
exports.pluginOptionsSchema = _optionsValidation.pluginOptionsSchema;
exports.onPostBuild = /*#__PURE__*/function () {
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref, _ref2) {
var graphql, reporter, output, query, excludes, resolveSiteUrl, resolvePagePath, resolvePages, filterPages, serialize, langs, combinedHrefs, _yield$graphql, queryRecords, errors, siteUrl, allPages, _pageFilter, filteredPages, messages, serializedPages, _iterator, _step, page, _yield$Promise$resolv, url, rest, sitemapWritePath, sitemapPublicPath, urlLangToHreflangMap, urlLangs, _iterator2, _step2, langObj;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
graphql = _ref.graphql, reporter = _ref.reporter;
output = _ref2.output, query = _ref2.query, excludes = _ref2.excludes, resolveSiteUrl = _ref2.resolveSiteUrl, resolvePagePath = _ref2.resolvePagePath, resolvePages = _ref2.resolvePages, filterPages = _ref2.filterPages, serialize = _ref2.serialize, langs = _ref2.langs, combinedHrefs = _ref2.combinedHrefs;
_context.next = 4;
return graphql(query);
case 4:
_yield$graphql = _context.sent;
queryRecords = _yield$graphql.data;
errors = _yield$graphql.errors;
_context.next = 9;
return Promise.resolve(resolveSiteUrl(queryRecords)).catch(function (err) {
return reporter.panic(_internals.REPORTER_PREFIX + " Error resolving Site URL", err);
});
case 9:
siteUrl = _context.sent;
if (errors) {
reporter.panic("Error executing the GraphQL query inside gatsby-plugin-sitemap:\n", errors);
}
_context.next = 13;
return Promise.resolve(resolvePages(queryRecords)).catch(function (err) {
return reporter.panic(_internals.REPORTER_PREFIX + " Error resolving Pages", err);
});
case 13:
allPages = _context.sent;
if (!Array.isArray(allPages)) {
reporter.panic(_internals.REPORTER_PREFIX + " The `resolvePages` function did not return an array.");
}
reporter.verbose(_internals.REPORTER_PREFIX + " Filtering " + allPages.length + " pages based on " + excludes.length + " excludes");
_pageFilter = (0, _internals.pageFilter)({
allPages: allPages,
filterPages: filterPages,
excludes: excludes
}, {
reporter: reporter
}), filteredPages = _pageFilter.filteredPages, messages = _pageFilter.messages;
messages.forEach(function (message) {
return reporter.verbose(message);
});
reporter.verbose(_internals.REPORTER_PREFIX + " " + filteredPages.length + " pages remain after filtering");
serializedPages = [];
_iterator = _createForOfIteratorHelperLoose(filteredPages);
case 21:
if ((_step = _iterator()).done) {
_context.next = 37;
break;
}
page = _step.value;
_context.prev = 23;
_context.next = 26;
return Promise.resolve(serialize(page, {
resolvePagePath: resolvePagePath
}));
case 26:
_yield$Promise$resolv = _context.sent;
url = _yield$Promise$resolv.url;
rest = (0, _objectWithoutPropertiesLoose2.default)(_yield$Promise$resolv, _excluded);
serializedPages.push((0, _extends2.default)({
shorturl: url,
// for langs classfication
url: (0, _internals.prefixPath)({
url: url,
siteUrl: siteUrl
})
}, rest));
_context.next = 35;
break;
case 32:
_context.prev = 32;
_context.t0 = _context["catch"](23);
reporter.panic(_internals.REPORTER_PREFIX + " Error serializing pages", _context.t0);
case 35:
_context.next = 21;
break;
case 37:
sitemapWritePath = _path.default.join("public", output);
sitemapPublicPath = _path.default.posix.normalize(output); // add x-default
langs = langs.includes("x-default") ? langs : langs.push("x-default") && langs; // map url lang to hreflang
urlLangToHreflangMap = new Map();
urlLangs = [];
for (_iterator2 = _createForOfIteratorHelperLoose(langs); !(_step2 = _iterator2()).done;) {
langObj = _step2.value;
if (typeof langObj === "string") {
urlLangs.push(langObj);
urlLangToHreflangMap.set(langObj, langObj);
} else {
urlLangs.push(langObj.urlLang);
urlLangToHreflangMap.set(langObj.urlLang, langObj.hreflang);
}
}
return _context.abrupt("return", resolveSitemapAndIndex({
hostname: siteUrl,
publicBasePath: sitemapPublicPath,
destinationDir: sitemapWritePath,
sourceData: serializedPages,
langs: urlLangs,
urlLangToHreflangMap: urlLangToHreflangMap,
combinedHrefs: combinedHrefs
}));
case 44:
case "end":
return _context.stop();
}
}
}, _callee, null, [[23, 32]]);
}));
return function (_x, _x2) {
return _ref3.apply(this, arguments);
};
}(); // resolve sitemap and index
var resolveSitemapAndIndex = function resolveSitemapAndIndex(_ref4) {
var hostname = _ref4.hostname,
_ref4$publicBasePath = _ref4.publicBasePath,
publicBasePath = _ref4$publicBasePath === void 0 ? "./" : _ref4$publicBasePath,
destinationDir = _ref4.destinationDir,
sourceData = _ref4.sourceData,
langs = _ref4.langs,
urlLangToHreflangMap = _ref4.urlLangToHreflangMap,
combinedHrefs = _ref4.combinedHrefs;
// mkdir if not exist
_fs.default.mkdirSync(destinationDir, {
recursive: true
}); // normalize path
if (!publicBasePath.endsWith("/")) {
publicBasePath += "/";
} // pipe items file
var urlsMap = generateUrlsMap(langs, sourceData);
var _generatefilesInfoArr = generatefilesInfoArray(urlsMap, langs, urlLangToHreflangMap),
pagesContentCombine = _generatefilesInfoArr.pagesContentCombine,
pagesContent = _generatefilesInfoArr.pagesContent;
langs = []; // clear langs to filter langs that had no items.
for (var _iterator3 = _createForOfIteratorHelperLoose(pagesContent), _step3; !(_step3 = _iterator3()).done;) {
var _step3$value = _step3.value,
lang = _step3$value.lang,
pageContent = _step3$value.pageContent;
_fs.default.writeFileSync(_path.default.resolve(destinationDir, lang + "-sitemap.xml"), pageContent);
langs.push(lang);
} // if combined hrefs pipe combined file
if (combinedHrefs) {
_fs.default.writeFileSync(_path.default.resolve(destinationDir, "sitemap.xml"), pagesContentCombine);
} // pipe index file
var sitemapIndexLocs = langs.map(function (lang) {
return hostname + _path.default.normalize(publicBasePath + lang + "-sitemap.xml");
}); // if combined hrefs
// add sitemap.xml
if (combinedHrefs) sitemapIndexLocs = [hostname + _path.default.normalize(publicBasePath + "sitemap.xml")].concat(sitemapIndexLocs);
var sitemapIndexXML = (0, _sitemapxml.generateSitemapIndexXML)(sitemapIndexLocs);
var sitemapIndexWritePath = _path.default.resolve(destinationDir, "sitemap-index.xml");
_fs.default.writeFileSync(sitemapIndexWritePath, sitemapIndexXML);
return {
sitemapIndexXML: sitemapIndexXML,
pagesContent: pagesContent
};
}; // generate all files info array
// the pageContent data sturcture like this, [{lang:string, fileContent:string}, ]
// pagesContentCombine combine all pageContent
function generatefilesInfoArray(urlsMap, langs, urlLangToHreflangMap) {
var pagesContent = [];
var allData = [];
var pageSumDataArray = [];
for (var _iterator4 = _createForOfIteratorHelperLoose(urlsMap), _step4; !(_step4 = _iterator4()).done;) {
var _step4$value = _step4.value,
_ = _step4$value[0],
source = _step4$value[1];
var dataCombine = generateXMLBySource(source, urlLangToHreflangMap);
allData.push(dataCombine);
}
for (var _iterator5 = _createForOfIteratorHelperLoose(langs), _step5; !(_step5 = _iterator5()).done;) {
var lang = _step5.value;
var pageContentArray = []; // one page's content
for (var _iterator6 = _createForOfIteratorHelperLoose(allData), _step6; !(_step6 = _iterator6()).done;) {
var _step6$value = _step6.value,
xmlArrayDataString = _step6$value[0],
xmlMapData = _step6$value[1];
var xmlLoc = void 0;
if (xmlMapData.get(lang)) {
xmlLoc = (0, _sitemapxml.wrapWithLoc)(xmlMapData.get(lang));
} else {
continue; // not contains this lang
}
var urlData = (0, _sitemapxml.wrapWithUrl)(xmlLoc + xmlArrayDataString);
pageContentArray.push(urlData);
pageSumDataArray.push(urlData);
}
if (pageContentArray.length === 0) continue;
var pageContent = (0, _sitemapxml.wrapWithXMLHeader)((0, _sitemapxml.wrapWithUrlset)(pageContentArray.join("")));
pagesContent.push({
lang: lang,
pageContent: pageContent
});
}
return {
pagesContentCombine: (0, _sitemapxml.wrapWithXMLHeader)((0, _sitemapxml.wrapWithUrlset)(pageSumDataArray.join(""))),
pagesContent: pagesContent
};
} // generate all xml array data by source data
function generateXMLBySource(source, urlLangToHreflangMap) {
var xmlArrayData = [];
var xmlMapData = new Map();
for (var _iterator7 = _createForOfIteratorHelperLoose(source), _step7; !(_step7 = _iterator7()).done;) {
var _step7$value = _step7.value,
lang = _step7$value.lang,
url = _step7$value.url;
var hreflang = urlLangToHreflangMap.get(lang);
var xmlData = (0, _sitemapxml.wrapWithXMLLink)(hreflang, url);
xmlArrayData.push(xmlData);
xmlMapData.set(lang, url);
}
return [xmlArrayData.join(""), xmlMapData];
} // for classfication
// the map (k,v) represents (url, langs array). for example, ('/', [en, fr])
function generateUrlsMap(langs, sourceData) {
// record langs in a map
var langsMap = new Map();
for (var _iterator8 = _createForOfIteratorHelperLoose(langs), _step8; !(_step8 = _iterator8()).done;) {
var lang = _step8.value;
langsMap.set(lang, true);
}
var urlsMap = new Map();
for (var _iterator9 = _createForOfIteratorHelperLoose(sourceData), _step9; !(_step9 = _iterator9()).done;) {
var data = _step9.value;
// classify by short url
var shorturl = data.shorturl;
var _lang = shorturl.split("/")[1];
var hasLang = langsMap.get(_lang);
if (hasLang) {
// remove lang prefix
shorturl = "/" + shorturl.split("/").slice(2).join("/");
} else {
_lang = "x-default";
}
if (!urlsMap.get(shorturl)) urlsMap.set(shorturl, []);
urlsMap.get(shorturl).push((0, _extends2.default)({
lang: _lang
}, data));
}
return urlsMap;
}