Vue 项目部署踩坑实录:从打包空白到路由刷新白屏的完整解决方案

在开发 Vue 项目的过程中,我们经常会遇到各种部署相关的问题。今天我想分享一下最近在部署一个排班管理系统时遇到的一些典型问题及其解决方案,希望能帮助到同样遇到这些问题的朋友。

问题背景

我们的项目是一个基于 Vue 的前后端分离项目,开发完成后需要打包部署到服务器上。在部署过程中,我们遇到了几个典型问题:

  1. 打包后使用npx serve命令启动显示空白页面
  2. 部署到服务器后,刷新页面出现白屏

下面我将详细记录每个问题的排查过程和解决方案。

问题一:打包后本地启动显示空白页面

问题现象

当我们完成开发后,使用npm run build命令打包项目,然后进入 dist 目录使用npx serve命令启动服务,结果打开浏览器发现页面完全是空白的,没有任何内容。

问题分析

通过检查打包后的index.html文件,我们发现了问题的关键:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="">
<head>
<meta base="/background/" />
<meta charset="utf-8" />
<!-- ... -->
<script defer="defer" src="/background/js/chunk-vendors.197cc9e1.js"></script>
<script defer="defer" src="/background/js/app.c9559ad8.js"></script>
<link href="/background/css/chunk-vendors.282a9c4b.css" rel="stylesheet" />
<link href="/background/css/app.204ccc13.css" rel="stylesheet" />
</head>
<!-- ... -->
</html>

可以看到,所有的静态资源(JS、CSS)都带有/background/前缀路径。这是因为在vue.config.js文件中配置了:

1
2
3
4
5
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true,
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/background/',
});

这个配置意味着生产环境构建的应用期望被部署在/background/路径下。当我们直接使用npx serve在根路径下启动服务时,应用尝试从/background/路径加载资源,但实际资源在根路径下,导致加载失败。

解决方案

我们将vue.config.js文件修改为使用相对路径:

1
2
3
4
5
const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true,
publicPath: './', // 修改为相对路径
});

然后重新打包项目:

1
npm run build

再使用 serve 启动:

1
npx serve -s dist

此时页面就能正常显示了。

问题二:部署到服务器后刷新页面白屏

问题现象

将项目部署到服务器后,首页可以正常访问,路由跳转也正常。但是一旦刷新页面,就会出现白屏现象。

问题分析

这个问题是典型的 Vue Router 在 HTML5 History 模式下的路由问题。我们的路由配置文件router/index.js中使用了 history 模式:

1
2
3
4
5
const router = new VueRouter({
mode: 'history',
base: '/background/',
routes,
});

在 HTML5 History 模式下,URL 看起来更像正常的 URL,例如http://oursite.com/user/id。然而,这种模式需要服务器配置支持。

当你使用 History 模式时,URL 就像正常的 URL,但问题是当用户直接访问这个 URL(比如刷新页面)时,服务器会尝试寻找对应的资源。由于这是一个单页应用,服务器上并不存在这个路径的实际文件,所以返回 404 错误或空白页面。

解决方案

我们提供了两种解决方案:

方案一:服务器配置(推荐)

如果你有服务器配置权限,可以配置服务器在找不到具体路径时返回 index.html 文件。以 Nginx 为例:

1
2
3
location /background/ {
try_files $uri $uri/ /background/index.html;
}

方案二:改为 Hash 模式(快速解决)

如果我们暂时无法修改服务器配置,可以将路由模式改为 hash 模式:

1
2
3
4
5
const router = new VueRouter({
mode: 'hash', // 改为hash模式
base: '/background/',
routes,
});

同时也要修改 resetRouter 函数中的配置:

1
2
3
4
5
6
7
export const resetRouter = () => {
router.matcher = new VueRouter({
mode: 'hash', // 改为hash模式
base: '/background/',
routes,
});
};

Hash 模式的 URL 会带有#符号,例如http://oursite.com/#/user/id。这种方式不需要服务器配置,因为#后面的内容不会发送到服务器。

总结

通过这次问题排查和解决,我们学到了几个重要的知识点:

  1. publicPath 配置的重要性:它决定了打包后静态资源的引用路径,需要根据实际部署情况进行配置。

  2. Vue Router 模式的选择

    • History 模式:URL 美观,但需要服务器配置支持
    • Hash 模式:兼容性好,无需服务器配置,但 URL 带有#
  3. 服务器部署注意事项:使用 History 模式时必须配置服务器,使其在找不到具体路径时返回 index.html 文件。

  4. 调试技巧:遇到空白页面问题时,首先要检查控制台错误信息,然后查看网络面板中资源加载情况,最后检查打包后的文件内容。

希望这篇记录能帮助到遇到类似问题的开发者朋友们。在实际项目中,我们需要根据具体情况选择合适的解决方案,既要考虑技术实现,也要考虑运维成本。