parcel-bundler / parcel

The zero configuration build tool for the web. πŸ“¦πŸš€
https://parceljs.org
MIT License
43.36k stars 2.26k forks source link

Cache and file watcher does not detect changes in `posthtml-component` files #9207

Open BastiDood opened 1 year ago

BastiDood commented 1 year ago

πŸ› Bug Report

For some context, posthtml-component is a fairly popular PostHTML plugin that allows us to treat HTML partials like components (i.e., prop merging, slots, etc.). Consider the following index.html below for example:

<!-- The `x-hello` element here is substituted by some `hello.html` somewhere. -->
<!-- Props and slots are also passed into the `hello.html` partial accordingly. -->
<x-hello hello="1" world="1">
    Wow! Cool slots!
</x-hello>

Parcel works great when we edit the index.html file itself. The problem arises when we edit the hello.html component. In this case, no changes are detected by the entire build system. That is:

Given that the cache is never invalidated, the problem persists across multiple invocations of parcel serve. The dev server boots up really fast, which is great most of the time, but not what we want in this case because this means Parcel reused its stale .parcel-cache/.

In an attempt to debug the issue, I tried deleting the .parcel-cache/ folder, which worked! πŸ₯³ But I'll be completely honest here, I would much rather not manually close the dev server, delete the .parcel-cache/ folder, and then run parcel serve again just to see the changes in hello.html reflect in the page.

πŸŽ› Configuration (.babelrc, package.json, cli command)

// .posthtmlrc
{ "plugins": { "posthtml-component": { } } }
// package.json
{
    // Package metadata omitted for brevity.
    "source": "index.html",
    "devDependencies": {
        "parcel": "^2.9.3",
        "posthtml-component": "^1.1.0"
    }
}

No other configurations follow. We use the default .parcelrc from @parcel/config-default.

πŸ’» Code Sample

Based on the provided configuration above, I present a minimal reproducible example here.

[!NOTE] Assume that all files are in the same directory as the configuration files.

<!-- index.html -->
<html>
    <body>
        <!-- Editing the call site works perfectly fine! πŸ₯³ -->
        <x-hello>Test</x-hello>
    </body>
</html>
<!-- hello.html -->
<!-- Editing the component itself is problematic. πŸ˜• -->
<p>
    <!-- The `yield` is specific to `posthtml-component`. -->
    <yield></yield>
</p>

πŸ€” Expected Behavior

As mentioned above, I expect that any changes in index.html and hello.html should be picked up by the file watcher, then invalidated in the cache, then recompiled by the build system, and finally refreshed by the dev server.

Moreover, when running parcel serve again after making changes to index.html or hello.html, I expect the build system to pick up on the changes and invalidate the cache accordingly.

😯 Current Behavior

The entire pipeline works perfectly fine when editing the call site of the component (i.e., index.html).

It is hello.html that is problematic. First, parcel serve does not detect new edits, thereby persisting a stale cache. Second, succeeding invocations of parcel serve does not cause a recompilation despite changes in hello.html.

πŸ’ Possible Solution

The problem may be worked around in three ways (neither of which are ideal):

  1. Delete the .parcel-cache/ beforehand.
  2. Re-run the dev server with --no-cache for each edit of hello.html.
  3. Edit index.html so that the PostHTML pipeline re-executes.

Now, I suspect that this bug is somewhat related to #5453. Given that PostHTML plugins are somewhat opaque to Parcel (especially when they implement custom module resolution like that in posthtml-component), I fear that I may have encountered an inherent limitation of Parcel's integration with PostHTML.

In other words, I believe that the naΓ―ve text substitution of the posthtml-component plugin preprocesses the HTML in such a way that does not preserve information about the dependencies (i.e., hello.html). Parcel's module resolution thus fails to observe hello.html because from Parcel's perspective, it only sees the preprocessed index.html (never the hello.html dependency).

With that said, I would love to know if there is anything that can be done to resolve or work around this issue aside from the three non-solutions I proposed earlier?

  1. Is there anything I can do in my project configuration as a temporary workaround?
  2. Is there anything we can tweak in Parcel's PostHTML pipeline that allows us to better observe "hidden" dependencies?
  3. Is there anything that can be changed in the posthtml-component plugin itself so that it can better preserve dependency information?
  4. Would a dedicated Parcel plugin whose sole purpose is to artificially insert a dependency help here? Of course, its output would be an empty string. The goal is to simply manually insert the "hidden" dependency.

🌍 Your Environment

Software Version(s)
Parcel 2.9.3
Node 20.5.1
pnpm 8.6.12
Operating System Windows 10
cossssmin commented 10 months ago

Related:

https://github.com/posthtml/posthtml-modules/pull/100

https://github.com/thewebartisan7/posthtml-components/issues/19