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)
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)?
$ 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.analytics_id is changed)$ 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
publicRuntimeConfigwhich 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:
nuxt.generate.cache = false)Pro: Fixes the whole problem
Con: Cache is never leveraged
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?"_
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
That's where I'd like to discuss with everyone, as:
For reference here are some changes I was able to think of:
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.
needBuild check with a user provided functionCurrently 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
Hi @lihbr thanks for nice explanation. First part is probably not directly feature that you request for "custom generate build cache invalidation mechanism". (see the end for this part)
It is not advisable to use async nuxt config (we are probably not supporting it anymore for nuxt3) and also it is not always required to rebuild project for configuration thanks to runtimeConfig (also supported by analytics module).
The trick for loading CMS configuration without need to rebuild or async nuxt config, is to use a nuxt module like this:
// nuxt.config.js
export default
buildModules: [
"@nuxtjs/google-analytics"
],
modules: [
'~/modules/cms-config'
]
};
// modules/cms-config.js
export default async function () {
const { nuxt } = this;
const { publicRuntimeConfig } = nuxt.options;
const settings = await getSettingsFromCMS();
publicRuntimeConfig.googleAnalytics = {
id: settings.analytics_id
};
}
Your CMS module will be loaded when using nuxt generate but doesn't needs a nuxt build step because id is injected to analytics module.
Of course there might be scenarios that untimeConfig cannot help so for custom invalidation mechanism, you might write a script to generate cms data hash and write it into filesystem: (can be gitignored too)
// scripts/cms-hash.js
const fs = require('fs')
getSettingsFromCMS().then(settings => {
fs.writeFileSync('cms-settings.json', JSON.stringify(settings, null, 2), 'utf-8')
}).catch(err => {
console.error(err)
process.exit(1)
})
Then in package.json:
{
"scritps": {
"cms-hash": "node ./scripts/cms-hash",
"generate": "npm run cms-hash && nuxt generate"
}
}
This will cause invalidating cache whenever cms-settings has been changed.
Hey @pi0, thanks for the nice answer! (wasn't expecting a quick one after my long post ^^') Anyway~

I think I'd make you cringe if you see how much I abuse of async config in my projects to the point it became part of my starter haha ^^' But if that's something you feel like moving away in future version of Nuxt, fair enough! I'm curious about the motivation though 🤔
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)
Ok, this one is brilliant! Your suggested workaround is just elegant, no regret sharing all of that here to figure this one ^^'
Thanks!
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 :)
Most helpful comment
If using
buildModules,nuxt generatewith cache will ignore it while i assume you want to apply CMS config for every generate. It is safe usingbuildModulesif the second method is used but if you can keep usingruntimeConfigi would suggest doing to to avoid unnecessary build step on cms changes :)Re cache invalidation please let me know if it didn't worked :)