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

Laravel+Vue+Inertia配置TypeScript遇500服务器错误求助

Laravel + Vue 3 + Inertia 转 TypeScript 后 npm run dev 报 500 错误

我用 Laravel、Vue 3 和 Inertia 技术栈把项目转成 TypeScript 后,执行 npm run dev 时 Chrome 控制台提示「加载资源失败:服务器响应状态码为 500 ()」。完全跟着教程操作还是出问题,排查后怀疑是配置问题,附上我的配置文件和组件代码,求解决:

配置文件

resources/js/app.ts

import "../css/app.css";
import { createApp, h, type DefineComponent } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

createInertiaApp({
    resolve: async (name: string) => {
        let page = await resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue'))
        return page
    },
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el)
    },
})

tsconfig.json

{
  "compilerOptions": {
   
    "target": "es2016",                                  
    "jsx": "preserve",                                
    "module": "commonjs",                               
    "paths": {
        "@/*": ["./resources/js/*"]
    },                                                            
    "resolveJsonModule": true,                       
    "allowJs": true,                                  
    "isolatedModules": true,                                    
    "esModuleInterop": true,                               
    "forceConsistentCasingInFileNames": true,            
    "strict": true,                                             
    "skipLibCheck": true                                
  }
}

resources/views/app.blade.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    @vite('resources/js/app.ts')
    @inertiaHead
</head>
<body>
@inertia
</body>
</html>

vite.config.js

import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.ts'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
});

父组件示例

<script setup lang="ts">
import { defineProps, reactive, ref, onMounted } from 'vue';
import WeatherDisplay  from './WeatherDisplay';
import { Refs, WeatherData } from '../interfaces/interfaces'
import { useDark, useToggle } from '@vueuse/core';
import { router } from '@inertiajs/vue3';

const isDark = useDark();
const toggleDark = useToggle(isDark);

// Define the props for the component
const props = defineProps<{
    data: Object,
}>();

// This object contains all required refs
const allRefs = ref<Refs>({
    searchWeather: '',
    errorMessage: null,
});

// Creates a reactive array that is updated with weatherData
const weatherData = reactive<WeatherData[]>([]);

// Function to load data from local storage
function loadDataFromLocalStorage(): WeatherData[] {
    const data = localStorage.getItem('weatherData');
    return data ? JSON.parse(data) : [];
}

// Function to set data to local storage
function setDataToLocalStorage(data: WeatherData[]) {
    weatherData.push(props.data);
    localStorage.setItem('weatherData', JSON.stringify(data));
}

// Delete weather data from array and local storage
function deleteWeatherData(index: number) {
    weatherData.splice(index, 1);
    localStorage.setItem('weatherData', JSON.stringify(weatherData));
}

// Load the data from local storage on mounted
onMounted(() => {
    const savedData = loadDataFromLocalStorage();
    if (savedData.length > 0) {
        weatherData.splice(0, weatherData.length, ...savedData);
    }

    if (props.data && !props.data.error) {
        setDataToLocalStorage(weatherData);
    } else if (props.data && props.data.error) {
        allRefs.value.errorMessage = props.data.error.message;
        console.log(allRefs.value.errorMessage);
    }
});

