HTML (PostHTML)

HTML assets are often the entry file that you provide to Parcel, but can also be referenced by JavaScript files, e.g. to provide links to other pages.

index.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./style.less" />
</head>
<body>
<img src="./images/header.png" />
More content: <a href="./other.html">Link to another page</a>.

<script src="./index.ts"></script>
</body>
</html>

ΒΆ Dependencies

Parcel detects most references in HTML to other files (such as <script src="...", <img src="...">, <video> or <meta property="og:image">) and processes them as well. These references are rewritten so that they link to the correct output files. Relative filenames are resolved relative to the current HTML file.

One noteworthy aspect of this is that <script type="module"> automatically creates a ESM JavaScript bundle (and restricting the Browserslist config to browsers supporting ESM). Together with <script nomodule>, this makes differential serving very straight forward (see also Generic Webapp).

index.html:
<!DOCTYPE html>
<script nomodule src="./index.ts"></script>
<script type="module" src="./index.ts"></script>

ΒΆ Inline script and style tags

<script> and <style> tags with text content are also processed just like standalone files and the generated bundles are inserted back into the HTML file.

index.html:
<!DOCTYPE html>
<style>
@import "./style.scss";
</style>
<script>
import value from "./other.ts";
console.log(value);
</script>

Use this sparingly, as big inline scripts/styles can be detrimental to the (perceived) load speed.

ΒΆ Inline style attribute

Inline style properties on HTML elements are turned into CSS assets, then PostCSS plugins are applied if configured and the result gets minified.

index.html:
<!DOCTYPE html>
<div style="text-decoration: underline red;">Hello!</div>
package.json:
{
"devDependencies": {
"autoprefixer": "^9.8.6",
"parcel": "next"
},
"browserslist": ["Firefox 30"]
}
.postcssrc:
{
"plugins": {
"autoprefixer": true
}
}

Output:

<!DOCTYPE html>
<div style="-moz-text-decoration:underline red;text-decoration:underline red">
Hello!
</div>

ΒΆ PostHTML

PostHTML is a tool for transforming HTML with plugins. You can configure PostHTML by creating a configuration file using one of these names: .posthtmlrc (JSON, strongly recommend), .posthtmlrc.js, or posthtml.config.js.

Install plugins in your app:

yarn add posthtml-doctype

Then, create a config file:

.posthtmlrc:
{
"plugins": {
"posthtml-doctype": { "doctype": "HTML 5" }
}
}

Plugins are specified in the plugins object as keys, and options are defined using object values. If there are no options for a plugin, just set it to true or an empty object instead, another example:

.posthtmlrc:
{
"plugins": {
"posthtml-include": {}
}
}
index.html:
<html>
<head>
<title>Home</title>
</head>
<body>
<include src="header.html"></include>
<main>My content</main>
</body>
</html>
header.html:
<header>This is my header</header>

ΒΆ posthtml.config.js

For some plugins that require passing a method as a configuration option, or to set up plugins based on process.env.NODE_ENV, you need to use a posthtml.config.js file for configuration, instead of .posthtmlrc.

npm i posthtml-modules posthtml-shorten -D
posthtml.config.js:
module.exports = {
plugins: {
"posthtml-modules": {},
"posthtml-shorten": {
shortener: {
process: function (url) {
return new Promise((resolve, reject) => {
resolve(url.replace(".html", ""));
});
},
},
tag: ["a"], // Allowed tags for URL shortening
attribute: ["href"], // Attributes to replace on the elements
},
},
};
index.html:
<html>
<head>
<title>Home</title>
</head>
<body>
<module href="./modules/header.html" locals='{"headerTitle":"Work"}'>
I will be rendered into content
</module>
<main>My content</main>
</body>
</html>
modules/header.html:
<header>Welcome to  with content: <content></content></header>

Note that for the usage of posthtml-modules defined locals cannot have a hyphen/dash (-) within their name, otherwise Parcel fails at compilation.

Furthermore, modules do not reload with HMR, unless you modify the file where you use them (in this case index.html).

ΒΆ htmlnano

If minification is enabled (e.g. parcel build without --no-minify) all bundles are automatically processed with htmlnano.

It can be configured according to its documentation with a .htmlnanorc (JSON) or .htmlnanorc.js file, for example to retain HTML comments

.htmlnanorc:
{
"removeComments": false
}

or to not minify SVG elements.

.htmlnanorc:
{
"minifySVG": false
}