欢迎光临本地信息咨询网
详情描述
Vue + Vite 项目通过 /dist 子路径访问首页空白问题分析与解决方案

问题分析

当 Vue + Vite 项目部署到 /dist 子路径下出现空白页面时,通常由以下几个原因导致:

1. 静态资源路径配置问题

Vite 默认假设应用部署在根路径下,当部署到子路径时,静态资源路径引用会出错。

2. Vue Router 路径配置问题

如果使用 Vue Router,路由的基础路径需要与部署路径匹配。

3. 服务器配置问题

服务器未正确配置重写规则,导致无法正确处理单页应用的路由。

完整解决方案

方案一:Vite 配置解决方案

1. 更新 vite.config.js
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  // 设置项目根目录
  base: '/dist/',

  build: {
    // 输出目录
    outDir: 'dist',

    // 资源文件输出路径
    assetsDir: 'assets',

    // 静态资源引用路径处理
    rollupOptions: {
      output: {
        chunkFileNames: 'assets/js/[name]-[hash].js',
        entryFileNames: 'assets/js/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
      }
    }
  },

  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },

  server: {
    // 开发服务器配置
    port: 3000
  }
})
2. 更新 vue-router 配置
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  // ...其他路由
]

const router = createRouter({
  // 使用历史模式,并设置基础路径
  history: createWebHistory('/dist/'),
  routes
})

export default router

方案二:环境变量配置

1. 创建环境文件
# .env.production
VITE_APP_BASE_URL=/dist/
VITE_APP_API_BASE_URL=/api/
2. 动态配置 Vite
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig(({ mode }) => {
  // 加载环境变量
  const env = loadEnv(mode, process.cwd())

  return {
    plugins: [vue()],
    // 动态设置 base
    base: env.VITE_APP_BASE_URL,

    build: {
      outDir: 'dist',
      // 生成 sourcemap 便于调试
      sourcemap: mode === 'development',
    }
  }
})
3. 在代码中使用环境变量
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

// 获取基础路径
const basePath = import.meta.env.VITE_APP_BASE_URL || '/'

const app = createApp(App)
app.use(router)
app.mount('#app')

// 输出环境信息便于调试
console.log('Base URL:', basePath)

方案三:HTML 模板配置

1. 更新 index.html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="<%= VITE_APP_BASE_URL %>favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue App</title>

    <!-- 动态设置 base 标签 -->
    <base href="<%= VITE_APP_BASE_URL %>" />

    <!-- 解决相对路径问题 -->
    <script type="text/javascript">
      // 设置全局基础路径
      window.BASE_URL = '<%= VITE_APP_BASE_URL %>';

      // 修复 history 路由问题
      (function() {
        const basePath = '<%= VITE_APP_BASE_URL %>';
        if (basePath && basePath !== '/') {
          const originalPushState = history.pushState;
          const originalReplaceState = history.replaceState;

          history.pushState = function(state, title, url) {
            return originalPushState.call(this, state, title, basePath + url.replace(new RegExp('^' + basePath), ''));
          };

          history.replaceState = function(state, title, url) {
            return originalReplaceState.call(this, state, title, basePath + url.replace(new RegExp('^' + basePath), ''));
          };
        }
      })();
    </script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

方案四:服务器配置方案

