66 lines
2.5 KiB
JavaScript
66 lines
2.5 KiB
JavaScript
import { resolveUrl } from './util';
|
|
import { getMimeType } from './mimes';
|
|
import { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl';
|
|
const URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g;
|
|
const URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g;
|
|
const FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g;
|
|
function toRegex(url) {
|
|
// eslint-disable-next-line no-useless-escape
|
|
const escaped = url.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1');
|
|
return new RegExp(`(url\\(['"]?)(${escaped})(['"]?\\))`, 'g');
|
|
}
|
|
export function parseURLs(cssText) {
|
|
const urls = [];
|
|
cssText.replace(URL_REGEX, (raw, quotation, url) => {
|
|
urls.push(url);
|
|
return raw;
|
|
});
|
|
return urls.filter((url) => !isDataUrl(url));
|
|
}
|
|
export async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) {
|
|
try {
|
|
const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL;
|
|
const contentType = getMimeType(resourceURL);
|
|
let dataURL;
|
|
if (getContentFromUrl) {
|
|
const content = await getContentFromUrl(resolvedURL);
|
|
dataURL = makeDataUrl(content, contentType);
|
|
}
|
|
else {
|
|
dataURL = await resourceToDataURL(resolvedURL, contentType, options);
|
|
}
|
|
return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`);
|
|
}
|
|
catch (error) {
|
|
// pass
|
|
}
|
|
return cssText;
|
|
}
|
|
function filterPreferredFontFormat(str, { preferredFontFormat }) {
|
|
return !preferredFontFormat
|
|
? str
|
|
: str.replace(FONT_SRC_REGEX, (match) => {
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [];
|
|
if (!format) {
|
|
return '';
|
|
}
|
|
if (format === preferredFontFormat) {
|
|
return `src: ${src};`;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
export function shouldEmbed(url) {
|
|
return url.search(URL_REGEX) !== -1;
|
|
}
|
|
export async function embedResources(cssText, baseUrl, options) {
|
|
if (!shouldEmbed(cssText)) {
|
|
return cssText;
|
|
}
|
|
const filteredCSSText = filterPreferredFontFormat(cssText, options);
|
|
const urls = parseURLs(filteredCSSText);
|
|
return urls.reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));
|
|
}
|
|
//# sourceMappingURL=embed-resources.js.map
|