Laravel/Vue3项目生产构建后b-modal组件失效求助
Laravel+Vue3项目使用bootstrap-vue-next的b-modal组件,开发环境执行npm run dev时组件正常工作,但执行npm run prod(即vite build)进行生产资源构建后,模态框完全失效。已尝试更换vite、bootstrap-vue-next版本,甚至改用webpack构建,问题仍未解决。以下是项目相关配置及代码片段,请求排查。
项目配置文件
package.json
{ "private": false, "scripts": { "dev": "vite", "prod": "vite build" }, "devDependencies": { "@popperjs/core": "^2.11.6", "@vitejs/plugin-vue": "^4.3.4", "axios": "^0.25.0", "lodash": "^4.17.19", "postcss": "^8.1.14", "sass": "^1.56.1", "vue": "^3.3.4" }, "dependencies": { "@anivive/vue3-form-wizard": "^1.0.1", "@chenfengyuan/vue-countdown": "^2.1.1", "@ckeditor/ckeditor5-build-classic": "^36.0.1", "@ckeditor/ckeditor5-vue": "^4.0.1", "@fullcalendar/bootstrap5": "^6.1.5", "@fullcalendar/core": "^6.1.5", "@fullcalendar/daygrid": "^6.1.5", "@fullcalendar/interaction": "^6.1.5", "@fullcalendar/list": "^6.1.5", "@fullcalendar/timegrid": "^6.1.5", "@fullcalendar/vue3": "^6.1.5", "@j-t-mcc/vue3-chartjs": "^1.3.0", "@vitejs/plugin-vue": "^4.3.4", "@vue-leaflet/vue-leaflet": "^0.9.0", "@vue/compiler-sfc": "^3.2.47", "@vueform/multiselect": "^2.6.1", "@vueform/slider": "^2.1.7", "@vuelidate/core": "^2.0.0", "@vuelidate/validators": "^2.0.0", "bootstrap": "^5.2.0", "bootstrap-vue-next": "^0.6.7", "dropzone": "^6.0.0-beta.2", "fullcalendar": "^6.1.4", "i18n": "^0.15.1", "laravel-vite-plugin": "^0.7.4", "leaflet": "^1.9.3", "maska": "^1.5.0", "metismenujs": "^1.4.0", "simplebar-vue": "^2.3.1", "simplebar-vue3": "^0.2.0", "sweetalert2": "^11.7.3", "vite": "^4.4.9", "vite-plugin-static-copy": "^0.13.1", "vue-carousel": "^0.18.0", "vue-cropperjs": "^5.0.0", "vue-draggable-next": "^2.1.1", "vue-easy-lightbox": "^1.15.0", "vue-form-wizard": "^0.8.4", "vue-i18n": "^9.2.2", "vue-loader": "^17.0.1", "vue-router": "^4.1.6", "vue3-apexcharts": "^1.4.1", "vue3-carousel": "^0.2.13", "vue3-datepicker": "^0.3.4", "vue3-dropzone": "^2.0.1", "vue3-google-map": "^0.15.0", "vuelidate": "^0.7.7", "vuex": "^4.0.2" } }
vite.config.js
import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import { viteStaticCopy } from 'vite-plugin-static-copy' import vue from '@vitejs/plugin-vue'; export default defineConfig({ build: { manifest: true, outDir: 'public/build/', cssCodeSplit: true, rollupOptions: { output: { assetFileNames: (assetInfo) => { if (assetInfo.name.endsWith('.css')) { return `css/[name].[hash].css`; } return `assets/[name].[hash][extname]`; }, entryFileNames: 'js/[name].[hash].js', }, }, chunkSizeWarningLimit: 2000, manualChunks: { 'chunk-vendor': ['vue'], 'chunk-app': ['app.js', 'app-rtl.scss'], 'chunk-bootstrap': ['bootstrap.scss'], 'chunk-icons': ['icons.scss'], }, }, plugins: [ laravel({ input: [ 'resources/sass/app.scss', 'resources/sass/app-rtl.scss', 'resources/sass/bootstrap.scss', 'resources/sass/icons.scss', 'resources/js/app.js', ], refresh: true, }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), viteStaticCopy({ targets: [ { src: 'resources/fonts', dest: '' }, { src: 'resources/images', dest: '' }, ], }) ], resolve: { alias: { vue: 'vue/dist/vue.esm-bundler.js', }, }, });
模态框代码片段
<b-modal> <div class="card-body"> <form action="javascript:void(0)" > <div class="row"> <div class="col-lg-4"> <div class="mb-3"> <label for="name">Name</label> <input type="text" class="form-control" id="name65" placeholder="Enter Device Name" v-model="obj.name" @input="validateName"/> <span v-if="validationErrors.nameError" class="text-danger">{{validationErrors.nameError}}</span> </div> </div> <div class="col-lg-4"> <div class="mb-3"> <label for="reg_no6">Unique ID</label> <input type="text" class="form-control" id="reg_no" placeholder="Enter ID emitted by the object" v-model="obj.unique_id" @input="validateRegistration" /> <span v-if="validationErrors.unique_idError" class="text-danger">{{validationErrors.unique_idError}}</span> </div> </div> </div> <div class="row"> <div class="col-lg-12"> <div class="text-end"> <button type="submit" class="btn btn-primary" @click="saveObj">Submit</button> </div> </div> </div> </form> </div> </b-modal>
排查方向建议
- 确认bootstrap-vue-next注册方式:检查app.js中是否全局注册了bootstrap-vue-next,生产构建的tree-shaking可能移除未正确注册的组件。正确全局注册代码:
import { createApp } from 'vue' import BootstrapVueNext from 'bootstrap-vue-next' import 'bootstrap-vue-next/dist/bootstrap-vue-next.css' const app = createApp(App) app.use(BootstrapVueNext)
若为按需引入,需显式导入并注册b-modal,避免被tree-shaking误删。
- 调整tree-shaking配置:vite生产模式默认开启tree-shaking,若组件未被识别为使用中会被移除。可在vite.config.js的
build.rollupOptions中添加:
external: ['bootstrap-vue-next'], // 或临时开启模块保留测试 output: { preserveModules: true }
测试是否解决问题,逐步定位是否为tree-shaking导致。
检查CSS加载状态:生产构建后,通过浏览器开发者工具查看
b-modal元素的类名是否完整,对应的bootstrap-vue-next CSS规则是否加载成功。补全组件核心属性:当前代码中的
b-modal缺少v-model绑定控制显示/隐藏状态,开发环境宽松规则可能正常工作,但生产环境严格编译会导致组件无法触发。需添加:
<b-modal v-model="showModal"> <!-- 内容 --> </b-modal>
并在组件data中定义showModal: false,通过按钮触发showModal = true打开模态框。
验证依赖版本兼容性:当前使用的bootstrap-vue-next@0.6.7与bootstrap@5.2.0、vue@3.3.4可能存在版本适配问题。尝试升级bootstrap-vue-next到最新稳定版,同时确保bootstrap版本与之匹配。
查看生产环境控制台错误:打开浏览器开发者工具的Console面板,排查是否有JS报错(如模块未找到、变量未定义等),这类错误通常是组件失效的直接原因。
内容的提问来源于stack exchange,提问作者Law

