如何在Laravel10+Inertia SSR中使用仅客户端Vue插件?
解决Laravel 10 + Jetstream + Inertia SSR下Vue Apexcharts与@fawmi/vue-google-maps的兼容问题
这两个插件故障的核心原因是:它们都依赖浏览器环境的API(如window、document),而SSR在服务端渲染阶段不存在这些对象,直接引入会触发环境不兼容报错。以下是针对性的解决方法:
一、处理Vue Apexcharts
方案1:动态导入+客户端专属渲染
通过client-only组件确保服务端跳过渲染,仅在客户端动态加载组件与依赖资源:
<template> <client-only> <apexchart v-if="ApexChart" :options="chartOptions" :series="series" type="bar" height="350" /> </client-only> </template> <script setup> import { ref, onMounted } from 'vue' import { useHead } from '@inertiajs/vue3' const ApexChart = ref(null) const chartOptions = ref({ // 你的图表配置项 xaxis: { categories: ['Jan', 'Feb', 'Mar'] } }) const series = ref([{ name: 'Sales', data: [30, 40, 45] }]) onMounted(async () => { // 仅在客户端导入组件 const module = await import('vue3-apexcharts') ApexChart.value = module.default }) // 客户端加载Apexcharts的CSS与脚本 useHead({ script: [{ src: 'https://cdn.jsdelivr.net/npm/apexcharts', body: true, async: true }], link: [{ rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/apexcharts/dist/apexcharts.css' }] }) </script>
方案2:拆分插件注册逻辑
在客户端入口resources/js/app.js中注册Apexcharts,服务端入口resources/js/ssr.js中跳过注册:
// app.js(仅客户端) import { createApp, h } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import ApexCharts from 'vue3-apexcharts' createInertiaApp({ resolve: name => require(`./Pages/${name}.vue`), setup({ el, App, props, plugin }) { return createApp({ render: () => h(App, props) }) .use(plugin) .use(ApexCharts) .mount(el) }, })
ssr.js中不要添加use(ApexCharts)的代码,避免服务端打包时引入插件。
二、处理@fawmi/vue-google-maps
方案1:动态导入+客户端渲染
同样用client-only隔离服务端渲染,动态加载组件与Google Maps脚本:
<template> <client-only> <GMapMap v-if="GMapMap" :center="{ lat: 51.093048, lng: 6.842120 }" :zoom="10" style="width: 100%; height: 400px" > <GMapMarker :position="{ lat: 51.093048, lng: 6.842120 }" /> </GMapMap> </client-only> </template> <script setup> import { ref, onMounted } from 'vue' import { useHead } from '@inertiajs/vue3' const GMapMap = ref(null) const GMapMarker = ref(null) onMounted(async () => { const module = await import('@fawmi/vue-google-maps') GMapMap.value = module.GMapMap GMapMarker.value = module.GMapMarker }) // 客户端加载Google Maps官方脚本(替换为你的API密钥) useHead({ script: [{ src: `https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places`, body: true, async: true }] }) </script>
方案2:拆分插件注册逻辑
仅在客户端入口注册Google Maps插件:
// app.js(仅客户端) import { createApp, h } from 'vue' import { createInertiaApp } from '@inertiajs/vue3' import VueGoogleMaps from '@fawmi/vue-google-maps' createInertiaApp({ resolve: name => require(`./Pages/${name}.vue`), setup({ el, App, props, plugin }) { return createApp({ render: () => h(App, props) }) .use(plugin) .use(VueGoogleMaps, { load: { key: 'YOUR_API_KEY', libraries: 'places', }, }) .mount(el) }, })
ssr.js中不要包含VueGoogleMaps的注册代码。
通用调试技巧
- 查看服务端日志,确认报错是否为
window is not defined或浏览器API缺失类问题; - 所有依赖浏览器环境的组件,都优先用
client-only包裹或动态导入; - 优先查阅插件官方文档,部分插件会提供SSR专属的兼容配置。
内容的提问来源于stack exchange,提问作者Andrii
相关产品推荐
相关产品推荐

