4

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.

Shuky Capon
  • 785
  • 5
  • 22
  • Others seem to have the same issue: https://github.com/parcel-bundler/parcel/issues/884 but it was never resolved... – exside Jul 25 '19 at 16:07
  • @exside Parcel has a tendency to close issues without discussion that aren't resolved. I've personally re-filed issues to make extremely clear that major suggestions supported by a ton of people can't be silently ignored. – jhpratt Jul 27 '19 at 23:09
  • 1
    In addition to the previously-commented github issue, there's also [this one](https://github.com/parcel-bundler/parcel/issues/1228). Looks like the owners don't want parcel to give up responsibility for the extensions. I would recommend writing a short script to re-name the re-named files. – Das_Geek Jul 30 '19 at 13:30

1 Answers1

1

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"
  },
}
Andrew Stegmaier
  • 3,429
  • 2
  • 14
  • 26
  • Thanks, looks like this would do the trick! The original question was actually posted when parcel version was at around 1.4.~ We eventually went with a post build bash script to rename all the files and references in the dist dir which was good enough and simpler on our case. – Shuky Capon Nov 07 '21 at 08:08