@altano/html-cdnify
Version:
Transform the relative URLs in your HTML markup (e.g. scripts, stylesheets, images) to use your CDN URL.
102 lines (100 loc) • 3.55 kB
JavaScript
import urlConverter_default from "./urlConverter.js";
import { HtmlAttributeStreamTransformer } from "./HtmlAttributeStreamTransformer.js";
import { merge, mergeWith, unionBy } from "lodash";
//#region src/CDNTransformer.ts
/**
* Handles merging objects that have TransformDefinition arrays
*/
var OptionsMerger = class OptionsMerger {
static isTransformDefinition(a) {
return a != null && typeof a === "object" && "selector" in a && "attribute" in a && typeof a.selector === "string" && typeof a.selector === "string" && typeof a.attribute === "string";
}
static isTransformDefinitions(a) {
return Array.isArray(a) && a.length > 0 && OptionsMerger.isTransformDefinition(a[0]);
}
static mergeCustomizer = (objValue, srcValue) => {
if (OptionsMerger.isTransformDefinitions(objValue) && OptionsMerger.isTransformDefinitions(srcValue)) {
const result = unionBy(srcValue, objValue, (value) => `${value.selector} / ${value.attribute}`);
return result;
} else return void 0;
};
static merge(target, source1, source2, source3) {
return mergeWith(target, source1, source2, source3, OptionsMerger.mergeCustomizer);
}
};
/**
* Wraps a node-trumpet Transform stream, w/ HTML as input and
* HTML as output. The output will have all non-absolute-URL
* attributes that identify CDN-able resources converted to
* use the given CDN URL.
*/
var CDNTransformer = class CDNTransformer extends HtmlAttributeStreamTransformer {
cdnOptions;
constructor(cdnOptions) {
super(OptionsMerger.merge({}, CDNTransformer.#defaultHtmlAttributeStreamTransformerOptions, {
transformDefinitions: [],
transformFunction: (attribute) => this.#cdnifyAttribute(attribute)
}, { transformDefinitions: cdnOptions.transformDefinitions }));
this.cdnOptions = merge({ transformDefinitions: [] }, CDNTransformer.#defaultCdnOptions, cdnOptions);
if (typeof this.cdnOptions.cdnUrl !== "string") throw new Error(`Invalid cdnUrl specified.`);
}
#cdnifyAttribute(oldUrl) {
return this.cdnOptions.transformFunction(this.cdnOptions.cdnUrl, oldUrl, this.cdnOptions.bufferPath);
}
static #defaultCdnOptions = {
bufferPath: ".",
transformFunction: urlConverter_default
};
static defaultTransformFunction = CDNTransformer.#defaultCdnOptions.transformFunction;
static #defaultHtmlAttributeStreamTransformerOptions = {
attributeToMarkElementToBeIgnored: "data-cdn-ignore",
transformDefinitions: [
{
selector: `video[poster]:not([data-cdn-ignore])`,
attribute: "poster"
},
{
selector: `img[data-src]:not([data-cdn-ignore])`,
attribute: "data-src"
},
{
selector: `script[src]:not([data-cdn-ignore])`,
attribute: "src"
},
{
selector: `source[src]:not([data-cdn-ignore])`,
attribute: "src"
},
{
selector: `link[rel="apple-touch-icon"]:not([data-cdn-ignore])`,
attribute: "href"
},
{
selector: `link[rel="icon"]:not([data-cdn-ignore])`,
attribute: "href"
},
{
selector: `link[rel="shortcut icon"]:not([data-cdn-ignore])`,
attribute: "href"
},
{
selector: `link[rel="stylesheet"]:not([data-cdn-ignore])`,
attribute: "href"
},
{
selector: `img[src]:not([data-cdn-ignore])`,
attribute: "src"
},
{
selector: `img[srcset]:not([data-cdn-ignore])`,
attribute: "srcset",
attributeParser(attr, transformFunction) {
return attr.split(",").map((imgInfo) => imgInfo.replace(/([^ ]+)/, transformFunction)).join(",");
}
}
]
};
};
//#endregion
export { CDNTransformer };
//# sourceMappingURL=CDNTransformer.js.map