Skip to content

Commit

Permalink
fix: missing tags inject fallback (#5339)
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev authored Oct 27, 2021
1 parent 52689c8 commit 3c44ac8
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 25 deletions.
24 changes: 19 additions & 5 deletions packages/playground/html/__tests__/html.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,18 +167,32 @@ if (isBuild) {
}

describe('noHead', () => {
// If there isn't a <head>, scripts are injected after <!DOCTYPE html>

beforeAll(async () => {
// viteTestUrl is globally injected in scripts/jestPerTestSetup.ts
await page.goto(viteTestUrl + '/noHead.html')
})

test('noHead tags transform', async () => {
const el = await page.$('meta[name=description]')
test('noHead tags injection', async () => {
const el = await page.$('html meta[name=description]')
expect(await el.getAttribute('content')).toBe('a vite app')

const kw = await page.$('meta[name=keywords]')
const kw = await page.$('html meta[name=keywords]')
expect(await kw.getAttribute('content')).toBe('es modules')
})
})

describe('noBody', () => {
beforeAll(async () => {
// viteTestUrl is globally injected in scripts/jestPerTestSetup.ts
await page.goto(viteTestUrl + '/noBody.html')
})

test('noBody tags injection', async () => {
// this selects the first noscript in body, even without a body tag
const el = await page.$('body noscript')
expect(await el.innerHTML()).toMatch(`<!-- this is prepended to body -->`)

const kw = await page.$('html:last-child')
expect(await kw.innerHTML()).toMatch(`<!-- this is appended to body -->`)
})
})
7 changes: 7 additions & 0 deletions packages/playground/html/noBody.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<link rel="stylesheet" href="/main.css" />

<!-- comment one -->
<h1>Hello</h1>
<!-- comment two -->

<script type="module" src="/main.js"></script>
8 changes: 4 additions & 4 deletions packages/playground/html/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
scriptMixed: resolve(__dirname, 'scriptMixed.html'),
zeroJS: resolve(__dirname, 'zeroJS.html'),
noHead: resolve(__dirname, 'noHead.html'),
noBody: resolve(__dirname, 'noBody.html'),
inline1: resolve(__dirname, 'inline/shared-1.html'),
inline2: resolve(__dirname, 'inline/shared-2.html'),
inline3: resolve(__dirname, 'inline/unique.html')
Expand All @@ -35,12 +36,11 @@ module.exports = {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
</head>`
return `
<!DOCTYPE html>
return `<!DOCTYPE html>
<html lang="en">${filename.includes('noHead') ? '' : head}
<body>
${filename.includes('noBody') ? html : `<body>
${html}
</body>
</body>`}
</html>
`
}
Expand Down
62 changes: 46 additions & 16 deletions packages/vite/src/node/plugins/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,28 +621,30 @@ function toPublicPath(filename: string, config: ResolvedConfig) {
return isExternalUrl(filename) ? filename : config.base + filename
}

const headInjectRE = /([ \t]*)<\/head>/
const headPrependInjectRE = /([ \t]*)<head[^>]*>/
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: string,
tags: HtmlTagDescriptor[],
prepend = false
) {
if (prepend) {
// inject after head or doctype
// inject as the first element of head
if (headPrependInjectRE.test(html)) {
return html.replace(
headPrependInjectRE,
(match, p1) => `${match}\n${serializeTags(tags, incrementIndent(p1))}`
)
}
else if(doctypePrependInjectRE.test(html)) {
return html.replace(
doctypePrependInjectRE,
`$&\n${serializeTags(tags)}`
)
}
} else {
// inject before head close
if (headInjectRE.test(html)) {
Expand All @@ -652,13 +654,18 @@ function injectToHead(
(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, just prepend
return serializeTags(tags) + html
// if no head tag is present, we prepend the tag for both prepend and append
return prependInjectFallback(html, tags)
}

const bodyInjectRE = /([ \t]*)<\/body>/
const bodyPrependInjectRE = /([ \t]*)<body[^>]*>/
function injectToBody(
html: string,
tags: HtmlTagDescriptor[],
Expand All @@ -672,8 +679,14 @@ function injectToBody(
(match, p1) => `${match}\n${serializeTags(tags, incrementIndent(p1))}`
)
}
// if no body, prepend
return serializeTags(tags) + html
// 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)) {
Expand All @@ -682,11 +695,28 @@ function injectToBody(
(match, p1) => `${serializeTags(tags, incrementIndent(p1))}${match}`
)
}
// if no body, append
// 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: string,
tags: HtmlTagDescriptor[]
) {
// 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(
Expand Down

0 comments on commit 3c44ac8

Please sign in to comment.