ventojs / vento

🌬 A template engine for Deno & Node
https://vento.js.org/
MIT License
212 stars 12 forks source link

Add option to disable Vento's cache when redundant or conflicting with other caching methods #71

Closed noelforte closed 4 months ago

noelforte commented 4 months ago

Unsure where it might apply elsewhere, but this is definitely applicable to the Eleventy integration. Eleventy provides its own caching mechanism to prevent excessive template compilation, so in the context of eleventy-plugin-vento there's no need to cache the templates.

Furthermore, myself and others (https://github.com/noelforte/eleventy-plugin-vento/issues/10) have run into issues where the cache has to be cleared multiple times per run because of how Eleventy reuses template engines for other things like permalink compilation and computed data that's generated at runtime. I could write in logic to tune caching control and clear the cache before each compile operation but it seems easier to disable it entirely at a lower level.

oscarotero commented 4 months ago

Cache is always enabled to avoid recompile templates in loops.

For example:

{{ for number of 100 }}
  {{ import "./show_number.vto" { number } }}
{{ /for }}

Without cache, the "show_number.vto" file is loaded and compiled 100 times. See https://github.com/ventojs/vento/issues/62

Does Eleventy's caching mechanism prevent this?

noelforte commented 4 months ago

Ah geeze, sorry I didn't see that other issue when I was writing this one. I actually don't know if Eleventy prevents this internally, but I'll do some tests.

oscarotero commented 4 months ago

No problem! The Vento cache is implemented here: https://github.com/ventojs/vento/blob/main/src/environment.ts#L183

A simple way to test this is by overriding this function to avoid the cache. For example:

class CustomEnvironment extends Environment {
  async load(file: string, from?: string): Promise<Template> {
    const path = this.options.loader.resolve(from || "", file);

    // Remove query and hash params from path before loading
    const cleanPath = path
      .split("?")[0]
      .split("#")[0];
     const { source, data } = await this.options.loader.load(cleanPath);
     return this.compile(source, path, data);
  }
}
noelforte commented 4 months ago

So Eleventy does save the results of a compiled template for reuse, something that's documented here. eleventy-plugin-vento uses the default read: true behavior of Eleventy Custom Engines, so caching would be active under these circumstances.

To prove whether it's actually effective at handling the use case you've suggested, I have a couple of questions:

  1. I'm assuming the best way to override via the code you provided is to locally link a copy of Vento with Environment replaced with CustomEnvironment in mod.ts, yes? If not, what would you suggest doing to implement that test?
  2. To qualify test results, should I add a certian expression to the template that proves that it's only being compiled once? Would something like {{> console.log('I will only run once') }} be sufficient?
noelforte commented 4 months ago

For example:

{{ for number of 100 }}
  {{ import "./show_number.vto" { number } }}
{{ /for }}

Also, running that throws an Invalid import error, I'm assuming you meant:

{{ for number of 100 }}
  {{ include "./show_number.vto" { number } }}
{{ /for }}
oscarotero commented 4 months ago

Due you're on Node, you can edit directly the code of the package in the node_modules folder, which it's easier for debuging, instead of override functions or classes. This is only to test if removing the cache solve your problems. If it does, I'll include an option to disable the cache in Vento.

  1. That wont work because the code will be executed every time the template is used, not loaded/compiled. You can place the console.log in the env.load() function (the same function that manages the cache): console.log(path). If it logs the same path multiple times, it means that it's loading and compiling the same file.

And about the error, yes, it'sinclude :)

noelforte commented 4 months ago

@oscarotero After doing some testing, I think I have a better idea of how Eleventy handles things:

  1. You're correct that "Without cache, the "show_number.vto" file is loaded and compiled 100 times.", Eleventy doesn't recognize anything going on inside custom engines by default, I don't know why I thought it did.
  2. With Eleventy's getCacheKey feature, it looks like I use that to inform Eleventy about what's cached and what's not, so maybe some implementation on my end to allow Eleventy to read what's in Vento's cache and compile in a more intelligent way from there.

Thanks for entertaining me and for the help with testing; I'll close this since it's on me to add to my integration. Cheers!