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

Vue3+Vite构建/预览后页面空白无报错求助

Vue 3 + Vite + TypeScript 构建后页面空白无报错问题

使用Vue.js 3 + Vite + TypeScript开发前端应用时,npm run dev启动开发服务一切正常,但执行npm run build后部署或npm run preview预览时,页面始终空白,浏览器控制台无任何报错。

细节说明

  • 访问根路由/和公开路由/login均出现此问题
  • 构建流程为npm run build → cd dist → 用serve命令启动服务
  • npm run preview及构建后启动服务的控制台均无异常日志

版本信息

  • VITE v3.2.7
  • Vue v3.2.41
  • Node v18.17.1
  • NPM v9.6.7
  • Serve v14.2.1

诊断结果

通过在生产/预览模式下启用Chrome Vue Devtools发现:开发模式下<Root>下的<RouterView>能正常渲染组件,但生产/预览模式下无法渲染。Devtools中显示的路由、I18N资源、Vuex等其他资源在两种模式下一致,页面标题和图标能正常加载。

相关项目文件

// vite.config.ts
// Plugins
import vue from '@vitejs/plugin-vue'
import vueI18n from '@intlify/vite-plugin-vue-i18n'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'

// Utilities
import { defineConfig } from 'vite'
import { fileURLToPath, URL } from 'node:url'
import { resolve, dirname } from 'node:path'

export default defineConfig(({ mode }) => ({
  plugins: [
    vue(),
    vueI18n({
      include: resolve(dirname(fileURLToPath(import.meta.url)), './src/locales/**'),
    }),
    VueI18nPlugin({ /* options */ }),
  ],
  define: { 
    'process.env': {},
    __VUE_PROD_DEVTOOLS__: mode !== 'production' },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
    extensions: [
      '.js',
      '.json',
      '.jsx',
      '.mjs',
      '.ts',
      '.tsx',
      '.vue',
    ],
  },
  server: {
    port: 3000,
    host: true,
  },
  test: {
    globals: true,
    environment: 'jsdom',
    exclude: [
      '**/node_modules/**'
    ]
  }
}))
// package.json
  "name": "my-frontend-project",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build --mode development", // "--mode development" has been added for devtools as said above, the bug happend before I added it.
    "preview": "vite preview",
    "lint": "eslint . --fix --ignore-path .gitignore",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    "test": "vitest",
    "coverage": "vitest run --coverage"
  },
[...] 
// index.html
<!DOCTYPE html>
<html lang="fr-BE" class="h-full">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/png" href="/images/tenants/compagny/favicon-180x180.png" sizes="180x180" />
  <link rel="icon" type="image/png" href="/images/tenants/compagny/favicon-96x96.png" sizes="96x96" />
  <link rel="icon" type="image/png" href="/images/tenants/compagny/favicon-48x48.png" sizes="48x48" />
  <link rel="icon" type="image/png" href="/images/tenants/compagny/favicon-32x32.png" sizes="32x32" />
  <link rel="icon" type="image/png" href="/images/tenants/compagny/favicon-16x16.png" sizes="16x16" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>compagny - Home</title>
</head>

<body class="h-full">
  <div id="app" class="h-full"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>
// src/main.ts
// Components
import App from './App.vue'
import MasonryWall from '@yeger/vue-masonry-wall'
import VueTailwindDatepicker from "vue-tailwind-datepicker"
import store from '@/core/store'
import './index.css'
import { i18n } from '@/locales/i18n.configuration'

// Composables
import { createApp } from 'vue'

// Plugins
import { registerPlugins } from '@/plugins'

export { i18n };

const app = createApp({
  extends: App
})

registerPlugins(app)

app.use(i18n)
app.use(MasonryWall)
app.use(VueTailwindDatepicker)
app.use(store)
app.mount('#app')
// src/plugins/index.ts
/**
 * plugins/index.ts
 *
 * Automatically included in `./src/main.ts`
 */

// Plugins
import { loadFonts } from './webfontloader'
import router from '@/router'

// Types
import type { App } from 'vue'

export function registerPlugins (app: App) {
  loadFonts()
  app
  .use(router)
}
// src/App.vue
<template>
  <router-view />
</template>

<script lang="ts" setup>
  //
</script>
// src/router/index.ts
// Composables
import { createRouter, createWebHistory } from 'vue-router'
import LocalAuthenticationService from "@/core/services/auth/LocalAuthentication.service";

// Routes
import coreRoutes from '@/core/router'

const routes = [
  ...coreRoutes,
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
})

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth) {
    if (LocalAuthenticationService.isLoggedIn()) {
      // User is authenticated, proceed to the route
      next();
    } else {
      // User is not authenticated, redirect to login
      next({ name: "login" });
    }
  } else {
    // Non-protected route, allow access
    next();
  }
});

export default router
// src/core/router.ts
const BasicLayout = () => import("./views/layouts/BasicLayout.vue");
const ViewBasicLogin = () => import("./views/auth/BasicLogin.vue");
const TemporaryHome = () => import("./views/temporary/TemporaryHome.vue");

export default [
  {
    path: "/",
    component: BasicLayout,
    children: [
      {
        path: "",
        name: "home",
        component: TemporaryHome,

      }
    ],
  },
  {
    path: "/login",
    name: "login",
    component: ViewBasicLogin,

  }
]

[...] 

已尝试无效方案

  • 在vite.config.ts的defineConfig中添加base: './'或base: '/'
  • 为路由添加path: '/:pathMatch(.*)*'的全局重定向路由

可能的解决方法

1. 修改App实例创建方式

main.ts中使用extends: App的写法不符合Vue 3常规用法,可能导致生产环境渲染异常,改为直接传入组件:

// src/main.ts
const app = createApp(App)

2. 移除冲突的I18n插件

vite.config.ts中同时启用了@intlify/vite-plugin-vue-i18n和@intlify/unplugin-vue-i18n/vite,存在插件冲突风险,注释其中一个后重新构建:

// vite.config.ts
plugins: [
  vue(),
  vueI18n({
    include: resolve(dirname(fileURLToPath(import.meta.url)), './src/locales/**'),
  }),
  // VueI18nPlugin({ /* options */ }), // 注释此插件
],

3. 调整构建模式配置

package.json中build命令添加了--mode development,尝试移除该参数,使用默认生产模式构建:

// package.json
"build": "vue-tsc --noEmit && vite build"

4. 测试同步组件加载

将路由中的异步组件改为同步导入,排查是否为异步组件加载问题:

// src/core/router.ts
import BasicLayout from "./views/layouts/BasicLayout.vue";
import ViewBasicLogin from "./views/auth/BasicLogin.vue";
import TemporaryHome from "./views/temporary/TemporaryHome.vue";

export default [
  // 路由配置不变
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:52:03