123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- import { removeIfMatchPattern } from '../utils/array.js';
- import { defaultSitemapTransformer } from '../utils/defaults.js';
- import { createDefaultLocaleReplace, entityEscapedUrl, generateUrl, isNextInternalUrl, } from '../utils/url.js';
- export class UrlSetBuilder {
- config;
- manifest;
- constructor(config, manifest) {
- this.config = config;
- this.manifest = manifest;
- }
- /**
- * Returns absolute url by combining siteUrl and path w.r.t trailingSlash config
- * @param siteUrl
- * @param path
- * @param trailingSlash
- * @returns
- */
- absoluteUrl(siteUrl, path, trailingSlash) {
- const url = generateUrl(siteUrl, trailingSlash ? `${path}/` : path);
- if (!trailingSlash && url.endsWith('/')) {
- return url.slice(0, url.length - 1);
- }
- return entityEscapedUrl(url);
- }
- /**
- * Normalize sitemap fields to include absolute urls
- * @param field
- */
- normalizeSitemapField(field) {
- // Handle trailing Slash
- const trailingSlash = 'trailingSlash' in field
- ? field.trailingSlash
- : this.config?.trailingSlash;
- return {
- ...field,
- trailingSlash,
- loc: this.absoluteUrl(this.config?.siteUrl, field?.loc, trailingSlash),
- alternateRefs: (field.alternateRefs ?? []).map((alternateRef) => ({
- href: alternateRef.hrefIsAbsolute
- ? alternateRef.href
- : this.absoluteUrl(alternateRef.href, field.loc, trailingSlash),
- hreflang: alternateRef.hreflang,
- })),
- };
- }
- /**
- * Create a unique url set
- */
- async createUrlSet() {
- // Load i18n routes
- const i18n = this.manifest?.routes?.i18n;
- // Init all page keys
- const allKeys = [
- ...Object.keys(this.manifest?.build.pages),
- ...(this.manifest?.build?.ampFirstPages ?? []),
- ...(this.manifest?.preRender
- ? Object.keys(this.manifest?.preRender.routes)
- : []),
- ];
- // Filter out next.js internal urls and generate urls based on sitemap
- let urlSet = allKeys.filter((x) => !isNextInternalUrl(x));
- // Remove default locale if i18n is enabled
- let defaultLocale;
- if (i18n) {
- defaultLocale = i18n.defaultLocale;
- const replaceDefaultLocale = createDefaultLocaleReplace(defaultLocale);
- urlSet = urlSet.map(replaceDefaultLocale);
- }
- // Remove the urls based on this.config?.exclude array
- if (this.config?.exclude && this.config?.exclude.length > 0) {
- urlSet = removeIfMatchPattern(urlSet, this.config?.exclude);
- }
- urlSet = [...new Set(urlSet)];
- // Remove routes which don't exist
- const notFoundRoutes = (this.manifest?.preRender?.notFoundRoutes ??
- []);
- urlSet = urlSet.filter((url) => {
- return (!notFoundRoutes.includes(url) &&
- !notFoundRoutes.includes(`/${defaultLocale}${url}`));
- });
- // Create sitemap fields based on transformation
- const sitemapFields = []; // transform using relative urls
- // Create a map of fields by loc to quickly find collisions
- const mapFieldsByLoc = {};
- for (const url of urlSet) {
- const sitemapField = await this.config?.transform?.(this.config, url);
- if (!sitemapField?.loc)
- continue;
- sitemapFields.push(sitemapField);
- // Add link on field to map by loc
- if (this.config?.additionalPaths) {
- mapFieldsByLoc[sitemapField.loc] = sitemapField;
- }
- }
- if (this.config?.additionalPaths) {
- const additions = (await this.config?.additionalPaths({
- ...this.config,
- transform: this.config?.transform ?? defaultSitemapTransformer,
- })) ?? [];
- for (const field of additions) {
- if (!field?.loc)
- continue;
- const collision = mapFieldsByLoc[field.loc];
- // Update first entry
- if (collision) {
- // Mutate common entry between sitemapFields and mapFieldsByLoc (spread operator don't work)
- Object.entries(field).forEach(([key, value]) => (collision[key] = value));
- continue;
- }
- sitemapFields.push(field);
- }
- }
- return sitemapFields.map((x) => this.normalizeSitemapField(x));
- }
- }
|