Nuxt3首页index.vue无法SSR渲染问题求助
Nuxt3首页index.vue无法SSR渲染,其他页面正常的问题排查与解决
我使用Nuxt3,通过Server目录搭建了自定义API。但遇到问题:pages文件夹下的index.vue作为首页,内容无法以SSR方式渲染;但将该页面内容移至任意命名的新页面(如xxx.vue)时,相同数据可正常SSR渲染。
目录结构
--pages --index.vue
index.vue代码
<template> <NuxtLayout name="moviedetails"> <v-container> <v-card class="my-4" color="transparent" variant="flat"> <main-news-slider class="mt-4" /> <v-container> <v-card color="transparent" flat> <div id="AADIV33"></div> </v-card> </v-container> <!-- <ClientOnly> --> <IGNSlider :data="ignIndex.data" /> <!-- </ClientOnly> --> <AnimeSlider :season="getCurrentSeason()" /> <v-card-actions class="justify-center my-4"> <v-btn-toggle color="primary" mandatory density="compact" v-model="trendTime" rounded="xl" > <v-btn value="week" size="small" density="compact" >هذا الأسبوع</v-btn > <v-btn value="day" size="small" density="compact">اليوم</v-btn> </v-btn-toggle> </v-card-actions> <swiper-trends-slider :swiperData="trendTime == 'day' ? todayTrendsData : weekTrendsData" > </swiper-trends-slider> </v-card> <v-locale-provider rtl> <v-card v-for="genres in allGenres" class="my-4" color="transparent" variant="flat" > <v-card-title class="mt-4"> {{ genres?.item?.title }} </v-card-title> <swiper-geners-sliders :swiperGenederData="genres?.data?.results" :swiperBreakPoints="genersBreakPoints" :mediaDataId="genres?.item" > </swiper-geners-sliders> </v-card> </v-locale-provider> </v-container> </NuxtLayout> </template> <script setup> import { getCurrentSeason } from "~~/common/commonFuntions"; import IGNSlider from "~~/components/IGNSlider.vue"; const trendTime = ref("day"); const genersBreakPoints = ref({ 640: { slidesPerView: 2, spaceBetween: 20, }, 768: { slidesPerView: 4, spaceBetween: 20, }, 1024: { slidesPerView: 6, spaceBetween: 20, }, }); const { data: todayTrendsData } = await useFetch( `/api/trendslider/day?type=day` ); const { data: weekTrendsData } = await useFetch( `/api/trendslider/day?type=week` ); const randid = function generateRandomId() { return Math.floor(Math.random() * 900000) + 100000 + ""; }; const { data: ignIndex } = await useFetch(`/api/ign/home?${randid}=${randid}`); console.log(ignIndex); const { data: allGenres } = await useFetch("/api/genres"); const returnMainPaegAds = () => { /* header_ads_section */ var k = decodeURIComponent(document.cookie), ca = k.split(";"), psc = ""; ca; for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == " ") c = c.substring(1); if (c.indexOf("adcapban") == 0) psc += (psc == "" ? "" : ",") + c.replace("adcapban", "").replace("=", ","); } var s = document.createElement("script"); s.src = "https://adsmanager.trexqr.com/ser.php?t=AADIV33" + String.fromCharCode(38) + "f=33" + String.fromCharCode(38) + "psc=" + psc; s; return s.src; }; const showScript = ref(false); const nuxt = useNuxtApp(); nuxt.hook("page:start", () => { showScript.value = false; }); nuxt.hook("page:finish", () => { setTimeout(() => { showScript.value = true; }, 1000); }); const route = useRoute(); useHead({ script: [ { src: () => (showScript.value == true ? returnMainPaegAds() : ""), tagPosition: "head", // valid options are: 'head' | 'bodyClose' | 'bodyOpen' }, ], }); // definePageMeta({ // layout: "moviedetails", // key: (route) => route.fullPath, // }); </script> <style> .ck-content * { color: black; } </style>
nuxt.config配置
// https://nuxt.com/docs/api/configuration/nuxt-config import vuetify from "vite-plugin-vuetify"; import { createResolver } from "@nuxt/kit"; const { resolve } = createResolver(import.meta.url); export default defineNuxtConfig({ ssr: true, modules: ["nuxt-swiper", '@pinia/nuxt', 'nuxt-delay-hydration', "nuxt-lodash"], delayHydration: { idleCallbackTimeout: 2000 }, runtimeConfig: { TMDBKEY: process.env.NUXT_TMDBKEY, SCRIPT_KEY: process.env.NUXT_SCRIPT, PPKEY: "123", public: { TMDBKEY: "*****", }, }, css: [ "vuetify/lib/styles/main.sass", "@mdi/font/css/materialdesignicons.min.css", "@/assets/main.scss", "@vuepic/vue-datepicker/dist/main.css" ], build: { transpile: ["vuetify"], }, vite: { define: { "process.env.DEBUG": false, }, }, app: { head: { titleTemplate: "%s - Aflam.vip", title: "Aflam.vip", meta: [ { charset: "utf-8" }, { name: "viewport", content: "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0", }, { name: "msapplication-TileImage", content: "telephone=no" }, { name: "propeller", content: "*****" }, ], script: [ ], style: [], noscript: [] }, }, plugins: [], imports: { dirs: ['./stores'], }, pinia: { autoImports: ['defineStore', 'acceptHMRUpdate'], }, });
问题排查与解决方法
1. 排除nuxt-delay-hydration模块的影响
你启用了nuxt-delay-hydration模块,该模块会延迟页面 hydration,可能导致首页看起来未完成SSR。可以针对首页禁用该功能:
// nuxt.config.ts export default defineNuxtConfig({ delayHydration: { excludeRoutes: ['/'] // 首页跳过延迟 hydration } })
或者临时移除该模块,验证是否是它导致的问题。
2. 修复客户端API在SSR阶段的执行错误
returnMainPaegAds函数中直接使用了document.cookie,这是客户端专属API,在SSR阶段执行会抛出错误,中断首页的SSR渲染。需要限制该函数仅在客户端运行:
const returnMainPaegAds = () => { if (process.server) return '' // 服务端直接返回空,避免执行客户端代码 var k = decodeURIComponent(document.cookie), ca = k.split(";"), psc = ""; for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == " ") c = c.substring(1); if (c.indexOf("adcapban") == 0) psc += (psc == "" ? "" : ",") + c.replace("adcapban", "").replace("=", ","); } return `https://adsmanager.trexqr.com/ser.php?t=AADIV33&f=33&psc=${psc}` };
更推荐使用Nuxt3提供的useCookieAPI,它支持跨服务端和客户端操作:
const adcapban = useCookie('adcapban') const returnMainPaegAds = () => { const psc = adcapban.value ? adcapban.value.replace("=", ",") : "" return `https://adsmanager.trexqr.com/ser.php?t=AADIV33&f=33&psc=${psc}` };
3. 启用页面唯一key配置
取消注释代码中definePageMeta的配置,给首页设置唯一路由key,避免路由复用导致的渲染异常:
definePageMeta({ layout: "moviedetails", key: (route) => route.fullPath });
4. 清除Nuxt缓存并重启服务
首页可能被缓存为客户端渲染版本,执行以下操作清除缓存:
- 删除项目根目录下的
.nuxt和.output文件夹 - 运行
npx nuxi clean命令 - 重启开发服务器
5. 检查自定义API的请求状态
确保首页调用的/api/trendslider/day、/api/ign/home、/api/genres接口在服务端正常返回数据。可以在useFetch中添加错误处理,排查请求问题:
const { data: todayTrendsData, error: todayError } = await useFetch(`/api/trendslider/day?type=day`) if (todayError.value) { console.error('今日趋势接口请求失败:', todayError.value) }
内容的提问来源于stack exchange,提问作者Yazan Haffar
相关产品推荐
相关产品推荐

