Using a non-conforming doctype with Vite

Using a fresh install of Vite via npm create vite@latest we get the following index.html. Note the modern doctype.

<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<link rel="icon" type="image/svg+xml" href="/vite.svg" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Vite + TS</title>
	</head>
	<body>
		<div id="app"></div>
		<script type="module" src="/src/main.ts"></script>
	</body>
</html>

<!DOCTYPE html> is the simplest possible, and the one recommended by current HTML standards.

MDN

I naively assumed I could change the doctype and continue development without issue.

<!DOCTYPE html PUBLIC "-//HbbTV//1.3.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.3.1.dtd">
<html lang="en">
	<!-- ... -->
</html>

However, doing this throws an error non-conforming-doctype.

 ERROR  10:31:16 [vite] Internal server error: Unable to parse HTML; parse5 error code non-conforming-doctype at /path/to/file/index.html:1:1
1  |  <!DOCTYPE html PUBLIC "-//HbbTV//1.3.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.3.1.dtd">
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This issue happens as the parse5 library, which Vite uses for HTML parsing, expects a valid and conforming doctype declaration at the top of the HTML file. If the doctype declaration is missing, incorrect, or non-standard, it can throw this error.

Solution

One solution is to use transformIndexHtml which requires a little bit of configuration in the vite.config.js file; if you don’t already have one create it in the root of the project.

Using transformIndexHtml

transformIndexHtml is a Vite specific hook used to transform the index.html file. We can use this to replace the doctype after the html has been processed.

import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		{
			name: 'html-transform',
			transformIndexHtml: (html) => {
				return html.replace(
					'<!DOCTYPE html>',
					'<!DOCTYPE html PUBLIC "-//HbbTV//1.3.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.3.1.dtd">'
				);
			}
		}
	]
});

Now run the build and check the source of index.html, note that the doctype has been replaced.

<!DOCTYPE html PUBLIC "-//HbbTV//1.3.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.3.1.dtd"> // [!code
highlight]
<html lang="en">
	<!-- ... -->
</html>