Nuxt 2.14 cache option & webmaster empowerment though async configuration

Disclaimer: this is something between a bug report, a feature request, and discussion about something out of scope for Nuxt 2, tried to provide as much information as possible to discuss about it.

Hey,

I’d like to talk about a pattern I like to use which allows configuration of the website settings through the CMS directly, helping it feel a bit more like WordPress (or others, in a good way), therefore empowering its final webmaster with great power (aKa not having your client / the marketing team reaching out to you two months later because they want to change the website’s Google Analytics account, example)

Problem Description

Let’s consider the following example with Google Analytics again (because I think that’s the most obvious one):

/* nuxt.config.js */
module.exports = async () => {
    const settings = await getSettingsFromCMS();

    console.log(settings);
    
    return {
        /* ... */
        buildModules: [
            ["@nuxtjs/google-analytics", { id: settings.analytics_id }]
        ],
        /* ... */
    };
};

The above works like a charm with Nuxt as this is (part of?) what asynchronous Nuxt configuration was meant for, although Nuxt 2.14 introduced a new caching feature, allowing to skip the Webpack build of the website, so what’s happening with this new feature on (default behavior)?

  1. $ nuxt generate ran for a first time, generating everything as expected (although the console log appears twice on the Webpack build part (?)) and caching the Webpack build.
  2. Settings are changed in the CMS (analytics_id is changed)
  3. $ nuxt generate ran for a second time, taking advantage of the previously cached Webpack build, therefore skipping it because no code change occurred, build succeed but the new analytics_id value is not applied everywhere (see below) because cache was used.

Indeed, the Google Analytics module injects its internal Nuxt plugin at Webpack build time and “hard-code” the id value here, so this value is part of the cached build now. On another hand if you forward our settings to Vue with publicRuntimeConfig and display it in a page you’ll have the updated value each time as this part is injected on route generation (after Webpack build).

I know the Google Analytics module also makes use of the publicRuntimeConfig which is a suitable workaround here, but this module is just taken as example here as we can think of other settings giving the webmaster even more control over the website like choosing between Google Analytics & Google Tag Manager, enabling Sentry or not, changing the meta title template… possibilities look endless to me…

I think you got the picture, if you want to fiddle with it, understand better what I talk about, you can download here a minimal reproduction:

Reproduction Download Link

Current Workarounds

Disabling cache (nuxt.generate.cache = false)

Pro: Fixes the whole problem
Con: Cache is never leveraged

Telling the webmaster to clear cache on settings change

Pro: Works, theoretically
Con: It’s obscure, error-prone, and we all know how this will end up: “Heh I changed my settings but they aren’t taken into account, any idea?”

Setting cache programmatically

Pro: Sounds like a nice idea, we can think of something like that:

/* nuxt.config.js */
module.exports = async () => {
    const settings = await getSettingsFromCMS();

    // Just think of something telling you if T settings has changed since T-1 settings
    const ignoreCache = hasChanged(settings);
    
    return {
        /* ... */
        generate: {
            cache: ignoreCache ? false : {}
        }
        /* ... */
    };
};

Con: Actually doesn’t work because build image & cache aren’t saved at all when cache is set to false

Solutions

That’s where I’d like to discuss with everyone, as:

  1. is this really a problem (something in Nuxt 2 scope)
  2. are there better approach to this whole “webmaster empowerment” thing
  3. should we enhance the cache behavior of Nuxt? What does that involve..?

For reference here are some changes I was able to think of:

Saving image & cache every time (even when nuxt.generate.cache = false)

…and using it only when cache is activated. This would allow the 3rd workaround discussed above to work although I’m not sure about the potential side effects of such a change, eventually this one can be featured as a patch to Nuxt if we agree on current behavior being an actual bug.

Allowing to extend the needBuild check with a user provided function

Currently on $ nuxt generate there’s a thing that basically says: “If previous image doesn’t match current one then invalidate cache”, we could change it to something like that if user provides a cache invalidation function: “If previous image doesn’t match current one OR user invalidateCache function returns false then invalidate cache”, although this one would introduce a minor version of Nuxt which as far as I know is not something we want to release anymore.

Anyway, happy to discuss with you all about that! Cheers~


Few Post Scriptum

  1. Feel free to rename the title, couldn’t think of something really accurate
  2. If you want me to move this discussion to another place (discussions, RFC Nuxt 2, RFC Nuxt 3, whatever) just tell me 🙂
  3. Feel free to contact me on Discord or Twitter if you want to live chat about it
  4. Depending on where the discussion leads us I’d be happy to submit a PR

Author: Fantashit

1 thought on “Nuxt 2.14 cache option & webmaster empowerment though async configuration

  1. I get the module way of working that around despite it feeling a bit less straightforward hmm, couldn’t it be a buildModule by the way? (registered before the analytics one of course)

    If using buildModules, nuxt generate with cache will ignore it while i assume you want to apply CMS config for every generate. It is safe using buildModules if the second method is used but if you can keep using runtimeConfig i would suggest doing to to avoid unnecessary build step on cms changes 🙂

    Re cache invalidation please let me know if it didn’t worked 🙂

Comments are closed.