You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:50:54