// Define a method to send the GET request to the backend
async function submit() {
    try {
        await router.get('/weather',  { searchWeather: allRefs.value.searchWeather });
    } catch (error) {
        console.log(error);
    }
}
</script>
<template>
    <main :class="{ 'dark-mode': isDark }">
        <div class="flex flex-col items-center justify-center h-96">
            <div
                class="mb-4 text-center text-4xl font-bold dark:text-[#7371FF]"
            >
                SecureClouds
            </div>
            <div class="flex flex-row justify-end mb-4">
                <div class="mr-4 flex items-center">
                    <span class="text-xl dark:text-[#7371FF]">
                        {{ isDark ? 'Dark' : 'Light' }} Mode
                    </span>
                </div>
                <div>
                    <button
                        @click="toggleDark()"
                        class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded dark:bg-[#22F1BF] dark:text-black"
                    >
                        Switch
                    </button>
                </div>
            </div>
            <div class="block w-2/3 rounded-lg">
                <div class="flex justify-center">
                    <div class="w-2/3 p-4">
                        <div
                            v-if="allRefs.errorMessage"
                            class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
                            role="alert"
                        >
                            <strong class="font-bold">{{
                                allRefs.errorMessage
                            }}</strong>
                        </div>

                        <form @submit.prevent="submit" class="w-full">
                            <div
                                class="relative mb-4 flex w-full flex-wrap items-stretch"
                            >
                                <input
                                    type="search"
                                    class="relative bg-[#F9F3EE] m-0 -mr-px block flex-auto border border-neutral-300 rounded-lg shadow dark:bg-transparent bg-clip-padding px-6 py-4 text-lg font-normal text-neutral-700 outline-none transition duration-300 ease-in-out focus:border-primary-600 focus:text-neutral-700 focus:shadow-te-primary focus:outline-none dark:border-[#22F1BF] dark:text-[#22F1BF] dark:placeholder:text-[#22F1BF]"
                                    placeholder="Suchen..."
                                    name="searchWeather"
                                    aria-label="Search"
                                    aria-describedby="button-addon3"
                                    v-model="allRefs.searchWeather"
                                />
                                <button
                                    type="submit"
                                    class="bg-[#F9F3EE] hover:bg-slate-200 text-gray-800 font-semibold py-2 px-6 border border-neutral-300 rounded-lg shadow ml-4 dark:bg-[#22F1BF] dark:border-[#22F1BF] dark:text-black"
                                >
                                    Suchen
                                </button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <div class="grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-3 gap-4">
            <WeatherDisplay
                v-for="(data, index) in weatherData"
                :key="index"
                :data="data"
                @delete="deleteWeatherData(index)"
            >
            </WeatherDisplay>
        </div>
    </main>
</template>

<style>
main {
    background-color: #b2c8df;
    overflow-y: scroll;
    height: 100vh;
}
.dark-mode {
    background: #0d1117;
}
</style>

可能的解决步骤

1. 查看 Laravel 日志定位真实错误

浏览器的 500 错误只是表面现象,真实错误信息在 Laravel 的日志文件里:storage/logs/laravel.log。先打开这个日志,找到对应时间点的错误条目,这是最直接的排查方式。

2. 修正 tsconfig.json 的模块配置

Vite 基于 ES 模块运行,你的 tsconfig.json 里 module 设置为 commonjs 会导致模块解析冲突。修改为:

"module": "ESNext",
"moduleResolution": "bundler",

3. 修复 app.ts 中的 resolve 函数

resolvePageComponent 返回的模块可能需要取 default 导出,否则会导致组件加载失败。调整 resolve 函数:

resolve: async (name: string) => {
    const page = await resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue'));
    // 确保返回组件的默认导出
    return page.default || page;
},

4. 组件中使用精确的 Props 类型

你当前的组件 props 用了 Object 类型,这不符合 TypeScript 规范,可能导致编译错误。替换为你定义的 WeatherData 类型:

const props = defineProps<{
    data: WeatherData | { error: { message: string } };
}>();

5. 安装必要的 TypeScript 依赖

确保安装了 Vue 和 Inertia 的类型定义,以及 Vite 相关的 TypeScript 支持:

npm install -D @types/node vue-tsc @vitejs/plugin-vue

6. 清理缓存并重启服务

  • 清理 Laravel 缓存:php artisan cache:clear && php artisan config:clear
  • 清理 Vite 缓存:删除 node_modules/.vite 文件夹
  • 重启 npm run dev 和 Laravel 服务

内容的提问来源于stack exchange,提问作者Michael Brilz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:09:54