diff --git a/nuxt/composables/useBlogList.ts b/nuxt/composables/useBlogList.ts index fa213fccfe..134b396d22 100644 --- a/nuxt/composables/useBlogList.ts +++ b/nuxt/composables/useBlogList.ts @@ -6,10 +6,13 @@ export const BLOG_PAGE_SIZE = 19 // which of these show as nav buttons; 'tips' has a route but isn't in that button list). export const BLOG_TAGS = ['how-to', 'node-red', 'ai', 'uns', 'dashboard', 'flowfuse', 'releases', 'news', 'plc', 'mqtt', 'opcua', 'modbus', 'tips'] -// Mirrors .eleventy.js's DEV_MODE_POSTS: future-dated posts are hidden outside production -// (Netlify sets CONTEXT), so deploy previews and dev can still preview scheduled posts. +// Mirrors .eleventy.js's DEV_MODE_POSTS: future-dated posts are hidden outside production, +// so deploy previews and dev can still preview scheduled posts. The flag is baked at build +// time (see nuxt.config.ts) rather than read from process.env here: a scheduled post gets no +// prerendered file, so its URL is served by the Netlify function, where process.env.CONTEXT +// is always undefined. That switched this check off and served the post before its date. export function isFuturePost(date: string | Date): boolean { - return new Date(date) > new Date() && process.env.CONTEXT === 'production' + return new Date(date) > new Date() && useRuntimeConfig().public.isProductionContext } export function useBlogList(tag: string | null, pageNumber: number) { diff --git a/nuxt/nuxt.config.ts b/nuxt/nuxt.config.ts index 76ef3c2709..2a433d5493 100644 --- a/nuxt/nuxt.config.ts +++ b/nuxt/nuxt.config.ts @@ -134,11 +134,14 @@ export default defineNuxtConfig({ devtools: { enabled: true }, modules: ['@nuxt/ui', '@nuxt/content', '@nuxtjs/seo', 'nuxt-studio', '@nuxt/image', './modules/docs-source', 'nuxt-llms'], - // Captured at build time (Netlify sets CONTEXT during the build, not necessarily - // in the deployed Function's runtime), then baked into the server bundle via - // runtimeConfig so analytics.ts doesn't depend on a process.env read at request time. + // Captured at build time (Netlify sets CONTEXT during the build, but passes only URL, + // SITE_NAME and SITE_ID to the deployed Function at runtime), then baked in via + // runtimeConfig so nothing depends on a process.env read at request time. Under `public` + // so the blog's scheduled-post check reads the same value everywhere it runs. runtimeConfig: { - isProductionContext: process.env.CONTEXT === 'production' + public: { + isProductionContext: process.env.CONTEXT === 'production' + } }, css: ['~/assets/css/theme.css'], diff --git a/nuxt/server/plugins/analytics.ts b/nuxt/server/plugins/analytics.ts index 11fc884c02..6ada0d465b 100644 --- a/nuxt/server/plugins/analytics.ts +++ b/nuxt/server/plugins/analytics.ts @@ -2,7 +2,7 @@ let headHtml: string | null = null let bodyHtml: string | null = null export default defineNitroPlugin((nitroApp) => { - if (import.meta.dev || !useRuntimeConfig().isProductionContext) return + if (import.meta.dev || !useRuntimeConfig().public.isProductionContext) return nitroApp.hooks.hook('render:html', async (html) => { if (html.bodyAppend.some(s => s.includes('cc.min.js'))) return diff --git a/nuxt/server/routes/blog/index.xml.ts b/nuxt/server/routes/blog/index.xml.ts index 2458a16ffc..5c33c3a34b 100644 --- a/nuxt/server/routes/blog/index.xml.ts +++ b/nuxt/server/routes/blog/index.xml.ts @@ -69,8 +69,10 @@ function escapeXml(value: string): string { .replace(/>/g, '>') } -function isFuturePost(date: string | Date): boolean { - return new Date(date) > new Date() && process.env.CONTEXT === 'production' +// See useBlogList.ts: the production flag is baked at build time, not read from +// process.env, which is empty of it inside the deployed Netlify function. +function isFuturePost(date: string | Date, isProductionContext: boolean): boolean { + return new Date(date) > new Date() && isProductionContext } // entry.body is a minimark tree: { value: MinimarkNode[] } where a node is @@ -178,7 +180,8 @@ export default defineEventHandler(async (event) => { const people = { ...teamPeople, ...guestPeople } // Full post bodies are heavy - cap the feed to the most recent posts rather // than shipping the entire multi-megabyte blog archive on every request. - const entries = allEntries.filter(entry => !isFuturePost(entry.date)).slice(0, 20) + const { isProductionContext } = useRuntimeConfig(event).public + const entries = allEntries.filter(entry => !isFuturePost(entry.date, isProductionContext)).slice(0, 20) // Mirrors useReleaseFeaturePage: splices plan-availability badges and changelog/docs // links into a release blog's body, resolved from its `features:` frontmatter.