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">
<html lang="en">
  <!-- ... -->
</html>