1. Nginx 配置
server {
    listen 80;
    server_name your-domain.com;

    # 主应用路径
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # 子路径配置
    location /dist/ {
        alias /usr/share/nginx/html/dist/;
        index index.html;

        # 处理 Vue Router 的 history 模式
        try_files $uri $uri/ /dist/index.html;

        # 设置正确的 MIME 类型
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # API 代理
    location /api/ {
        proxy_pass http://api-server:3000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
2. Apache 配置
<VirtualHost *:80>
    ServerName your-domain.com
    DocumentRoot /var/www/html

    # 子路径配置
    Alias /dist /var/www/html/dist

    <Directory "/var/www/html/dist">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted

        # 重写规则支持 history 模式
        RewriteEngine On
        RewriteBase /dist/
        RewriteRule ^index\.html$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /dist/index.html [L]
    </Directory>
</VirtualHost>

方案五:构建后验证脚本

1. 创建验证脚本
// scripts/verify-build.js
import fs from 'fs'
import path from 'path'

const distPath = path.resolve(process.cwd(), 'dist')
const indexPath = path.join(distPath, 'index.html')

// 检查构建目录
if (!fs.existsSync(distPath)) {
  console.error('❌ dist 目录不存在')
  process.exit(1)
}

// 检查 index.html
if (!fs.existsSync(indexPath)) {
  console.error('❌ index.html 不存在')
  process.exit(1)
}

// 读取 index.html 内容
const htmlContent = fs.readFileSync(indexPath, 'utf-8')

// 检查资源路径
const checks = [
  {
    name: 'JavaScript 文件引用',
    pattern: /src="\/(?!\/)/,
    shouldExist: false,
    message: '❌ 发现绝对路径引用,应该使用相对路径或基础路径'
  },
  {
    name: '基础路径设置',
    pattern: /<base href="\/dist\/"/,
    shouldExist: true,
    message: '✅ 基础路径已正确设置'
  },
  {
    name: 'Vite 构建标记',
    pattern: /data-vite-project-id/,
    shouldExist: true,
    message: '✅ Vite 构建标记存在'
  }
]

console.log('🔍 开始验证构建结果...\n')

checks.forEach(check => {
  const hasMatch = check.pattern.test(htmlContent)
  const isCorrect = hasMatch === check.shouldExist

  if (isCorrect) {
    console.log(check.message)
  } else {
    console.log(`❌ ${check.name} 检查失败`)
  }
})

// 检查静态资源
const assetsDir = path.join(distPath, 'assets')
if (fs.existsSync(assetsDir)) {
  const assets = fs.readdirSync(assetsDir)
  console.log(`\n📁 发现 ${assets.length} 个资源文件`)
}

console.log('\n✅ 验证完成!')
2. 在 package.json 中添加脚本
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "verify": "node scripts/verify-build.js",
    "build:verify": "vite build && npm run verify"
  }
}

方案六:调试工具与技巧

1. 添加调试中间件
// vite.config.js - 开发服务器配置
server: {
  port: 3000,
  proxy: {
    '/api': {
      target: 'http://localhost:3001',
      changeOrigin: true
    }
  },
  // 添加自定义中间件调试请求
  configureServer: (server) => {
    server.middlewares.use((req, res, next) => {
      console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
      next()
    })
  }
}
2. 浏览器控制台调试
// 在应用启动时添加调试信息
console.group('应用环境信息')
console.log('Base URL:', import.meta.env.VITE_APP_BASE_URL)
console.log('Mode:', import.meta.env.MODE)
console.log('Public Path:', __webpack_public_path__ || '未设置')
console.groupEnd()

// 监控路由变化
router.afterEach((to, from) => {
  console.log(`路由变化: ${from.path} -> ${to.path}`)
})

最佳实践总结

始终使用环境变量配置基础路径 在开发和构建时使用相同的路径策略 确保服务器正确配置重写规则 使用相对路径或基于 base 的路径引用资源 构建后进行验证和测试

常见问题排查清单

  • [ ] 检查 vite.config.js 中的 base 配置
  • [ ] 验证 vue-routerhistory 模式基础路径
  • [ ] 检查服务器配置中的重写规则
  • [ ] 查看浏览器控制台是否有 404 错误
  • [ ] 确认静态资源文件是否被正确加载
  • [ ] 检查网络请求中的路径是否正确
  • [ ] 验证环境变量是否被正确注入
  • [ ] 确保所有路由都有相应的处理

通过以上方案,您可以系统地解决 Vue + Vite 项目在子路径部署时的空白页面问题。建议从方案一开始尝试,逐步排查和解决问题。

相关帖子
为什么有时候两个兴趣相似的好友,收到的推荐内容列表却差异很大?
为什么有时候两个兴趣相似的好友,收到的推荐内容列表却差异很大?
没有固定雇主,个人缴纳养老保险的金额该如何计算?
没有固定雇主,个人缴纳养老保险的金额该如何计算?
《俄罗斯女子学院》:19世纪圣彼得堡的“金丝雀牢笼”,贵族少女在沙皇阴影下学礼仪、藏叛逆
《俄罗斯女子学院》:19世纪圣彼得堡的“金丝雀牢笼”,贵族少女在沙皇阴影下学礼仪、藏叛逆
海浪与沙粒的对话:塑造沙滩形态的自然力量有哪些?
海浪与沙粒的对话:塑造沙滩形态的自然力量有哪些?
从《桃花源记》到《洞穴寓言》:东西方思想中“洞”的哲学意象。
从《桃花源记》到《洞穴寓言》:东西方思想中“洞”的哲学意象。
咸宁市专业网站开发建设&精准获客,多年专业建站经验
咸宁市专业网站开发建设&精准获客,多年专业建站经验
扬州市救护车转院转运回家&长途跨省救护车转运24小时电话
扬州市救护车转院转运回家&长途跨省救护车转运24小时电话
高效管理你的Linux系统: Debian操作系统常用命令指南
高效管理你的Linux系统: Debian操作系统常用命令指南
长期受噪音困扰影响休息,如何进行自我心理调节与舒缓?
长期受噪音困扰影响休息,如何进行自我心理调节与舒缓?
济南市网站建设服务%精准获客系统,高端网站开发设计
济南市网站建设服务%精准获客系统,高端网站开发设计
如果社保已经断缴了,在2026年还有没有机会进行补缴操作?
如果社保已经断缴了,在2026年还有没有机会进行补缴操作?
湛江市企业网站建设公司&做网站公司,收费标准
湛江市企业网站建设公司&做网站公司,收费标准
2026年通过哪些官方或正规的线上平台,可以查询到可靠的跨境招聘信息?
2026年通过哪些官方或正规的线上平台,可以查询到可靠的跨境招聘信息?
杭州市救护车长途跨省护送病人出院@120救护车一次多少钱
杭州市救护车长途跨省护送病人出院@120救护车一次多少钱
黄石市专业网站设计制作%定制化网站建设,小程序开发
黄石市专业网站设计制作%定制化网站建设,小程序开发
在马路上看到哪些问题可以通过随手拍上报并获得奖励?
在马路上看到哪些问题可以通过随手拍上报并获得奖励?
2026年异地销户是否支持线上办理,话费余额如何处理?
2026年异地销户是否支持线上办理,话费余额如何处理?
web面试常问http缓存解析相关
web面试常问http缓存解析相关
徐州市长途救护车出租&重症急救车出租,转院接送
徐州市长途救护车出租&重症急救车出租,转院接送
外卖骑手在等待取餐时,平台系统是如何自动识别和记录等时时间的?
外卖骑手在等待取餐时,平台系统是如何自动识别和记录等时时间的?