Running in a browser

While primarly developed as a NodeJS CLI/backend tool it is possible to run html-validate in a browser as well.

Note

While it is possible to get html-validate running in a browser it is currently not supported and requires a few workarounds.

Improvements are welcome!

Base implementation

This article assume you are trying to get something similar to this code to run in the browser.

import { HtmlValidate } from "html-validate";

const markup = "<button></button>";
const htmlvalidate = new HtmlValidate();
const report = htmlvalidate.validateString(markup, "my-file.html");

Example

There is an example project try-online running at online.html-validate.org showing that it can be done and the workarounds required.

Browser bundle

The first step is to make sure the correct bundle is used. The library contains both a full build and a browser build, if your bundler fails to pick up the right one you need to be explicit:

-import { HtmlValidate } from "html-validate";
+import { HtmlValidate } from "html-validate/browser";

Configuration loading

By default html-validate will traverse the filesystem looking for configuration files (e.g. .htmlvalidate.json). This is true even when using validateString(..).

This will manifest itself with errors such as:

To get around this the StaticConfigLoader (or a custom loader) can be used:

-import { HtmlValidate } from "html-validate"
+import { StaticConfigLoader, HtmlValidate } from "html-validate/browser";

-const htmlvalidate = new HtmlValidate();
+const loader = new StaticConfigLoader();
+const htmlvalidate = new HtmlValidate(loader);
 const report = htmlvalidate.validateString(markup, "my-file.html");

The StaticConfigLoader will only load the configuration passed to the constructor or to validateString(..). By default it uses the html-validate:recommended preset but can be overridden by passing a different to the constructor:

-const loader = new StaticConfigLoader();
+const loader = new StaticConfigLoader({
+  extends: ["html-validate:standard"],
+  elements: ["html5"],
+});
 const htmlvalidate = new HtmlValidate(loader);

Previous workaround

The previous workaround was to pass a configuration to the HtmlValidate constructor with the root property set to true but this is no longer recommended for this purpose:

-const htmlvalidate = new HtmlValidate();
+const htmlvalidate = new HtmlValidate({
+  root: true,
+  extends: ["html-validate:recommended"],
+});

Note that no default configuration will be loaded either so you must explicitly enable rules or extend a preset.

Bundled files

Since v7.8.0 all files previously stored in elements/*.{js,json,d.ts} are now bundled in the same build and it is no longer needed to manually configure your loaded to include these files.

If you had this configured before you can now remove it:

 import { StaticConfigLoader, HtmlValidate } from "html-validate/browser";

-// check your webpack loader! it must return a plain object (not `default: { ... }`, a path/url, etc)
-import html5 from "html-validate/elements/html5.json";

 const loader = new StaticConfigLoader({
   extends: ["html-validate:recommended"],
-  elements: [html5],
+  elements: ["html5"],
 });
 const htmlvalidate = new HtmlValidate(loader);

Webpack

Internally there are many dynamic imports and fs access.

You will see warnings such as:

WARNING in ./node_modules/html-validate/dist/config/config.js 81:25-50
Critical dependency: the request of a dependency is an expression

In many cases there is no way to avoid the warning per se but the workaround above are implemented the code paths triggering these issues are not hit.