html-loader
Version:
Html loader module for webpack
210 lines (177 loc) • 5.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _parse5SaxParser = _interopRequireDefault(require("parse5-sax-parser"));
var _utils = require("../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = options => function process(html) {
const {
list,
urlFilter: maybeUrlFilter
} = options.sources;
const sources = [];
const urlFilter = (0, _utils.getFilter)(maybeUrlFilter, value => (0, _utils.isUrlRequestable)(value));
const getAttribute = (tag, attribute, attributes, resourcePath) => {
const foundTag = list.get(tag.toLowerCase()) || list.get('*');
if (!foundTag) {
return false;
}
const foundAttribute = foundTag.get(attribute.toLowerCase());
if (!foundAttribute) {
return false;
}
const result = foundAttribute.filter ? foundAttribute.filter(tag, attribute, attributes, resourcePath) : true;
return result ? foundAttribute : false;
};
const {
resourcePath
} = options;
const parser5 = new _parse5SaxParser.default({
sourceCodeLocationInfo: true
});
parser5.on('startTag', node => {
const {
tagName,
attrs,
sourceCodeLocation
} = node;
attrs.forEach(attribute => {
const {
prefix
} = attribute;
let {
name
} = attribute;
name = prefix ? `${prefix}:${name}` : name;
if (!sourceCodeLocation.attrs[name]) {
return;
}
const foundAttribute = getAttribute(tagName, name, attrs, resourcePath);
if (!foundAttribute) {
return;
}
const {
type
} = foundAttribute;
const target = html.slice(sourceCodeLocation.attrs[name].startOffset, sourceCodeLocation.attrs[name].endOffset);
const unquoted = target[target.length - 1] !== '"' && target[target.length - 1] !== "'";
const result = []; // eslint-disable-next-line default-case
switch (type) {
case 'src':
{
(0, _utils.typeSrc)({
name,
attribute,
node,
target,
html,
options
}).forEach(i => {
result.push(i);
});
break;
}
case 'srcset':
{
(0, _utils.typeSrcset)({
name,
attribute,
node,
target,
html,
options
}).forEach(i => {
result.push(i);
});
break;
}
default:
{
type({
name,
attribute,
node,
target,
html,
options
}).forEach(i => {
result.push(i);
});
}
}
for (const i of result) {
if (i) {
sources.push({ ...i,
name,
unquoted
});
}
}
});
});
parser5.end(html);
const imports = new Map();
const replacements = new Map();
let offset = 0;
for (const source of sources) {
const {
name,
value,
unquoted,
startIndex,
endIndex
} = source;
let normalizedUrl = value;
let prefix = '';
const queryParts = normalizedUrl.split('!');
if (queryParts.length > 1) {
normalizedUrl = queryParts.pop();
prefix = queryParts.join('!');
}
normalizedUrl = (0, _utils.normalizeUrl)(normalizedUrl);
if (!urlFilter(name, value, resourcePath)) {
// eslint-disable-next-line no-continue
continue;
}
let hash;
const indexHash = normalizedUrl.lastIndexOf('#');
if (indexHash >= 0) {
hash = normalizedUrl.substring(indexHash);
normalizedUrl = normalizedUrl.substring(0, indexHash);
}
const request = (0, _utils.requestify)(normalizedUrl);
const newUrl = prefix ? `${prefix}!${request}` : request;
const importKey = newUrl;
let importName = imports.get(importKey);
if (!importName) {
importName = `___HTML_LOADER_IMPORT_${imports.size}___`;
imports.set(importKey, importName);
options.imports.push({
importName,
source: (0, _utils.stringifyRequest)(options.context, newUrl)
});
}
const replacementKey = JSON.stringify({
newUrl,
unquoted,
hash
});
let replacementName = replacements.get(replacementKey);
if (!replacementName) {
replacementName = `___HTML_LOADER_REPLACEMENT_${replacements.size}___`;
replacements.set(replacementKey, replacementName);
options.replacements.push({
replacementName,
importName,
hash,
unquoted
});
} // eslint-disable-next-line no-param-reassign
html = html.slice(0, startIndex + offset) + replacementName + html.slice(endIndex + offset);
offset += startIndex + replacementName.length - endIndex;
}
return html;
};
exports.default = _default;