javascripthtmlbuildparceljsposthtml

Parceljs / PostHTML - keeping .htm files from being renamed to .html


When building through parcel .htm files, the output is .html files. I much rather just keep the .htm files as output files, but couldn't figure out a way to do it in either Parcel or PostHTML which is being used by parcel.

I've updated an old static website to use Parcel as the build tool. All the website files are with a .htm file extension.

I'm having a problem where currently parcel automatically renames all the .htm files to .html, and also auto updates all the internal links to .html

This is currently an issue because the site is indexed on search engines with .htm file suffixes, so I currently either need to keep two copies or perform redirects for each .htm file.


Solution

  • I don't think this is supported out-of-the-box in parcel v2, but it could be accomplished relatively easily with a custom namer plugin

    Here's some code that will work:

    import { Namer } from "@parcel/plugin";
    import path from "path";
    
    export default new Namer({
      name({ bundle }) {
        if (bundle.type === "html") {
          const filePath = bundle.getMainEntry()?.filePath;
          if (filePath) {
            let baseNameWithoutExtension = path.basename(filePath, path.extname(filePath));
            // See: https://parceljs.org/plugin-system/namer/#content-hashing
            if (!bundle.needsStableName) {
              baseNameWithoutExtension += "." + bundle.hashReference;
            }
            return `${baseNameWithoutExtension}.htm`;
          }
        }
        // Returning null means parcel will keep the name of non-html bundles the same.
        return null;
      },
    });
    

    The easiest way to hook this plugin up with parcel without publishing a separate package is to use yarn's link protocol.

    You'd structure your project like this:

    project
    ├── .parcelrc
    ├── package.json
    ├── src
    │   └── index.html
    └── parcel-namer-htm
        ├── package.json
        └── src
            └── HtmNamer.js <-- the code above
    

    Your main package.json would link to your parcel-namer-htm folder like this:

    {
      "name": "my-project",
      "dependencies": {
        "parcel": "^2.0.0",
        "parcel-namer-htm": "link:./parcel-transformer-foo"
      }
    }
    

    Your .parcelrc file would look like this:

    {
      "extends": "@parcel/config-default",
      "namers": ["parcel-namer-htm", "..."]
    }
    

    And the parcel-namer-htm/package.json would look like this:

    {
      "name": "parcel-namer-htm",
      "main": "src/HtmNamer.js",
      "engines": {
        "node": ">= 12.0.0",
        "parcel": "^2.0.0"
      },
    }