Skip to content

Cache invalidation issues on custom HTML transformer #10105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Diegovsky opened this issue Mar 9, 2025 · 5 comments
Open

Cache invalidation issues on custom HTML transformer #10105

Diegovsky opened this issue Mar 9, 2025 · 5 comments

Comments

@Diegovsky
Copy link

Hi, I have a custom transformer that generates HTML. It seems that parcel doesn't do normal post-processing of HTML if it came from this transformer. Following the guide, my transformer looks like this:

export default new Transformer({
  async transform({asset,options}) {

    // generates html from source file
    let html = await runHtmeta(asset.filePath);

    let deps = html.matchAll(/@(import)|(include) "(.*?)"/g);
    
    for (let dep of deps) {
      //  Tried adding dependencies but it also doesn't work
      asset.addDependency({
        specifier: `./${dep}`,
        specifierType: 'kdl'
      });
    }
    // had to add this so the gen'd html is invalidated on source change
    asset.invalidateOnFileChange(asset.filePath)
    asset.type = 'html';
    asset.setCode(html);

    // Return the asset
    return [asset];
  }
});

I've noticed that it doesn't invalidate HTML deps like imported TS and CSS, despite knowing about them in the first build, which makes me always delete the generated files to invalidate the cache. However, the actual contents of the generated HTML do change.

I assume the generated HTML goes through the usual steps, as it does generate a dependency tree, but it seems that caching does not take this into account.

Am I doing something wrong? (Besides not setting a source map)

Originally posted by @Diegovsky in #10086

@Diegovsky
Copy link
Author

My original discussion didn't get any answers so I'm reposting as an issue to hopefully get some insights.

Also, I would love more pointers into how I would write a custom HTML transformer, sort-of in a tutorial form. I wrote what I have reading the docs, but I think I'm still missing some bits.

@devongovett
Copy link
Member

Sounds like you are expecting the transformer to run again when one of the dependencies changes? By default this is not the case because dependencies are treated as separate assets, and therefore are transformed separately. If you're including them in the original compilation, then you can use asset.invalidateOnFileChange instead of asset.addDependency to track them.

@Diegovsky
Copy link
Author

Yes, I was expecting that. For example, if my CSS changes, the HTML should link to the new CSS, not the old one. This also happens with TS: when a "dependency" TS file changes, the HTML is not regenerated with a link to the changed JS (which I think it should).

Is this really expected behavior? I can change them into asset.invalidateOnFileChange but this is just generated HTML. I would have to somehow patch the HTML plugin to do it.

@devongovett
Copy link
Member

For example, if my CSS changes, the HTML should link to the new CSS, not the old one

Right, updating the links occurs in the packaging phase. The transformer should insert a placeholder into the HTML, which is returned by addURLDependency. In the packaging phase, this placeholder is replaced with the final bundle URL (once that is known). https://parceljs.org/plugin-system/transformer/#url-dependencies

@Diegovsky
Copy link
Author

That behavior wasn't what I observed in my project. As least, not with the file watcher.

The HTML did change, but not the linked local css when the css did change. What forced it to change was deleting the cache folder, but invalidating whole build isn't very nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants