[{"data":1,"prerenderedAt":1785},["ShallowReactive",2],{"navigation":3,"\u002Fnuxt-module\u002Fpage-caching":409,"\u002Fnuxt-module\u002Fpage-caching-surround":1780},[4,14,36,69,144,384],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started\u002F1.index",[9,10],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":15,"path":16,"stem":17,"children":18,"page":35},"Guides","\u002Fguides","2.guides",[19,23,27,31],{"title":20,"path":21,"stem":22},"Your First Layout","\u002Fguides\u002Fyour-first-layout","2.guides\u002F1.your-first-layout",{"title":24,"path":25,"stem":26},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","2.guides\u002F2.your-first-page-template",{"title":28,"path":29,"stem":30},"Your First Component","\u002Fguides\u002Fyour-first-component","2.guides\u002F3.your-first-component",{"title":32,"path":33,"stem":34},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","2.guides\u002F4.alternative-ui-variants",false,{"title":37,"path":38,"stem":39,"children":40,"page":35},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[41,45,49,53,57,61,65],{"title":42,"path":43,"stem":44},"How It All Works","\u002Fcore-concepts\u002Farchitecture","3.core-concepts\u002F1.architecture",{"title":46,"path":47,"stem":48},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","3.core-concepts\u002F2.the-data-model",{"title":50,"path":51,"stem":52},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","3.core-concepts\u002F3.layouts-and-pages",{"title":54,"path":55,"stem":56},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","3.core-concepts\u002F4.dynamic-pages",{"title":58,"path":59,"stem":60},"Components","\u002Fcore-concepts\u002Fcomponents","3.core-concepts\u002F5.components",{"title":62,"path":63,"stem":64},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","3.core-concepts\u002F6.draft-and-publish",{"title":66,"path":67,"stem":68},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","3.core-concepts\u002F7.admin-panel",{"title":70,"path":71,"stem":72,"children":73,"page":35},"Api","\u002Fapi","4.api",[74,78,120,124,128,132,136,140],{"title":75,"path":76,"stem":77},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F1.bundle-setup",{"title":58,"path":79,"stem":80,"children":81,"page":35},"\u002Fapi\u002Fcomponents","4.api\u002F2.components",[82,86,107],{"title":83,"path":84,"stem":85},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F2.components\u002F1.creating-components",{"title":87,"path":88,"stem":89,"children":90,"page":35},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F2.components\u002F2.annotations",[91,95,99,103],{"title":92,"path":93,"stem":94},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F2.components\u002F2.annotations\u002F1.publishable",{"title":96,"path":97,"stem":98},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F2.components\u002F2.annotations\u002F2.uploadable",{"title":100,"path":101,"stem":102},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F2.components\u002F2.annotations\u002F3.timestamped",{"title":104,"path":105,"stem":106},"Explicit Allow Only","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fexplicit-allow-only","4.api\u002F2.components\u002F2.annotations\u002F4.explicit-allow-only",{"title":108,"path":109,"stem":110,"children":111,"page":35},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F2.components\u002F3.built-ins",[112,116],{"title":113,"path":114,"stem":115},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F2.components\u002F3.built-ins\u002F1.collection-component",{"title":117,"path":118,"stem":119},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F2.components\u002F3.built-ins\u002F2.form-component",{"title":121,"path":122,"stem":123},"Dynamic & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F3.dynamic-pages",{"title":125,"path":126,"stem":127},"Users & Security","\u002Fapi\u002Fusers-and-security","4.api\u002F4.users-and-security",{"title":129,"path":130,"stem":131},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F5.data-fixtures",{"title":133,"path":134,"stem":135},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F6.configuration",{"title":137,"path":138,"stem":139},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F7.console-commands",{"title":141,"path":142,"stem":143},"Debugging & Profiler","\u002Fapi\u002Fdebugging","4.api\u002F8.debugging",{"title":145,"path":146,"stem":147,"children":148,"page":35},"Nuxt Module","\u002Fnuxt-module","5.nuxt-module",[149,153,157,161,174,194,215,248,332,356,360],{"title":150,"path":151,"stem":152},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F1.module-setup",{"title":154,"path":155,"stem":156},"PWA & Offline","\u002Fnuxt-module\u002Fpwa","5.nuxt-module\u002F10.pwa",{"title":158,"path":159,"stem":160},"Page Caching","\u002Fnuxt-module\u002Fpage-caching","5.nuxt-module\u002F11.page-caching",{"title":162,"path":163,"stem":164,"children":165,"page":35},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F2.configuration",[166,170],{"title":167,"path":168,"stem":169},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F2.configuration\u002F1.nuxt-config",{"title":171,"path":172,"stem":173},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F2.configuration\u002F2.site-config-and-seo",{"title":175,"path":176,"stem":177,"children":178,"page":35},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F3.building-your-ui",[179,183,187,190],{"title":180,"path":181,"stem":182},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F3.building-your-ui\u002F1.creating-layouts",{"title":184,"path":185,"stem":186},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F3.building-your-ui\u002F2.creating-page-templates",{"title":83,"path":188,"stem":189},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F3.building-your-ui\u002F3.creating-components",{"title":191,"path":192,"stem":193},"CLI Generator","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcwa-cli","5.nuxt-module\u002F3.building-your-ui\u002F4.cwa-cli",{"title":195,"path":196,"stem":197,"children":198,"page":35},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F4.cwa-components",[199,203,207,211],{"title":200,"path":201,"stem":202},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F4.cwa-components\u002F1.cwa-component-group",{"title":204,"path":205,"stem":206},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F4.cwa-components\u002F2.cwa-page",{"title":208,"path":209,"stem":210},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F4.cwa-components\u002F3.cwa-link",{"title":212,"path":213,"stem":214},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F4.cwa-components\u002F5.cwa-default-layout",{"title":216,"path":217,"stem":218,"children":219,"page":35},"Cwa Api","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F5.cwa-api",[220,224,228,232,236,240,244],{"title":221,"path":222,"stem":223},"Overview","\u002Fnuxt-module\u002Fcwa-api\u002Foverview","5.nuxt-module\u002F5.cwa-api\u002F1.overview",{"title":225,"path":226,"stem":227},"Resources","\u002Fnuxt-module\u002Fcwa-api\u002Fresources","5.nuxt-module\u002F5.cwa-api\u002F2.resources",{"title":229,"path":230,"stem":231},"Resources Manager","\u002Fnuxt-module\u002Fcwa-api\u002Fresources-manager","5.nuxt-module\u002F5.cwa-api\u002F3.resources-manager",{"title":233,"path":234,"stem":235},"Auth","\u002Fnuxt-module\u002Fcwa-api\u002Fauth","5.nuxt-module\u002F5.cwa-api\u002F4.auth",{"title":237,"path":238,"stem":239},"Forms","\u002Fnuxt-module\u002Fcwa-api\u002Fforms","5.nuxt-module\u002F5.cwa-api\u002F5.forms",{"title":241,"path":242,"stem":243},"Admin","\u002Fnuxt-module\u002Fcwa-api\u002Fadmin","5.nuxt-module\u002F5.cwa-api\u002F6.admin",{"title":245,"path":246,"stem":247},"Site Config","\u002Fnuxt-module\u002Fcwa-api\u002Fsite-config","5.nuxt-module\u002F5.cwa-api\u002F7.site-config",{"title":249,"path":250,"stem":251,"children":252,"page":35},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F6.composables",[253,261,298,315],{"title":254,"path":255,"stem":256,"children":257,"page":35},"Layout","\u002Fnuxt-module\u002Fcomposables\u002Flayout","5.nuxt-module\u002F6.composables\u002F0.layout",[258],{"title":254,"path":259,"stem":260},"\u002Fnuxt-module\u002Fcomposables\u002Flayout\u002Fuse-cwa-layout","5.nuxt-module\u002F6.composables\u002F0.layout\u002F1.use-cwa-layout",{"title":262,"path":263,"stem":264,"children":265,"page":35},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F6.composables\u002F1.component",[266,270,274,278,282,286,290,294],{"title":267,"path":268,"stem":269},"Component (recommended)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-component","5.nuxt-module\u002F6.composables\u002F1.component\u002F0.use-cwa-component",{"title":271,"path":272,"stem":273},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F1.use-cwa-resource",{"title":275,"path":276,"stem":277},"Collection Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F2.use-cwa-collection-resource",{"title":279,"path":280,"stem":281},"File Field","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-file-field","5.nuxt-module\u002F6.composables\u002F1.component\u002F3.use-cwa-file-field",{"title":283,"path":284,"stem":285},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form","5.nuxt-module\u002F6.composables\u002F1.component\u002F4.use-cwa-form",{"title":287,"path":288,"stem":289},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-input","5.nuxt-module\u002F6.composables\u002F1.component\u002F5.use-cwa-form-input",{"title":291,"path":292,"stem":293},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F6.composables\u002F1.component\u002F6.use-cwa-form-repeated",{"title":295,"path":296,"stem":297},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-collection","5.nuxt-module\u002F6.composables\u002F1.component\u002F7.use-cwa-form-collection",{"title":299,"path":300,"stem":301,"children":302,"page":35},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F6.composables\u002F2.admin-manager",[303,307,311],{"title":304,"path":305,"stem":306},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":308,"path":309,"stem":310},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F2.use-cwa-resource-model",{"title":312,"path":313,"stem":314},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F3.use-cwa-resource-upload",{"title":316,"path":317,"stem":318,"children":319,"page":35},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F6.composables\u002F3.utilities",[320,324,328],{"title":321,"path":322,"stem":323},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F1.use-cwa-resource-endpoint",{"title":325,"path":326,"stem":327},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F2.use-query-bound-model",{"title":329,"path":330,"stem":331},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F3.use-cwa-resource-route",{"title":333,"path":334,"stem":335,"children":336,"page":35},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F7.component-helpers",[337,341,345,349,353],{"title":338,"path":339,"stem":340},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F7.component-helpers\u002F1.images-and-uploads",{"title":342,"path":343,"stem":344},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F7.component-helpers\u002F2.collections-and-pagination",{"title":346,"path":347,"stem":348},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F7.component-helpers\u002F3.html-content",{"title":350,"path":351,"stem":352},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F7.component-helpers\u002F4.real-time-updates",{"title":237,"path":354,"stem":355},"\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F7.component-helpers\u002F5.forms",{"title":357,"path":358,"stem":359},"Authentication","\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F8.authentication",{"title":361,"path":362,"stem":363,"children":364,"page":35},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[365,368,372,376,380],{"title":221,"path":366,"stem":367},"\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":369,"path":370,"stem":371},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":373,"path":374,"stem":375},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":377,"path":378,"stem":379},"Styling","\u002Fnuxt-module\u002Fcwa-layer\u002Fstyling","5.nuxt-module\u002F9.cwa-layer\u002F4.styling",{"title":381,"path":382,"stem":383},"Date Pickers","\u002Fnuxt-module\u002Fcwa-layer\u002Fdate-pickers","5.nuxt-module\u002F9.cwa-layer\u002F5.date-pickers",{"title":385,"path":386,"stem":387,"children":388,"page":35},"Deployment","\u002Fdeployment","6.deployment",[389,393,397,401,405],{"title":390,"path":391,"stem":392},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":394,"path":395,"stem":396},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":398,"path":399,"stem":400},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"title":402,"path":403,"stem":404},"Load Testing","\u002Fdeployment\u002Fload-testing","6.deployment\u002F4.load-testing",{"title":406,"path":407,"stem":408},"Faster Behat Tests","\u002Fdeployment\u002Ffaster-behat-tests","6.deployment\u002F5.faster-behat-tests",{"id":410,"title":158,"badge":411,"body":414,"description":1773,"extension":1774,"links":1775,"meta":1776,"navigation":1777,"path":159,"seo":1778,"stem":160,"__hash__":1779},"docs\u002F5.nuxt-module\u002F11.page-caching.md",{"label":412,"color":413},"Draft","amber",{"type":415,"value":416,"toc":1760},"minimark",[417,426,430,567,574,578,581,589,636,645,658,662,673,705,723,726,733,756,782,789,793,800,816,836,842,858,861,865,929,941,960,997,1001,1011,1022,1078,1158,1242,1264,1268,1271,1298,1306,1325,1337,1345,1349,1363,1370,1413,1420,1531,1536,1552,1566,1572,1627,1642,1649,1672,1709,1714,1721,1727,1731,1756],[418,419,420,421,425],"p",{},"The module lets a shared cache (Souin, in the template) store the HTML that Nuxt renders. It sets the headers; the shared cache stores the page and drops it when the API purges. Page caching is ",[422,423,424],"strong",{},"on by default",".",[427,428,162],"h2",{"id":429},"configuration",[431,432,437],"pre",{"className":433,"code":434,"language":435,"meta":436,"style":436},"language-ts shiki shiki-themes github-light github-dark material-theme-palenight","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  cwa: {\n    pageCache: {\n      enabled: true,            \u002F\u002F default\n      sharedMaxAge: undefined,  \u002F\u002F optional cap, in seconds. Default: unset, so the API decides\n      staleWhileRevalidate: 0,  \u002F\u002F default: off\n    },\n  },\n})\n","ts","",[438,439,440,449,471,484,494,512,529,546,552,558],"code",{"__ignoreMap":436},[441,442,445],"span",{"class":443,"line":444},"line",1,[441,446,448],{"class":447},"sTBSN","\u002F\u002F nuxt.config.ts\n",[441,450,452,456,459,463,467],{"class":443,"line":451},2,[441,453,455],{"class":454},"sm4w6","export",[441,457,458],{"class":454}," default",[441,460,462],{"class":461},"sKpYG"," defineNuxtConfig",[441,464,466],{"class":465},"sPB8G","(",[441,468,470],{"class":469},"sOvfz","{\n",[441,472,474,478,481],{"class":443,"line":473},3,[441,475,477],{"class":476},"sDHlG","  cwa",[441,479,480],{"class":469},":",[441,482,483],{"class":469}," {\n",[441,485,487,490,492],{"class":443,"line":486},4,[441,488,489],{"class":476},"    pageCache",[441,491,480],{"class":469},[441,493,483],{"class":469},[441,495,497,500,502,506,509],{"class":443,"line":496},5,[441,498,499],{"class":476},"      enabled",[441,501,480],{"class":469},[441,503,505],{"class":504},"swWMF"," true",[441,507,508],{"class":469},",",[441,510,511],{"class":447},"            \u002F\u002F default\n",[441,513,515,518,520,524,526],{"class":443,"line":514},6,[441,516,517],{"class":476},"      sharedMaxAge",[441,519,480],{"class":469},[441,521,523],{"class":522},"sBtbT"," undefined",[441,525,508],{"class":469},[441,527,528],{"class":447},"  \u002F\u002F optional cap, in seconds. Default: unset, so the API decides\n",[441,530,532,535,537,541,543],{"class":443,"line":531},7,[441,533,534],{"class":476},"      staleWhileRevalidate",[441,536,480],{"class":469},[441,538,540],{"class":539},"scSvc"," 0",[441,542,508],{"class":469},[441,544,545],{"class":447},"  \u002F\u002F default: off\n",[441,547,549],{"class":443,"line":548},8,[441,550,551],{"class":469},"    },\n",[441,553,555],{"class":443,"line":554},9,[441,556,557],{"class":469},"  },\n",[441,559,561,564],{"class":443,"line":560},10,[441,562,563],{"class":469},"}",[441,565,566],{"class":465},")\n",[418,568,569,570,573],{},"Set ",[438,571,572],{},"enabled: false"," to turn it off.",[427,575,577],{"id":576},"what-a-cached-page-carries","What a cached page carries",[418,579,580],{},"When a page can be cached, the module sets two headers:",[431,582,587],{"className":583,"code":585,"language":586},[584],"language-text","Cache-Control: public, max-age=0, s-maxage=31536000\nSurrogate-Key: cwa-html, \u002F_\u002Fpages\u002F8f3c…, \u002F_\u002Fcomponent_groups\u002F4d5e…, \u002Fcomponent\u002Ftitles\u002F1a2b…, …\n","text",[438,588,585],{"__ignoreMap":436},[590,591,592,613,625],"ul",{},[593,594,595,600,601,604,605,607,608,425],"li",{},[422,596,597],{},[438,598,599],{},"Surrogate-Key"," lists the IRI of every CWA resource used to render the page, plus the constant key ",[438,602,603],{},"cwa-html",". When the API saves a resource, it purges that resource's IRI, and every page that used it is dropped. Saving site config purges ",[438,606,603],{},", which drops every page. See ",[609,610,612],"a",{"href":611},"\u002Fapi\u002Fconfiguration#purging-every-rendered-page","Purging Every Rendered Page",[593,614,615,620,621,624],{},[422,616,617],{},[438,618,619],{},"max-age=0"," is fixed. A browser's cache can't be purged, and a stale page that points at an old build's ",[438,622,623],{},"\u002F_nuxt"," files loads blank.",[593,626,627,632,633,425],{},[422,628,629],{},[438,630,631],{},"stale-while-revalidate"," is added only when you set ",[438,634,635],{},"staleWhileRevalidate",[637,638,640],"callout",{"icon":639},"i-heroicons-information-circle",[418,641,642,644],{},[438,643,603],{}," is a contract shared with the API bundle. Both sides must use the same name, or the purge matches nothing and pages stay stale until they expire.",[637,646,648],{"icon":647},"i-heroicons-photo",[418,649,650,651,654,655,657],{},"Screenshot: DevTools → Network showing a page response's ",[438,652,653],{},"Cache-Control"," and ",[438,656,599],{}," headers.",[427,659,661],{"id":660},"how-long-a-page-is-kept","How long a page is kept",[418,663,664,665,668,669,672],{},"A page's ",[438,666,667],{},"s-maxage"," is the ",[422,670,671],{},"lowest"," of:",[590,674,675,681,694],{},[593,676,677,680],{},[438,678,679],{},"pageCache.sharedMaxAge",", if you set it",[593,682,683,684,686,687,690,691,693],{},"the ",[438,685,667],{}," of every API response fetched during the render (or its ",[438,688,689],{},"max-age",", if it has no ",[438,692,667],{},")",[593,695,696,697,700,701,704],{},"the time left until any API response's ",[438,698,699],{},"Expires",", measured against that response's own ",[438,702,703],{},"Date"," header",[418,706,707,708,711,712,714,715,717,718,722],{},"The API shortens its responses ahead of anything scheduled: a component's future ",[438,709,710],{},"publishedAt"," arrives as ",[438,713,699],{},", and an upcoming route go-live caps ",[438,716,667],{}," on routes, pages and manifests (",[609,719,721],{"href":720},"\u002Fapi\u002Fconfiguration#scheduled-publication-and-cache-lifetime","Scheduled Publication and Cache Lifetime","). So a page is never kept past a scheduled change, even though no save happens at that moment.",[418,724,725],{},"If none of these supplies a value, the page is kept for one hour.",[418,727,728,729,732],{},"By default ",[438,730,731],{},"sharedMaxAge"," is unset, so a page lasts as long as the API responses it used: one year in the template's production API, and 60 seconds in development. A long lifetime is safe because the API purges a page when any resource on it is saved, site config purges every page, scheduled changes shorten the lifetime in advance, and each deploy purges and warms the cache.",[637,734,737],{"icon":735,"color":736},"i-heroicons-exclamation-triangle","warning",[418,738,739,744,745,748,749,751,752,755],{},[422,740,569,741,743],{},[438,742,731],{}," if your pages render anything the API doesn't provide."," Only CWA resources are tagged for purging. A date rendered on the server, a third-party fetch, or a ",[438,746,747],{},"useAsyncData"," call outside CWA is never purged, so with the default lifetime it stays in the cached page for up to a year. ",[438,750,731],{}," caps every page, for example ",[438,753,754],{},"sharedMaxAge: 3600"," refreshes them at least hourly. It can only shorten a page's lifetime, never extend it past the API's.",[637,757,758],{"icon":639},[418,759,760,761,764,765,771,772,774,775,778,779,781],{},"Module builds before ",[438,762,763],{},"636e9247"," (",[609,766,770],{"href":767,"rel":768},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcwa-nuxt-module\u002Fissues\u002F325",[769],"nofollow","cwa-nuxt-module#325",") defaulted ",[438,773,731],{}," to ",[438,776,777],{},"3600",", so pages were capped at an hour. They also added ",[438,780,631],{}," only when that cap set the page's lifetime.",[418,783,784,785,788],{},"Go-live capping uses the soonest scheduled go-live across ",[422,786,787],{},"all"," routes. While any route is waiting to go live, every page's lifetime is shortened to that moment.",[427,790,792],{"id":791},"when-a-page-is-not-cached","When a page is not cached",[418,794,795,796,799],{},"The module marks a page ",[438,797,798],{},"private, no-store"," when:",[590,801,802,805],{},[593,803,804],{},"the visitor is signed in, or",[593,806,807,808,811,812,815],{},"any API response used in the render was ",[438,809,810],{},"private"," or ",[438,813,814],{},"no-store",". The API sends this for an admin's draft view.",[418,817,818,819,822,823,826,827,764,830,835],{},"A ",[438,820,821],{},"4xx"," API response doesn't count towards the page's headers. A ",[438,824,825],{},"5xx"," still does, because nothing purges the page once the API recovers. An anonymous visitor's request for an unpublished component returns a private 404, and the page that places it is still cached; the component appears when it is published, because publishing purges it. Module builds before ",[438,828,829],{},"26f06f8d",[609,831,834],{"href":832,"rel":833},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcwa-nuxt-module\u002Fissues\u002F324",[769],"cwa-nuxt-module#324",") counted that 404, so a page that used a draft component was never cached.",[418,837,838,839,841],{},"A page response with any status other than 200 (a redirect or an error) gets ",[438,840,814],{},". So does any render where the page's own route or resource failed to load.",[637,843,844],{"icon":735,"color":736},[418,845,846,764,852,857],{},[422,847,760,848,851],{},[438,849,850],{},"7a219b76"," stored error pages",[609,853,856],{"href":854,"rel":855},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcwa-nuxt-module\u002Fissues\u002F340",[769],"cwa-nuxt-module#340","). Nuxt renders an error page through a separate internal request that returns 200, and the module copied that request's cacheable headers onto the real 404 or 500. A missing page stayed a cached 404 for the full page lifetime. A route scheduled to go live stayed a 404 after its time passed, because nothing purges at that moment. If you see this, update the module and purge the page cache.",[418,859,860],{},"A page that used no CWA resources, or whose lifetime works out as zero, gets no cache headers from the module.",[427,862,864],{"id":863},"deployment-requirements","Deployment requirements",[590,866,867,882,905,919],{},[593,868,869,874,875,878,879,425],{},[422,870,871,872,425],{},"The shared cache must purge by ",[438,873,599],{}," The template's Caddyfile caches page HTML on the same Souin store that the API purges. See the ",[438,876,877],{},"@use_cache"," notes in ",[609,880,390],{"href":881},"\u002Fdeployment\u002Fdocker#common-gotchas",[593,883,884,890,891,893,894,896,897,900,901,904],{},[422,885,886,887,425],{},"The page's cache key must not include ",[438,888,889],{},"Accept"," Each browser sends a different ",[438,892,889],{}," header for the same HTML, so a key that includes it stores one copy per browser, and a page cached for one browser is a miss for the next. The template keeps ",[438,895,889],{}," in the key for ",[438,898,899],{},"\u002F_api*"," only. API responses do depend on it, and API Platform's Swagger UI response sends no ",[438,902,903],{},"Vary: Accept",", so without it a cache hit could serve HTML to a JSON-LD client.",[593,906,907,910,911,914,915,918],{},[422,908,909],{},"Compression must happen after the cache."," If the cache stores responses that are already compressed, it keeps one copy per ",[438,912,913],{},"Accept-Encoding"," value. In Caddy, use ",[438,916,917],{},"order cache after encode",", so the page is stored once, uncompressed, and compressed for each client on the way out.",[593,920,921,924,925,928],{},[422,922,923],{},"The shared cache must skip requests that carry the auth cookie."," The module sends no ",[438,926,927],{},"Vary: Cookie",", because it would ruin the hit rate. A cached page is always an anonymous one, so this is not a leak, but a signed-in admin served a cached page sees no admin controls or draft content.",[637,930,931],{"icon":735,"color":736},[418,932,933,936,937,940],{},[422,934,935],{},"Your own personalised content is not detected."," The module only understands CWA data. If your pages render per-visitor content of their own (a cookie-based ",[438,938,939],{},"useFetch",", a geo banner, an A\u002FB test), turn page caching off or exclude those paths from the shared cache.",[637,942,943],{"icon":735,"color":736},[418,944,945,959],{},[422,946,947,948,951,952,654,955,958],{},"Nuxt ",[438,949,950],{},"isr",", ",[438,953,954],{},"swr",[438,956,957],{},"prerender"," route rules don't mix with this."," Nitro's own cache isn't purged by the API, so edits don't appear until the route rule expires. The module warns at build time when both are on.",[637,961,962,968],{"icon":639},[418,963,964,965,967],{},"A deploy changes the ",[438,966,623],{}," file names without changing any resource, so nothing purges cached pages. The template's Souin store is in memory in the php container, so it is emptied whenever that container restarts. If you deploy the Nuxt app on its own, or put a persistent CDN in front, cached pages can point at files that no longer exist until they expire.",[418,969,970,971,974,975,978,979,982,983,985,986,989,990,993,994,425],{},"Purge the pages after every front-end deploy, once the new Nuxt pods have fully replaced the old ones. Run ",[438,972,973],{},"php bin\u002Fconsole silverback:api-components:purge-rendered-html"," in the API container, or send ",[438,976,977],{},"POST \u002F_\u002Frendered_html\u002Fpurge"," as an admin (it returns ",[438,980,981],{},"204","). Both purge only ",[438,984,603],{},", so cached API responses are kept. If the cache refuses the purge or can't be reached, the command prints the reason and exits ",[438,987,988],{},"1",", and the endpoint returns ",[438,991,992],{},"502",", so a deploy script can rely on either. The template's pipeline already does this: see ",[609,995,398],{"href":996},"\u002Fdeployment\u002Fci-cd#why-every-deploy-clears-the-page-cache",[427,998,1000],{"id":999},"tracking-parameters","Tracking parameters",[418,1002,1003,1004,811,1007,1010],{},"The query string is part of the cache key. Without help, every ",[438,1005,1006],{},"?utm_source=…",[438,1008,1009],{},"gclid"," value would render and store its own copy of a page, so ad clicks and shared links would always miss the cache. The API would be split the same way, because the module passes the page query on to Collection fetches.",[418,1012,1013,1014,1017,1018,1021],{},"The template's Caddyfile drops these parameters before the cache sees the request. A ",[438,1015,1016],{},"@tracking_query"," matcher decides when to run a ",[438,1019,1020],{},"uri query { … }"," block:",[431,1023,1027],{"className":1024,"code":1025,"language":1026,"meta":436,"style":436},"language-caddyfile shiki shiki-themes github-light github-dark material-theme-palenight","@tracking_query {\n    not path \u002F_nuxt\u002F*\n    expression `{http.request.uri.query}.matches(\"(^|&)(utm_source|utm_medium|…|mc_eid)(=|&|$)\")`\n}\nuri @tracking_query query {\n    -utm_source\n    -utm_medium\n    -utm_campaign\n    # … the rest of the list\n}\n","caddyfile",[438,1028,1029,1034,1039,1044,1049,1054,1059,1064,1069,1074],{"__ignoreMap":436},[441,1030,1031],{"class":443,"line":444},[441,1032,1033],{},"@tracking_query {\n",[441,1035,1036],{"class":443,"line":451},[441,1037,1038],{},"    not path \u002F_nuxt\u002F*\n",[441,1040,1041],{"class":443,"line":473},[441,1042,1043],{},"    expression `{http.request.uri.query}.matches(\"(^|&)(utm_source|utm_medium|…|mc_eid)(=|&|$)\")`\n",[441,1045,1046],{"class":443,"line":486},[441,1047,1048],{},"}\n",[441,1050,1051],{"class":443,"line":496},[441,1052,1053],{},"uri @tracking_query query {\n",[441,1055,1056],{"class":443,"line":514},[441,1057,1058],{},"    -utm_source\n",[441,1060,1061],{"class":443,"line":531},[441,1062,1063],{},"    -utm_medium\n",[441,1065,1066],{"class":443,"line":548},[441,1067,1068],{},"    -utm_campaign\n",[441,1070,1071],{"class":443,"line":554},[441,1072,1073],{},"    # … the rest of the list\n",[441,1075,1076],{"class":443,"line":560},[441,1077,1048],{},[418,1079,1080,1081,951,1084,951,1087,951,1090,951,1093,951,1096,951,1099,951,1102,951,1105,951,1108,951,1110,951,1113,951,1116,951,1119,951,1122,951,1125,951,1128,951,1131,951,1134,951,1137,951,1140,951,1143,951,1146,951,1149,951,1152,654,1155,425],{},"The full list is ",[438,1082,1083],{},"utm_source",[438,1085,1086],{},"utm_medium",[438,1088,1089],{},"utm_campaign",[438,1091,1092],{},"utm_term",[438,1094,1095],{},"utm_content",[438,1097,1098],{},"utm_id",[438,1100,1101],{},"utm_source_platform",[438,1103,1104],{},"utm_creative_format",[438,1106,1107],{},"utm_marketing_tactic",[438,1109,1009],{},[438,1111,1112],{},"gclsrc",[438,1114,1115],{},"gbraid",[438,1117,1118],{},"wbraid",[438,1120,1121],{},"dclid",[438,1123,1124],{},"srsltid",[438,1126,1127],{},"_gl",[438,1129,1130],{},"_ga",[438,1132,1133],{},"fbclid",[438,1135,1136],{},"msclkid",[438,1138,1139],{},"twclid",[438,1141,1142],{},"ttclid",[438,1144,1145],{},"li_fat_id",[438,1147,1148],{},"igshid",[438,1150,1151],{},"yclid",[438,1153,1154],{},"mc_cid",[438,1156,1157],{},"mc_eid",[590,1159,1160,1181,1202,1212,1218,1232],{},[593,1161,1162,1165,1166,1169,1170,1173,1174,1177,1178,1180],{},[422,1163,1164],{},"It only runs when the query contains a listed parameter."," Caddy's ",[438,1167,1168],{},"uri query"," rewrites the whole query whenever it runs, even with nothing to remove, and turns a key with no value (",[438,1171,1172],{},"?k",") into ",[438,1175,1176],{},"k=",". Other requests keep their query exactly as sent. A query with a tracking parameter and a valueless key still gets ",[438,1179,1176],{},", which is harmless for pages.",[593,1182,1183,1189,1190,1193,1194,1197,1198,1201],{},[422,1184,1185,1186,425],{},"It never runs for ",[438,1187,1188],{},"\u002F_nuxt\u002F*"," In ",[438,1191,1192],{},"nuxt dev",", Vite asks for style blocks with URLs such as ",[438,1195,1196],{},"?vue&type=style&index=0&lang.css",". Rewritten to ",[438,1199,1200],{},"?vue=&…",", Vite served them as raw CSS and the app never mounted.",[593,1203,1204,1211],{},[422,1205,1206,1207,1210],{},"Every other path is covered, ",[438,1208,1209],{},"\u002F_api"," included."," A URL with these parameters gets the same cache entry as the URL without them. Any other query parameter still gets its own entry.",[593,1213,1214,1217],{},[422,1215,1216],{},"Only the server loses them."," Analytics scripts (Google Analytics, Meta Pixel and so on) read them from the browser's address bar, so tracking still works.",[593,1219,1220,1223,1224,1227,1228,1231],{},[422,1221,1222],{},"Nuxt and php never see them."," If your project needs one on the server, remove it from the block and from the matcher's expression. To strip another parameter, add a ",[438,1225,1226],{},"-name"," line and add the name to the expression. The two lists must match. Wildcards are not supported. The expression is CEL, so keep it on one line and put no ",[438,1229,1230],{},"#"," comments inside it.",[593,1233,1234,1237,1238,1241],{},[422,1235,1236],{},"The access log still shows the original URL."," A ",[438,1239,1240],{},"utm_"," parameter in Caddy's log does not mean the strip failed.",[637,1243,1244],{"icon":639},[418,1245,1246,1247,1249,1250,1253,1254,1257,1258,1260,1261,1263],{},"Projects generated before this change don't have the block. Copy the ",[438,1248,1016],{}," matcher and the ",[438,1251,1252],{},"uri @tracking_query query { … }"," block from the template's ",[438,1255,1256],{},"api\u002Ffrankenphp\u002FCaddyfile"," into your own, inside the site block. If you already copied a plain ",[438,1259,1020],{}," block, add the matcher: without it, ",[438,1262,1192],{}," serves style blocks as raw CSS and the app never mounts.",[427,1265,1267],{"id":1266},"purging-all-cached-data","Purging all cached data",[418,1269,1270],{},"A purge by tag only reaches what the API knows has changed. If data changed some other way, such as a direct database edit, a data fix or an import, the cached API responses and pages still hold the old data. For that, flush the whole cache:",[590,1272,1273,1280,1291],{},[593,1274,1275,1276,1279],{},"in site settings, click ",[422,1277,1278],{},"Purge all cached data"," and confirm, or",[593,1281,1282,1283,1286,1287,1290],{},"call ",[438,1284,1285],{},"$cwa.siteConfig.purgeHttpCache()",", which sends ",[438,1288,1289],{},"POST \u002F_\u002Fhttp_cache\u002Fpurge",", or",[593,1292,1293,1294,1297],{},"run ",[438,1295,1296],{},"php bin\u002Fconsole silverback:api-components:purge-http-cache"," in the API container.",[418,1299,1300,1301,1305],{},"All three drop every cached response, API and page HTML together. There is no way to flush only the API responses. See ",[609,1302,1304],{"href":1303},"\u002Fapi\u002Fconfiguration#flushing-the-whole-http-cache","Flushing the Whole HTTP Cache"," for how the API does it.",[418,1307,1308,1309,1312,1313,1316,1317,1320,1321,1324],{},"The site settings action is shown even when ",[438,1310,1311],{},"pageCache.enabled"," is ",[438,1314,1315],{},"false",", because the API cache exists either way. The section is then titled ",[422,1318,1319],{},"Cached data"," and the page-cache buttons are hidden. With page caching on, a successful purge offers ",[422,1322,1323],{},"Warm page cache now",", because every page is a cache miss until it is rendered again.",[637,1326,1327],{"icon":639},[418,1328,1329,1330,1333,1334,425],{},"Ordinary edits in the admin are already purged by tag, so you don't need this after saving content. If the cache can't be flushed (the purger isn't Souin), the endpoint returns ",[438,1331,1332],{},"501"," and site settings reports ",[422,1335,1336],{},"Nothing was purged",[637,1338,1339],{"icon":647},[418,1340,1341,1342,1344],{},"Screenshot: site settings with the ",[422,1343,1278],{}," button and its confirmation dialog.",[427,1346,1348],{"id":1347},"warming-the-cache-from-site-settings","Warming the cache from site settings",[418,1350,1351,1352,1355,1356,1359,1360,425],{},"After a purge, every page is a cache miss until someone visits it. An admin can refill the cache from site settings with ",[422,1353,1354],{},"Warm page cache",", which shows live progress. It calls ",[438,1357,1358],{},"$cwa.siteConfig.warmPageCache()",", which posts to the module's server route ",[438,1361,1362],{},"POST \u002F_cwa\u002Fpage-cache\u002Fwarm",[418,1364,1365,1366,1369],{},"The warm runs on the Nuxt server, not in the admin's browser. The browser's requests carry the auth cookie, and the shared cache deliberately skips those, so nothing would be stored. Instead, the server reads the same page list as the sitemap and requests each page anonymously through the in-cluster origin, with the ",[438,1367,1368],{},"Host"," header set to the site's public host. Each response is stored under the same cache key visitors use.",[590,1371,1372,1379,1390],{},[593,1373,1374,1375,1378],{},"Only admins can start it. The route checks the role through the API, and returns ",[438,1376,1377],{},"403"," otherwise.",[593,1380,1381,1382,1385,1386,1389],{},"One warm runs at a time ",[422,1383,1384],{},"per Nuxt server process",". A second request to the same server gets ",[438,1387,1388],{},"409"," while one is running, but separate replicas can warm at the same time.",[593,1391,1392,1393,1396,1397,1400,1401,1404,1405,1408,1409,1412],{},"Only a ",[438,1394,1395],{},"200"," counts as warmed. The result lists every other page with its cause: ",[438,1398,1399],{},"\u002Fabout (308 → https:\u002F\u002Fwww.example.com\u002Fabout)"," for a redirect, ",[438,1402,1403],{},"\u002Fabout (no response: DEPTH_ZERO_SELF_SIGNED_CERT)"," when the request got no response, or ",[438,1406,1407],{},"\u002Fabout (timed out)",". The page list already leaves out redirect routes, so a ",[438,1410,1411],{},"3xx"," here means the request never reached the renderer.",[418,1414,1415,1416,1419],{},"Settings live in the server-only runtime config, so they can be set per environment with ",[438,1417,1418],{},"NUXT_CWA_PAGE_CACHE_WARM_*"," variables:",[431,1421,1423],{"className":433,"code":1422,"language":435,"meta":436,"style":436},"export default defineNuxtConfig({\n    runtimeConfig: {\n        cwa: {\n            pageCacheWarm: {\n                concurrency: 3,  \u002F\u002F pages at once, capped at 10\n                timeout: 30000,  \u002F\u002F per page, in milliseconds\n                origin: '',      \u002F\u002F defaults to the origin of apiUrl\n            },\n        },\n    },\n})\n",[438,1424,1425,1437,1446,1455,1464,1479,1494,1510,1515,1520,1524],{"__ignoreMap":436},[441,1426,1427,1429,1431,1433,1435],{"class":443,"line":444},[441,1428,455],{"class":454},[441,1430,458],{"class":454},[441,1432,462],{"class":461},[441,1434,466],{"class":465},[441,1436,470],{"class":469},[441,1438,1439,1442,1444],{"class":443,"line":451},[441,1440,1441],{"class":476},"    runtimeConfig",[441,1443,480],{"class":469},[441,1445,483],{"class":469},[441,1447,1448,1451,1453],{"class":443,"line":473},[441,1449,1450],{"class":476},"        cwa",[441,1452,480],{"class":469},[441,1454,483],{"class":469},[441,1456,1457,1460,1462],{"class":443,"line":486},[441,1458,1459],{"class":476},"            pageCacheWarm",[441,1461,480],{"class":469},[441,1463,483],{"class":469},[441,1465,1466,1469,1471,1474,1476],{"class":443,"line":496},[441,1467,1468],{"class":476},"                concurrency",[441,1470,480],{"class":469},[441,1472,1473],{"class":539}," 3",[441,1475,508],{"class":469},[441,1477,1478],{"class":447},"  \u002F\u002F pages at once, capped at 10\n",[441,1480,1481,1484,1486,1489,1491],{"class":443,"line":514},[441,1482,1483],{"class":476},"                timeout",[441,1485,480],{"class":469},[441,1487,1488],{"class":539}," 30000",[441,1490,508],{"class":469},[441,1492,1493],{"class":447},"  \u002F\u002F per page, in milliseconds\n",[441,1495,1496,1499,1501,1505,1507],{"class":443,"line":531},[441,1497,1498],{"class":476},"                origin",[441,1500,480],{"class":469},[441,1502,1504],{"class":1503},"seSrl"," ''",[441,1506,508],{"class":469},[441,1508,1509],{"class":447},"      \u002F\u002F defaults to the origin of apiUrl\n",[441,1511,1512],{"class":443,"line":548},[441,1513,1514],{"class":469},"            },\n",[441,1516,1517],{"class":443,"line":554},[441,1518,1519],{"class":469},"        },\n",[441,1521,1522],{"class":443,"line":560},[441,1523,551],{"class":469},[441,1525,1527,1529],{"class":443,"line":1526},11,[441,1528,563],{"class":469},[441,1530,566],{"class":465},[1532,1533,1535],"h3",{"id":1534},"choosing-the-warm-origin","Choosing the warm origin",[418,1537,1538,764,1541,1544,1545,1548,1549,1551],{},[438,1539,1540],{},"origin",[438,1542,1543],{},"NUXT_CWA_PAGE_CACHE_WARM_ORIGIN",") is where the warm connects. It defaults to the origin of the server's ",[438,1546,1547],{},"apiUrl",", and the public host travels in the ",[438,1550,1368],{}," header, so the page is stored under the key visitors hit and the request never leaves your network.",[418,1553,1554,1557,1558,1561,1562,1565],{},[422,1555,1556],{},"On Kubernetes, leave it unset."," The chart runs Caddy with ",[438,1559,1560],{},"SERVER_NAME=:80",": plain HTTP, no redirect, so the derived origin (",[438,1563,1564],{},"http:\u002F\u002F\u003Cfullname>",") already works.",[418,1567,1568,1571],{},[422,1569,1570],{},"On a single server where Caddy runs its own automatic HTTPS, you must set it",", and to a different URL from the one the server renders with:",[1573,1574,1575,1590],"table",{},[1576,1577,1578],"thead",{},[1579,1580,1581,1584,1587],"tr",{},[1582,1583],"th",{},[1582,1585,1586],{},"Example",[1582,1588,1589],{},"Why",[1591,1592,1593,1609],"tbody",{},[1579,1594,1595,1601,1606],{},[1596,1597,1598,1599,693],"td",{},"Rendering (",[438,1600,1547],{},[1596,1602,1603],{},[438,1604,1605],{},"http:\u002F\u002Fphp.local\u002F_api",[1596,1607,1608],{},"Over HTTPS the TLS name would be the internal host, which only an internally issued certificate covers.",[1579,1610,1611,1616,1621],{},[1596,1612,1613,1614,693],{},"Warming (",[438,1615,1543],{},[1596,1617,1618],{},[438,1619,1620],{},"https:\u002F\u002Fphp.local",[1596,1622,1623,1624,1626],{},"The warm sends the public ",[438,1625,1368],{},", so the TLS name is your real domain and its ACME certificate validates.",[418,1628,1629,1630,1633,1634,1637,1638,425],{},"The template's ",[438,1631,1632],{},"compose.prod.yaml"," sets both, from its ",[438,1635,1636],{},"2.0.0-alpha.2"," release on; see ",[609,1639,1641],{"href":1640},"\u002Fdeployment\u002Fdocker#production-docker-compose","Production Docker Compose",[418,1643,1644,1645,1648],{},"Over plain HTTP on that setup, Caddy answers every page with a ",[438,1646,1647],{},"308"," to HTTPS, so every page is reported failed and nothing is warmed.",[637,1650,1651],{"icon":735,"color":736},[418,1652,1653,1165,1656,1659,1660,1663,1664,1667,1668,1671],{},[422,1654,1655],{},"Don't keep the warm on HTTP to avoid the certificate.",[438,1657,1658],{},"reverse_proxy"," sets ",[438,1661,1662],{},"X-Forwarded-Proto"," from the scheme it received, so the pages would be rendered and cached with ",[438,1665,1666],{},"http:\u002F\u002F"," canonical and ",[438,1669,1670],{},"og:url"," values, for the API's full cache lifetime.",[418,1673,1674,764,1677,1680,1681,1684,1685,1688,1689,1692,1693,1696,1697,1700,1701,1704,1705,1708],{},[422,1675,1676],{},"When Caddy issues the certificate itself",[438,1678,1679],{},"SERVER_NAME=localhost",", a ",[438,1682,1683],{},".local"," host or ",[438,1686,1687],{},"tls internal","), the warm fails with ",[438,1690,1691],{},"DEPTH_ZERO_SELF_SIGNED_CERT",", because Node doesn't trust Caddy's local root. Give Node the root with ",[438,1694,1695],{},"NODE_EXTRA_CA_CERTS",", or install it in the system trust store and start Node with ",[438,1698,1699],{},"--use-system-ca",". In the template, the root is at ",[438,1702,1703],{},"\u002Fdata\u002Fcaddy\u002Fpki\u002Fauthorities\u002Flocal\u002Froot.crt"," in the php container's ",[438,1706,1707],{},"caddy_data"," volume. The Nuxt container doesn't mount that volume, so copy the file out or mount it.",[637,1710,1711],{"icon":639},[418,1712,1713],{},"The module has no option to turn certificate verification off, and won't add one. With verification off, a warm pointed at the wrong host would report every page warmed while storing nothing.",[418,1715,1716,1717,1720],{},"The template's local development stack already sets ",[438,1718,1719],{},"NODE_TLS_REJECT_UNAUTHORIZED=0"," on the Nuxt container, so the default origin works there.",[418,1722,1723,1724,425],{},"The deploy pipeline has its own warm step, which does the same job after each deploy: see ",[609,1725,398],{"href":1726},"\u002Fdeployment\u002Fci-cd#warming-the-cache-after-a-deploy",[427,1728,1730],{"id":1729},"fixed-404-status-on-the-wrong-page","Fixed: 404 status on the wrong page",[637,1732,1733],{"icon":735,"color":736},[418,1734,760,1735,1738,1739,1744,1745,1748,1749,1751,1752,1755],{},[438,1736,1737],{},"72df02b3"," could apply one request's 404 to a different page rendered at the same moment (",[609,1740,1743],{"href":1741,"rel":1742},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcwa-nuxt-module\u002Fissues\u002F313",[769],"cwa-nuxt-module#313","). That page kept its content but got a ",[438,1746,1747],{},"404"," status, and a shared cache could store it for the full page lifetime. If you're on an older build, update the module. Until you do, watch for real pages reported as ",[438,1750,1747],{}," in the post-deploy ",[609,1753,1754],{"href":1726},"cache warm",", and purge the page cache if one is stored.",[1757,1758,1759],"style",{},"html pre.shiki code .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sm4w6, html code.shiki .sm4w6{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#F97583;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sKpYG, html code.shiki .sKpYG{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#82AAFF}html pre.shiki code .sPB8G, html code.shiki .sPB8G{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#BABED8}html pre.shiki code .sOvfz, html code.shiki .sOvfz{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#89DDFF}html pre.shiki code .sDHlG, html code.shiki .sDHlG{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#F07178}html pre.shiki code .swWMF, html code.shiki .swWMF{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#FF9CAC}html pre.shiki code .sBtbT, html code.shiki .sBtbT{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#89DDFF}html pre.shiki code .scSvc, html code.shiki .scSvc{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .seSrl, html code.shiki .seSrl{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#89DDFF}",{"title":436,"searchDepth":451,"depth":451,"links":1761},[1762,1763,1764,1765,1766,1767,1768,1769,1772],{"id":429,"depth":451,"text":162},{"id":576,"depth":451,"text":577},{"id":660,"depth":451,"text":661},{"id":791,"depth":451,"text":792},{"id":863,"depth":451,"text":864},{"id":999,"depth":451,"text":1000},{"id":1266,"depth":451,"text":1267},{"id":1347,"depth":451,"text":1348,"children":1770},[1771],{"id":1534,"depth":473,"text":1535},{"id":1729,"depth":451,"text":1730},"How the module lets a shared cache store rendered page HTML, tags it for purging, and works out how long each page can be kept.","md",null,{},true,{"title":158,"description":1773},"PV3uYboslHFgbZoAwLPrB_NWokbmWS7dQPXs3-x-KH0",[1781,1783],{"title":154,"path":155,"stem":156,"description":1782,"children":-1},"Add safe service-worker caching and offline support to a CWA app — without ever serving a cached draft to the public.",{"title":167,"path":168,"stem":169,"description":1784,"children":-1},"[object Object]",1790419985794]