Laravel Mix Watch不更新Vue Router加载的组件文件问题
问题:Laravel Mix watch无法检测Vue路由组件的修改并重新构建
我有一个基于Symfony(搭配Laravel Mix)+Vue+Vue Router的应用。运行npm run watch时,Webpack能检测到App.vue的修改并更新app.js,但像Conversation.vue这类通过路由懒加载的组件修改后,app.js不会自动更新。试过laravel-mix-vue-auto-routing但没用。Symfony仅用于会话管理和API服务。
相关配置代码
webpack.mix.js
const path = require('path') const mix = require('laravel-mix') const glob = require('glob') const webpack = require('webpack') const { VuetifyPlugin } = require('webpack-plugin-vuetify') const { PurgeCSSPlugin } = require('purgecss-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') mix.setPublicPath('public').webpackConfig({ module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, "css-loader" ] } ] }, plugins: [ new VuetifyPlugin({ styles: { configFile: 'resources/sass/vuetify-config.scss' } }), new webpack.DefinePlugin({ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false', }), new MiniCssExtractPlugin({ filename: "[name].css", }), mix.inProduction() ? new PurgeCSSPlugin({ paths: glob.sync(`${path.join(__dirname, 'public')}/**/*`, { nodir: true }), }) : () => {} // Empty function to skip PurgeCSS in development ] }) mix.js('resources/js/pages/app.js', 'public/js/pages/app.js').vue().version() mix.sass('resources/sass/app.scss', 'public/css').version()
router/index.js
import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/', alias: ['/conversations'], name: 'Conversations', meta: { title: 'Conversations - Inbox' }, component: () => import('../components/Conversations/NoConversation.vue') }, { path: '/conversations/:id', name: 'Conversation', meta: { title: 'Conversations - Inbox' }, component: () => import('../components/Conversations/Conversation.vue'), props: (route) => ({ conversationId: route.params.id }) } ] const router = createRouter({ history: createWebHistory(), routes }) export default router
resources/js/pages/app.js
import router from '../router' import { createApp } from 'vue' import { pinia } from '../stores' import { vuetify } from '../vuetify' import { library } from '@fortawesome/fontawesome-svg-core' import { fas } from '@fortawesome/free-solid-svg-icons' import { far } from '@fortawesome/free-regular-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import App from '../components/App.vue' import { useUserStore } from '../stores/user' library.add(fas, far) const app = createApp(App) app.component('font-awesome-icon', FontAwesomeIcon) app.use(pinia).use(router).use(vuetify) await useUserStore().fetchData() app.mount('#app')
resources/js/components/App.vue
<script setup> import Header from './App/Header.vue' import Layout from './Conversations/Layout.vue' import NotFound from './App/NotFound.vue' const { notFound } = defineProps({ notFound: Boolean }) </script> <template> <v-app> <v-main> <NotFound v-if="notFound" /> <template v-else> <Header /> <Layout> <router-view /> </Layout> </template> </v-main> </v-app> </template>
src/Controller/IndexController.php
<?php namespace App\Controller; use App\Helper\ViewHelper; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class IndexController extends AbstractController { private ViewHelper $viewHelper; public function __construct(ViewHelper $viewHelper) { $this->viewHelper = $viewHelper; } #[Route('/', name: 'homepage', methods: ['GET'])] #[Route('/conversations', name: 'conversations', methods: ['GET'])] #[Route('/conversations/{route}', name: 'catch_all', methods: ['GET'])] public function index(): Response { $data = [ 'title' => 'Inbox', 'component' => 'app', ]; return $this->render('views/index.html.twig', array_merge($data, $this->viewHelper->getCommonViewData())); } }
package.json
{ "scripts": { "dev": "npm run development", "development": "mix", "watch": "mix watch", "prod": "npm run production", "production": "mix --production", "format": "prettier . --write" }, "dependencies": { "@fawmi/vue-google-maps": "^0.9.79", "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.6", "@popperjs/core": "^2.11.8", "@vueuse/core": "^10.7.1", "axios": "^1.6.7", "boxicons": "^2.1.4", "glob": "^10.3.10", "laravel-mix": "^6.0.49", "mini-css-extract-plugin": "^2.8.0", "mitt": "^3.0.1", "moment": "^2.30.1", "path": "^0.12.7", "pinia": "^2.1.7", "purgecss-webpack-plugin": "^5.0.0", "vue": "^3.4.19", "vue-auto-routing": "^1.0.1", "vue-router": "^4.0.13", "vuetify": "^3.5.5", "webpack-plugin-vuetify": "^2.0.1" }, "devDependencies": { "@mdi/font": "^7.1.96", "@rushstack/eslint-patch": "^1.7.2", "@types/google.maps": "^3.54.4", "@types/webpack-env": "^1.18.0", "@vitejs/plugin-vue": "^5.0.4", "@vue/compiler-sfc": "^3.2.45", "@vue/eslint-config-prettier": "^9.0.0", "autoprefixer": "^10.4.17", "cross-env": "^7.0.3", "eslint": "^8.49.0", "eslint-plugin-vue": "^9.22.0", "laravel-mix-vue3": "^0.7.0", "postcss": "^8.4.35", "resolve-url-loader": "^5.0.0", "sass": "^1.57.1", "sass-loader": "^13.2.0", "tailwindcss": "^3.4.1", "vue-loader": "^17.0.1", "webpack": "^5.90.3" } }
解决方案
1. 配置Webpack监听所有Vue文件并启用热重载
Laravel Mix默认的watch配置可能未正确追踪懒加载组件的依赖,需显式添加watchOptions并开启热模块替换(HMR)。
修改webpack.mix.js,在webpackConfig中新增以下配置:
watchOptions: { ignored: /node_modules/, aggregateTimeout: 300, poll: 1000 }, devServer: { hot: true, liveReload: true }
完整修改后的webpack.mix.js:
const path = require('path') const mix = require('laravel-mix') const glob = require('glob') const webpack = require('webpack') const { VuetifyPlugin } = require('webpack-plugin-vuetify') const { PurgeCSSPlugin } = require('purgecss-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') mix.setPublicPath('public').webpackConfig({ module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, "css-loader" ] } ] }, plugins: [ new VuetifyPlugin({ styles: { configFile: 'resources/sass/vuetify-config.scss' } }), new webpack.DefinePlugin({ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false', }), new MiniCssExtractPlugin({ filename: "[name].css", }), mix.inProduction() ? new PurgeCSSPlugin({ paths: glob.sync(`${path.join(__dirname, 'public')}/**/*`, { nodir: true }), }) : () => {} // Empty function to skip PurgeCSS in development ], watchOptions: { ignored: /node_modules/, aggregateTimeout: 300, poll: 1000 }, devServer: { hot: true, liveReload: true } }) mix.js('resources/js/pages/app.js', 'public/js/pages/app.js').vue({ version: 3, options: { compilerOptions: { preserveWhitespace: false } } }).version() mix.sass('resources/sass/app.scss', 'public/css').version()
2. 清除Webpack缓存并重启watch
缓存可能导致文件变化不被检测,执行以下命令:
rm -rf node_modules/.cache npm run watch
3. 确认懒加载组件路径正确性
检查路由中import的相对路径是否存在大小写错误(Linux/macOS环境敏感),确保Webpack能正确建立依赖关系。
4. 开发环境暂时禁用版本号(可选)
version()生成的哈希文件名可能干扰热重载,开发时可注释该配置:
// mix.js('resources/js/pages/app.js', 'public/js/pages/app.js').vue().version() mix.js('resources/js/pages/app.js', 'public/js/pages/app.js').vue() // mix.sass('resources/sass/app.scss', 'public/css').version() mix.sass('resources/sass/app.scss', 'public/css')
内容的提问来源于stack exchange,提问作者Manos Liod
相关产品推荐
相关产品推荐

