@farmfe/core
Version:
Farm is a extremely fast web build tool written in Rust. Farm can start a project in milliseconds and perform HMR within 10ms, making it much faster than similar tools like webpack and vite.
144 lines • 5.18 kB
JavaScript
/**
* @license MIT Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors.
* This file is the same as https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/html.ts#L1185
*/
export function applyHtmlTransform(html, res) {
let tags;
if (Array.isArray(res)) {
tags = res;
}
else {
html = res.html || html;
tags = res.tags;
}
let headTags;
let headPrependTags;
let bodyTags;
let bodyPrependTags;
for (const tag of tags) {
switch (tag.injectTo) {
case 'body':
(bodyTags ?? (bodyTags = [])).push(tag);
break;
case 'body-prepend':
(bodyPrependTags ?? (bodyPrependTags = [])).push(tag);
break;
case 'head':
(headTags ?? (headTags = [])).push(tag);
break;
default:
(headPrependTags ?? (headPrependTags = [])).push(tag);
}
}
if (headPrependTags)
html = injectToHead(html, headPrependTags, true);
if (headTags)
html = injectToHead(html, headTags);
if (bodyPrependTags)
html = injectToBody(html, bodyPrependTags, true);
if (bodyTags)
html = injectToBody(html, bodyTags);
return html;
}
const headInjectRE = /([ \t]*)<\/head>/i;
const headPrependInjectRE = /([ \t]*)<head[^>]*>/i;
const htmlInjectRE = /<\/html>/i;
const htmlPrependInjectRE = /([ \t]*)<html[^>]*>/i;
const bodyInjectRE = /([ \t]*)<\/body>/i;
const bodyPrependInjectRE = /([ \t]*)<body[^>]*>/i;
const doctypePrependInjectRE = /<!doctype html>/i;
function injectToHead(html, tags, prepend = false) {
if (tags.length === 0)
return html;
if (prepend) {
// inject as the first element of head
if (headPrependInjectRE.test(html)) {
return html.replace(headPrependInjectRE, (match, p1) => `${match}\n${serializeTags(tags, incrementIndent(p1))}`);
}
}
else {
// inject before head close
if (headInjectRE.test(html)) {
// respect indentation of head tag
return html.replace(headInjectRE, (match, p1) => `${serializeTags(tags, incrementIndent(p1))}${match}`);
}
// try to inject before the body tag
if (bodyPrependInjectRE.test(html)) {
return html.replace(bodyPrependInjectRE, (match, p1) => `${serializeTags(tags, p1)}\n${match}`);
}
}
// if no head tag is present, we prepend the tag for both prepend and append
return prependInjectFallback(html, tags);
}
function injectToBody(html, tags, prepend = false) {
if (tags.length === 0)
return html;
if (prepend) {
// inject after body open
if (bodyPrependInjectRE.test(html)) {
return html.replace(bodyPrependInjectRE, (match, p1) => `${match}\n${serializeTags(tags, incrementIndent(p1))}`);
}
// if no there is no body tag, inject after head or fallback to prepend in html
if (headInjectRE.test(html)) {
return html.replace(headInjectRE, (match, p1) => `${match}\n${serializeTags(tags, p1)}`);
}
return prependInjectFallback(html, tags);
}
else {
// inject before body close
if (bodyInjectRE.test(html)) {
return html.replace(bodyInjectRE, (match, p1) => `${serializeTags(tags, incrementIndent(p1))}${match}`);
}
// if no body tag is present, append to the html tag, or at the end of the file
if (htmlInjectRE.test(html)) {
return html.replace(htmlInjectRE, `${serializeTags(tags)}\n$&`);
}
return html + `\n` + serializeTags(tags);
}
}
function prependInjectFallback(html, tags) {
// prepend to the html tag, append after doctype, or the document start
if (htmlPrependInjectRE.test(html)) {
return html.replace(htmlPrependInjectRE, `$&\n${serializeTags(tags)}`);
}
if (doctypePrependInjectRE.test(html)) {
return html.replace(doctypePrependInjectRE, `$&\n${serializeTags(tags)}`);
}
return serializeTags(tags) + html;
}
const unaryTags = new Set(['link', 'meta', 'base']);
function serializeTag({ tag, attrs, children }, indent = '') {
if (unaryTags.has(tag)) {
return `<${tag}${serializeAttrs(attrs)}>`;
}
else {
return `<${tag}${serializeAttrs(attrs)}>${serializeTags(children, incrementIndent(indent))}</${tag}>`;
}
}
function serializeTags(tags, indent = '') {
if (typeof tags === 'string') {
return tags;
}
else if (tags && tags.length) {
return tags
.map((tag) => `${indent}${serializeTag(tag, indent)}\n`)
.join('');
}
return '';
}
function serializeAttrs(attrs) {
let res = '';
for (const key in attrs) {
if (typeof attrs[key] === 'boolean') {
res += attrs[key] ? ` ${key}` : ``;
}
else {
res += ` ${key}=${JSON.stringify(attrs[key])}`;
}
}
return res;
}
function incrementIndent(indent = '') {
return `${indent}${indent[0] === '\t' ? '\t' : ' '}`;
}
//# sourceMappingURL=apply-html-transform.js.map