打包后地图资源 404?publicPath 与静态路径排查

TL;DR:Vue3 + Vite 项目本地 npm run dev 一切正常、build 后部署到 GitHub Pages / Gitee Pages / Nginx 子路径就地图白屏、资源 404------先看 Network 里 404 的 URL 缺没缺子路径前缀,缺了就是 base 与静态路径问题。排查顺序和正确写法见下,文末 Demo 可一键切换错误 / 正确两种状态。

上个月交付一个水利一张图,本地跑得好好的,推到客户内网 Nginx 的 /gis/ 子路径下,打开直接白屏。F12 一看,/assets/index-xxx.js 全部 404------ 资源引用写死在根路径,部署到子路径当然找不到。

这种坑的典型特征就是本地测不出来、一部署就炸,而且 404 的不是业务代码,是打包产物的资源引用。这篇把排查顺序和根治写法一次讲清,本机 Chrome 实测,2026-10。

先看 404 的 URL 长什么样

打开 F12 Network,过滤 404,盯着失败的请求看两秒:

  • https://host/gis/assets/index-xxx.js → 带上了子路径,问题在资源本身不存在或路径写错;

  • https://host/assets/index-xxx.js → 缺了 /gis/ 前缀,就是 base / 静态路径问题,直接往下走。

这一步决定了排查方向,别一上来就翻配置文件。90% 的 "部署后白屏" 是第二种形态。

Vite 默认 base: '/',产物引用写死根路径

Vite 默认把资源引用写成绝对根路径,build 后打开 dist/index.html 能看到:

javascript 复制代码
<script type="module" src="/assets/index-BCH-ek3h.js"></script>

部署到 https://host/gis/ 后,浏览器按规则把 /assets/... 拼成 https://host/assets/...------ 子路径 gis 被丢掉了,404。这不是你代码的问题,是构建配置没适配部署位置。

正确做法,二选一:

typescript 复制代码
`vite.config.ts`
export default defineConfig({
  // 方案一:相对路径,任何子路径都能部署
  base: './',
})
typescript 复制代码
`vite.config.ts`
// 方案二:明确指定部署子路径(部署位置固定时更稳)
export default defineConfig({
  base: '/gis/',
})

base: './' 会把产物引用改成相对路径(./assets/index-xxx.js),相对 index.html 所在目录解析,部署到哪层子路径都不会丢。这个 demo 工程就是用 hash 路由 + 相对 base 部署的,Gitee Pages 的 /仓库名/ 子路径下直接能跑。

代码里写死的根绝对路径,grep 一下就有数

base 改完了,再 grep 一下源码里有没有手写根路径:

bash 复制代码
grep -rn "src=\"/" src/        # 模板里的图片资源
grep -rn "new URL('/" src/     # 动态 URL
grep -rn "fetch('/" src/       # 接口 / 静态文件请求

常见三处:<img src="/assets/xxx">、fetch('/api/...')、new URL('/xxx', import.meta.url)。这些路径不受 base 影响,部署到子路径后照样 404。地图相关的静态资源(瓦片、GeoJSON、模型)要用构建期变量拼:

vue 复制代码
<script setup lang="ts">
// BASE_URL 由 base 配置注入,部署到 /gis/ 时它是 '/gis/'
const tileUrl = import.meta.env.BASE_URL + 'data/tiles/{z}/{x}/{y}.png'
</script>

<template>
  <img :src="import.meta.env.BASE_URL + 'img/底图示意.png'" alt="底图资源" />
</template>

BASE_URL 是 Vite 构建时注入的部署根路径变量,跟着 base 走 ------base 是 /gis/ 它就是 /gis/,base 是 ./ 它就是相对值。所有 "会变成 URL 的静态资源" 统一走它,不再手写。

public 目录资源没拼前缀

public/ 下的文件会原样拷进 dist/ 根目录。很多人写 <img src="/logo.png"> 本地没事,部署到子路径一样 404。public 资源的引用规则是:

javascript 复制代码
<!-- 错误:手写根路径 -->
<img src="/img/logo.png" />

<!-- 正确:BASE_URL + public 相对路径 -->
<img :src="import.meta.env.BASE_URL + 'img/logo.png'" />

demo 里我模拟了完整场景:资源放在 public/docs/assets/(相当于部署在 /docs/ 子路径),错误写法请求 /assets/w5-tile.png(缺前缀,加载失败),正确写法请求 /docs/assets/w5-tile.png(命中,正常显示)------ 按钮一键切换,打开就能对比。

隐藏坑:本地 dev 的 SPA fallback 会掩盖 404

这是最容易误判的一环。本地 npm run dev 时,Vite dev server 对未命中的路径会返回 index.html(SPA fallback)------ 你写错路径,浏览器拿到的不是 404,而是一段 HTML。图片拿到 HTML 会解码失败照样裂开,JS 引用拿到 HTML 照样白屏,但 Network 面板里看不到 404,看着像 "资源在但没用上",把排查方向带偏。

所以验证要绕开 dev:

  1. npm run build 后,直接在 dist/ 里双击 index.html 看效果(相对 base 时本地文件协议也能跑);

  2. 或者 npm run preview,它就是模拟生产环境的产物服务;

  3. 部署后再看一次 Network,这时候的 404 才是真的。

另外提醒一句:只改 base 不够。base 只管构建产物的引用,你代码里手写的绝对路径 (原因二)和 public 资源引用(原因三)都得跟着改,缺一个都会在部署环境露出 404。改完用上面的 grep 三连过一遍最省事。

小结

按这个清单过一遍,部署后资源 404 基本能一次修完:

  1. Network 里看 404 URL 缺没缺子路径前缀 → 判定是不是 base 问题;

  2. vite.config.ts 配 base: './' 或具体子路径;

  3. grep 源码里写死的 /assets、/img、fetch('/,改用 import.meta.env.BASE_URL 拼接;

  4. public 资源引用同样走 BASE_URL;

  5. 别在 dev 里验证,用 dist 双击或 preview 复现真实部署行为。

路径这关过了,再遇到白屏就回到渲染本身去查 ------ 容器、初始化时机、底图源,那是另一条线。

📦 Demo 见 jgwx-notes-code 工程 /vite-asset-404 路由(npm run dev 后浏览器直接打开,错误 / 正确一键切换即可复现)。

相关推荐
super_Omni8 小时前
MobileNetV3-small
前端框架
瓦瓦gogo9 小时前
实习中接触前端开发后,我开始了解 React
前端·react.js·前端框架
GISBox1 天前
倾斜摄影Web端落地全攻略:从OSGB格式到3DTiles的完整转换路径
gis·格式转换·倾斜摄影·3dtiles·osgb·gisbox·顶点压缩
GMapNET1 天前
WGS-84 / GCJ-02 / BD-09 到底差多少?实测 12 个城市偏移量,附完整转换代码
gis
某人辛木1 天前
Web前端框架应用(三)路由
前端·javascript·前端框架
总要学点什么2 天前
第79篇:数据可视化-模拟迁徙效果——把三十条航线画成会飞的弧
3d·信息可视化·数据挖掘·数据分析·gis·webgl·cesium
进击的丸子2 天前
APP 人脸识别增值版 SDK:Camera2 无缝接入指南
前端·前端框架·代码规范
空中湖3 天前
用 React 写数据大屏:为什么我不建议用图表库
前端·react.js·前端框架
vjmap3 天前
WebGIS + AI 智能体:唯杰地图智能体平台一句话处理 CAD 图纸,支持 MCP 接入 AI 编辑器
gis·agent·mcp