Vue3结合Laravel Blade模板生产构建失效问题求助
问题:Laravel Blade结合Vue3 SFC构建后页面空白
场景与代码
尝试在Laravel Blade文件中使用Vue3单文件组件(SFC),开发环境功能正常,但生产构建后页面空白。相关代码如下:
Test.vue
<script setup> import { ref} from 'vue'; const testValue = ref('Works'); </script>
app.blade.php
<head> @stack('js') </head> <body> <div id="app"> @yield('content') </div> </body> </html>
test.blade.php
@extends('layouts.app') @push('js') @vite(['resources/js/test.js']) @endpush @section('content') <span>@{{ testValue }}</span> @endsection
test.js
import { createApp } from 'vue'; import Test from "./components/Test.vue"; const app = createApp(Test).mount("#app");
vite.config.js
import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ server: { hmr: true, https: false, host: 'localhost', proxy: { '/app': { target: 'wss://localhost:6001', ws: true } } }, plugins: [ laravel( { input: [ 'resources/js/test.js', ], refresh: true, }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), ], resolve: { alias: { 'vue': 'vue/dist/vue.esm-bundler.js', }, }, build: { chunkSizeWarningLimit: 1000, }, define: { __VUE_PROD_DEVTOOLS__: true, __VUE_OPTIONS_API__: true, } });
问题现象
npm run dev时功能正常,Blade中的Vue插值@{{ testValue }}能正确渲染npm run build执行后,页面空白,Blade中的模板内容无法加载
原因分析
- Vue挂载逻辑覆盖DOM内容:当前用
createApp(Test).mount("#app")时,Vue会替换#app元素的全部内容。开发环境下Vite的HMR机制会等待Blade渲染完成后再挂载Vue,所以Blade内容能被保留并解析;但生产构建后,JS文件可能在Blade内容渲染完成前就执行,或者因为Test.vue没有模板内容,Vue挂载后直接清空了#app内的Blade代码。 - Test.vue无模板定义:你的
Test.vue仅包含逻辑代码,没有<template>部分,Vue无法找到模板,挂载时只能替换掉#app的原有内容。
解决方法
方法1:调整Vue挂载逻辑,保留Blade模板
无需将Test.vue作为根组件,而是创建空根组件挂载到#app,让Vue接管Blade内的模板:
修改test.js:
import { createApp, ref } from 'vue'; const app = createApp({ setup() { const testValue = ref('Works'); return { testValue }; } }).mount("#app");
若要复用Test.vue的逻辑,可将其改为逻辑导出组件:Test.vue修改为:
<script setup> import { ref} from 'vue'; export const testValue = ref('Works'); </script>
test.js对应修改:
import { createApp } from 'vue'; import { testValue } from "./components/Test.vue"; const app = createApp({ setup() { return { testValue }; } }).mount("#app");
方法2:让Vue复用Blade模板作为根组件模板
修改test.js,手动获取#app内的Blade渲染内容作为模板:
import { createApp, h } from 'vue'; import Test from "./components/Test.vue"; // 获取Blade渲染后的DOM内容 const appEl = document.getElementById('app'); const template = appEl.innerHTML; // 合并Test组件逻辑与Blade模板 const app = createApp({ extends: Test, render() { return h('div', { innerHTML: template }); } }).mount("#app");
方法3:确保JS在DOM加载完成后执行
调整app.blade.php,将JS栈移到</body>前,确保Blade内容先渲染:
<head> </head> <body> <div id="app"> @yield('content') </div> @stack('js') </body> </html>
同时在test.blade.php中给Vite添加defer属性,延迟JS执行:
@extends('layouts.app') @section('content') <span>@{{ testValue }}</span> @endsection @push('js') @vite(['resources/js/test.js'], { defer: true }) @endpush
内容的提问来源于stack exchange,提问作者Sc00rpY
相关产品推荐
相关产品推荐

