102 lines
2.7 KiB
JavaScript
102 lines
2.7 KiB
JavaScript
/**
|
|
* URL utilities for NextJS static paths
|
|
*/
|
|
|
|
import { makeTree } from '../utils.js';
|
|
|
|
export const _N = '/_next';
|
|
export const _NS = `${_N}/static/`;
|
|
|
|
/**
|
|
* Get all NextJS static URLs from HTML
|
|
* @param {string} html - HTML string
|
|
* @param {DOMParser} DOMParser - DOMParser instance
|
|
* @returns {Array<string>|null} Array of URLs or null
|
|
*/
|
|
export function getNextStaticUrls(html, DOMParser) {
|
|
const doc = makeTree(html, DOMParser);
|
|
|
|
const result = [];
|
|
|
|
// Find all elements with href containing /_next/static/
|
|
const hrefElements = doc.querySelectorAll(`[href*="${_NS}"]`);
|
|
for (const el of hrefElements) {
|
|
const href = el.getAttribute('href');
|
|
if (href) result.push(href);
|
|
}
|
|
|
|
// Find all elements with src containing /_next/static/
|
|
const srcElements = doc.querySelectorAll(`[src*="${_NS}"]`);
|
|
for (const el of srcElements) {
|
|
const src = el.getAttribute('src');
|
|
if (src) result.push(src);
|
|
}
|
|
|
|
return result.length > 0 ? result : null;
|
|
}
|
|
|
|
/**
|
|
* Get base path from URLs or HTML
|
|
* @param {string|Array<string>} value - HTML string or array of URLs
|
|
* @param {DOMParser} DOMParser - DOMParser instance (required if value is HTML)
|
|
* @param {boolean} removeDomain - Remove domain from absolute URLs
|
|
* @returns {string|null} Base path or null
|
|
*/
|
|
export function getBasePath(value, DOMParser = null, removeDomain = false) {
|
|
let paths;
|
|
|
|
if (Array.isArray(value)) {
|
|
paths = value;
|
|
} else {
|
|
if (!DOMParser) {
|
|
throw new Error('DOMParser required when value is HTML string');
|
|
}
|
|
paths = getNextStaticUrls(value, DOMParser);
|
|
if (!paths) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
let globalIndex = null;
|
|
let basePath = null;
|
|
|
|
for (const path of paths) {
|
|
const index = path.lastIndexOf(_NS);
|
|
if (index < 0) {
|
|
throw new Error(`can't find '${_NS}' in path=${path}`);
|
|
}
|
|
|
|
if (globalIndex === null) {
|
|
globalIndex = index;
|
|
} else if (index !== globalIndex) {
|
|
throw new Error(`index=${index} of '${_NS}' in path=${path} is != globalIndex=${globalIndex}`);
|
|
}
|
|
|
|
const candidate = path.substring(0, index);
|
|
if (basePath === null) {
|
|
basePath = candidate;
|
|
} else if (candidate !== basePath) {
|
|
throw new Error(`basePath=${candidate} extracted from path=${path} is != globalBasePath=${basePath}`);
|
|
}
|
|
}
|
|
|
|
let result = basePath ?? '';
|
|
|
|
// Remove domain if requested
|
|
if (removeDomain) {
|
|
try {
|
|
const url = new URL(result);
|
|
const hostname = url.hostname;
|
|
if (hostname) {
|
|
const parts = result.split(hostname);
|
|
if (parts.length > 1) {
|
|
result = parts[1];
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Not a valid URL, ignore
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|