尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vue项目WebStorm打包到Nginx部署:环境配置、发布流程与404白屏排查

Vue项目WebStorm打包到Nginx部署:环境配置、发布流程与404白屏排查 工作里接手过不少前端项目也见过太多人卡在“本地跑得好好的一打包部署就各种幺蛾子”这一步。Vue项目从WebStorm里跑起来只是开始真正考验人的是把dist目录里的静态文件扔到服务器上让它能在线上稳定访问。这篇东西我不讲虚的就按我实际操作的路径来从WebStorm打包前的环境检查到打包命令执行再到服务器上的Nginx配置和发布最后是部署后最常见的404、白屏、静态资源加载不出来这些问题的排查思路。适合刚接触部署的新手也适合那些部署过两三次但还没形成完整套路的朋友。1. 打包前的准备工作与思路梳理1.1 先看清楚你手里的是哪套Vue工程很多人上来就敲npm run build连自己项目基于Vue 2还是Vue 3、用的是webpack还是Vite都没搞清楚。这两个版本在打包逻辑上差别不小尤其影响后面的部署配置。如果你打开项目根目录看到的是webpack.config.js或者build目录下有一堆webpack相关的配置那基本是Vue 2 webpack的组合使用vue-cli-service build来打包。如果是Vue 3项目大概率用的是Vite配置文件是vite.config.js打包命令是vite build。这两种工具产出的静态文件都放在dist目录下但内部的资源引用方式、环境变量处理机制完全不同。还有一种情况是项目里同时存在package.json、yarn.lock、pnpm-lock.yaml这种情况要留意包管理器版本。我遇到过用npm装完依赖后打包总是报错换成项目自带的pnpm或者yarn才恢复正常因为lock文件锁定的依赖版本跟npm解析出来的不完全一致。在WebStorm里打包前先看一眼package.json里的scripts部分确认build命令是什么再决定后续操作。1.2 环境变量打包前必须确认的头等大事环境变量是打包阶段最容易埋雷的地方。开发环境请求的接口地址通常走代理转发到localhost:8080但线上部署之后前端请求的接口域名、路径前缀都变了。如果代码里直接写死了/api这种相对路径或者把开发环境的完整地址硬编码进去打包出来的东西在线上基本就是废的。Vue 2 webpack的项目里环境变量通过.env、.env.development、.env.production这些文件来管理在代码里用process.env.VUE_APP_API_BASE这样的变量名读取。Vue 3 Vite的项目则用import.meta.env.VITE_API_BASE_URL。打包前必须逐个检查这些配置文件确认线上环境的接口地址、CDN路径、路由base路径都是对的。# Vue 2 / webpack 项目示例 .env.production NODE_ENVproduction VUE_APP_API_BASE/api VUE_APP_CDN_URLhttps://cdn.example.com// Vue 3 / Vite 项目示例 env.d.ts 里的环境变量声明 interface ImportMetaEnv { readonly VITE_API_BASE: string readonly VITE_CDN_URL: string }我见过最坑的一个项目团队把测试环境的IP地址直接写死在.env.production里结果打包前忘了改上线之后所有接口请求都发到内网IP用户自然是白屏加报错。所以每次打包前第一件事就是把.env.production这类文件打开逐行确认环境变量对应的目标环境。1.3 WebStorm里检查项目状态的三个动作进入WebStorm后建议先做三件事。第一打开Terminal面板运行node -v和npm -v确认Node版本满足项目要求。Vite 4及以上版本对Node版本有要求通常是14.18或者16版本太低会直接报错。第二查看package.json里的engines字段有些项目强制约束了Node版本范围。第三确认依赖已完整安装node_modules目录存在且完整。WebStorm有时会提示依赖缺失这时候别急着打包先把依赖装好再说。打包前可以用WebStorm的npm工具窗口双击build脚本直接触发打包也可以在Terminal里手动执行命令。两种方式本质一样但通过工具窗口的好处是会把输出信息规整地展示在Run面板里方便排查报错。2. 用WebStorm把项目真正打成可部署产物2.1 打包命令的选择与执行细节假设你的项目package.json里的scripts是这样写的{ scripts: { dev: vue-cli-service serve, build:prod: vue-cli-service build --mode production } }那么在WebStorm的Terminal面板里执行npm run build:prod或者在npm工具窗口双击build:prod脚本即可。这里有个细节值得注意--mode production指定了构建模式webpack会读取对应的.env.production文件。如果你的项目里同时有build:test、build:prod这类多环境脚本打包时务必选对命令别把测试环境的包发到生产服务器上。Vite项目稍有不同执行npm run build时会自动加载.env.production文件。如果遇到打包速度极慢的情况可以考虑在vite.config.js里通过build.chunkSizeWarningLimit调整警告阈值但首次打包还是建议保持默认配置避免为了消警告而引入不必要的插件。执行打包后控制台会出现大量日志。重点关注以下几点Build complete字样说明打包成功warning级别的提示一般不影响使用但如果是error直接标红的就需要停下来排查了。另外打包结束时通常会显示产物的体积信息比如dist目录下各个chunk的大小如果某个单文件超过1MB就要考虑后续做代码分割了。2.2 打包产物dist目录里到底有什么打包成功后在项目根目录下会生成dist文件夹这就是需要部署到服务器的全部内容。一个典型的Vue 3 Vite项目dist目录结构大概长这样dist/ ├── index.html ├── favicon.ico ├── assets/ │ ├── index-7f2a3d91.css │ ├── index-7f2a3d91.js │ ├── vendor-9c1b2e44.js │ └── logo.png └── (如果有public目录下的其他静态资源也会原样搬运过来)index.html是入口页面assets目录下带哈希值的JS和CSS文件是构建产物。哈希值的意义在于版本管理每次内容变化后文件名都会变部署时浏览器会请求新文件而不会命中旧缓存这样就省去了手动清缓存的操作。检查产物是否正确有几个小技巧。用文本编辑器打开index.html看看内部引用的script和link标签路径是什么。如果引用路径以/开头说明部署时资源会被解析到域名根路径下那么Nginx的root配置就要指向dist目录本身如果引用路径带着./前缀说明即使部署到子路径下也能正常加载。很多部署事故都是这里路径写错了比如配了子路径部署但资源路径是绝对的/assets/xxx.js结果全部404。2.3 打包报错的常见套路与解法打包报错是家常便饭新手容易慌老手看报错关键字就能猜到方向。最常见的几类第一类是内存溢出报错信息里通常有JS heap out of memory字样。Vue项目打包需要内存较大尤其是大型项目。解决办法是给Node进程加大内存限制# 方式一直接在命令里指定 node --max_old_space_size4096 node_modules/vue/cli-service/bin/vue-cli-service build # 方式二修改 package.json 脚本 build:prod: node --max_old_space_size8192 node_modules/vue/cli-service/bin/vue-cli-service build --mode production第二类是各种模块解析错误比如Module not found: Error: Cant resolve xxx。这类问题通常是依赖不完整或者某个包的版本不兼容导致的。先执行npm install重装依赖如果还不行就删掉node_modules和package-lock.json重新完整安装一遍绝大多数问题都能解决。第三类是语法报错在WebStorm的Run面板里会直接显示具体文件和行号。这种问题属于源码层面的不是打包工具的问题。最常见的场景是使用了低版本浏览器不支持的语法特性需要确认browserslist配置是否合理。提示如果项目是CI/CD自动构建不要忽略WebStorm本地打包和服务器打包的差异。本地装了一堆全局工具服务器上是干净环境可能会出现本地能打包、服务器上失败的情况。最好的办法是在服务器上严格安装项目package.json里声明的依赖版本。3. 服务器端环境的准备与部署实施3.1 部署方式对比该用Nginx还是Node服务Vue项目打包后是纯静态文件理论上任何能托管静态资源的服务器软件都能部署。实际生产环境里绝大多数团队选择Nginx原因很简单性能好、配置灵活、天然支持反向代理和静态文件服务。也有团队把dist目录交给Node服务托管比如用Express或者Koa写一个静态资源中间件再配合history模式的路由重写。这种做法在某些全栈项目里有用但如果你想省心省力直接上Nginx是王道。我的建议是只要能独立装Nginx就优先用Nginx不要在后端服务里掺杂静态文件逻辑。Nginx的安装不复杂。Ubuntu系统上执行sudo apt install nginx就能装好CentOS系统用sudo yum install nginx。装好后通过sudo systemctl status nginx查看服务状态能看到active (running)说明已经起来了。默认情况下Nginx会监听80端口你可以先试试访问服务器的IP地址如果看到Nginx欢迎页说明环境OK。3.2 Nginx配置精讲静态文件、路由重写、接口代理一次配齐部署Vue项目的Nginx配置核心就是三件事托管静态文件、处理前端路由、代理后端接口。一封典型配置如下server { listen 80; server_name your-domain.com; # 开启gzip压缩传输体积 gzip on; gzip_min_length 1k; gzip_types text/plain text/css application/javascript application/json; # 静态资源根目录指向你的 dist 目录 root /var/www/vue-app/dist; index index.html; # 核心配置所有前端路由都回退到 index.html location / { try_files $uri $uri/ /index.html; } # 静态资源缓存策略 location /assets/ { expires 30d; add_header Cache-Control public, no-transform; } # 接口代理转发到后端服务 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这里最核心的try_files $uri $uri/ /index.html;解决了前端路由的history模式问题。没有这一行当你访问/user/123这类路由时Nginx会去磁盘上找/user/123这个文件找不到就返回404。加了这行之后Nginx发现文件不存在就回退到index.html由前端路由接管URL解析页面就不会白屏了。这个配置是所有Vue项目部署的标配一定要写对。proxy_pass代理后端接口是为了解决跨域和生产环境接口地址不一致的问题。前端请求/api/loginNginx把请求转发到http://127.0.0.1:8080对应的后端服务上。注意proxy_pass后面的URL是否带路径这会影响实际转发的路由拼接建议先了解清楚再写。另外如果你部署的是HTTPS站点需要额外配置SSL证书server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/your-domain.com.pem; ssl_certificate_key /etc/nginx/ssl/your-domain.com.key; # 其他配置与HTTP一致 }3.3 文件上传与发布操作流程配置写好之后接下来就是把打包好的dist目录传到服务器上。常用的方式有scp命令和rsync命令。如果你是个人项目scp就够用了# 在本地执行把 dist 整个目录上传到服务器 scp -r ./dist useryour-server-ip:/var/www/vue-app/如果项目比较大推荐用rsync增量传输能省不少时间# 在本地执行rsync 只同步有变化的文件 rsync -avz --delete ./dist useryour-server-ip:/var/www/vue-app/上传完毕之后还需要检查目录权限。Nginx进程通常以www-data用户运行如果dist目录的权限不对会出现403或者访问不到文件的情况。最简单的办法是把目录所有者改成www-data或者直接chmod -R 755。我习惯执行sudo chown -R www-data:www-data /var/www/vue-app/一次性解决权限问题。改完Nginx配置后需要重载配置让改动生效# 检查配置语法 nginx -t # 如果显示 syntax is ok就重载配置 nginx -s reload到这里一个基础的部署流程就完成了。访问服务器IP或域名能看到页面正常加载部署成功。3.4 更新发布别每次上传整个dist目录很多新手发布新版本时是把整个dist目录拖上去覆盖。这个方式也不是不行但容易出问题本地旧文件残留、上传时间长、万一传到一半断了线上就处于半新半旧的状态。更好的办法有几种。一种是保留dist目录只把打包产物用rsync --delete同步上去--delete参数会删除服务器上存在但本地不存在的文件保证两边完全一致同时只传输变化的部分比较可靠。另一种是版本号管理每次发布前把新版本放到以时间戳命名的目录里然后Nginx的root配置指过去。想回滚时只需要改一下root指向旧的版本目录再重载Nginx就行。这个方案省心适合部署频率高的项目。我自己的习惯是保留最近两到三版的目录再多就清理掉避免磁盘被占满。4. 部署后的疑难杂症排查4.1 页面访问404或者刷新后404这个问题的根源几乎都在于try_files配置没写对或者是Nginx根目录下根本没有对应的静态文件。先到服务器上用ls确认dist目录内容完整再看index.html是否存在。如果文件都在那就是路由重写没生效把try_files $uri $uri/ /index.html;配上重载Nginx就能解决。另一个隐蔽的场景是base路径不是/。如果你打包时设置了publicPath: ./或者base: /my-app/那么index.html里引用的资源路径就带上了前缀。此时Nginx的root配置、try_files回退逻辑都要匹配这个前缀否则就会出现“首页能进点按钮后404”的情况。排查时先看页面源码里script标签的路径再对照Nginx的配置基本就能定位。4.2 白屏但控制台没有明显报错白屏是最让人头疼的现象因为报错不一定直接出现。几个高发原因要按顺序排查。第一检查index.html里有没有内容。如果打开页面后查看源代码div idapp/div是空的JS文件没执行或者加载失败。浏览器开发者工具的Network面板里看index.js文件是否返回200。如果返回404或者500多半是静态资源路径配错了或者文件没传全。第二看JS是否报错。如果资源文件加载成功但还是白屏打开浏览器控制台如果看到类似Cannot read properties of undefined的报错说明可能是某个组件初始化失败这属于代码问题不一定和部署有关但有时候也会因为环境变量没配上导致接口挂了进而组件加载失败。第三有可能是因为BrowserRouterhistory模式下后端没配置好直接访问根路径能打开但刷新子路由时白屏。这时候按try_files的配置检查一遍就行。4.3 接口报404或者跨域错误接口问题分两种情况。一种情况是前端请求能发出去但返回404。这种多半是proxy_pass代理路径配错了。比如前端代码请求的是/api/user/list后端服务实际接收的路径是/user/list你就需要在location /api/下面去掉/api前缀再转发location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; }proxy_pass末尾加一个/会把/api/前缀去掉再转发不加/则会带上/api/原样转发。这个细节非常常见也是老手翻车最多的地方。另一种情况是浏览器报跨域错误。这种情况通常意味着前端请求没经过Nginx代理直接访问了后端地址而后端没有配置跨域头。解决办法是检查前端代码里接口的baseURL确保线上环境请求的是/api这类相对路径通过Nginx反代到后端。如果前端直接用了完整域名那就要在后端配合配置跨域了。我把排查顺序整理成表格方便对照现象可能原因排查手段刷新子路由404没有try_files回退检查Nginx配置是否包含try_files $uri $uri/ /index.html;首页白屏资源路径不对Network面板看JS/CSS请求是否404页面能开但接口404代理路径没写对确认proxy_pass末尾/是否按预期处理前缀接口跨域请求没走代理看浏览器请求的URL是否同源一直转圈不加载数据后端服务没起来在服务器上curl http://127.0.0.1:8080验证后端服务样式全乱静态资源缓存强制刷新检查缓存策略这里我还想强调一个冷门但常见的坑部署完成后首次能访问但过一段时间再访问页面变成旧的。这八成是缓存问题。index.html不要设置强缓存否则浏览器一直用旧页面。Nginx配置里对index.html关闭缓存location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; }这样每次访问都会校验index.html是否更新引用的带哈希值的静态资源文件则会命中长期缓存速度也不受影响。这个组合是性价比最高的缓存策略。4.4 打包后布局异常的特殊情况热搜词里有“vue 打包后 布局异常”这个我确实遇到过。打包后布局错乱常见的原因有两个。第一是publicPath配置不当导致某些背景图、字体文件加载失败。如果某个图片资源用的是url()方式写在CSS里打包后它会被解析成独立的静态资源文件搬运到assets目录。如果publicPath配成/而站点部署在子路径下资源路径就会错位图片加载不出来、布局自然就乱了。这种情况下把publicPath改成相对路径./通常能解决但要注意改成相对路径后路由的history模式会变得比较难处理需要整体权衡。第二是第三方UI库的样式失效。这种情况多半是因为打包后CSS文件被压缩或者改名而某个组件依赖的样式选择器权重不对。比如Element UI和自定义样式混用时打包后样式覆盖顺序可能变化需要检查样式的加载顺序必要时在main.js里调整引入顺序。注意如果用了按需引入UI库比如babel-plugin-import确认style配置在打包模式下是否正确。有时候开发环境没问题是因为开发服务器的transform过程和webpack解析顺序不一样打包后才会暴露出样式缺失问题。5. 部署后还能做的几件加分事5.1 用Nginx把gzip和缓存一起搞定前面配置里已经写了gzip的基础设置。这里再补充一个细节gzip除了能压缩HTML、CSS、JS对JSON接口数据也有效。如果你的接口走Nginx代理可以在location /api/里加一句gzip_proxied any;允许代理响应也参与压缩location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; gzip_proxied any; }静态资源的缓存策略建议区分对待。带哈希值的文件assets目录下的可以设置长时间的缓存比如30d或者max。不带哈希值的index.html不能缓存或者说只能设置no-cache。这样配置之后用户重新访问时只会获取一个新的index.html内容变化了就会加载新的带哈希值的JS/CSS老文件自然被替换。这个方案实测对性能优化效果非常显著尤其是页面体积较大的项目首屏加载时间能降低30%左右。5.2 多环境下的一键部署思路如果你维护多个环境测试、预发布、生产建议在package.json里把不同环境的打包脚本分开命名比如build:test、build:staging、build:prod各自加载对应的环境变量文件。发布时先用一个简单的shell脚本把打包和上传绑定在一起#!/bin/bash # deploy.sh npm run build:prod scp -r ./dist/* userserver:/var/www/vue-app/ ssh userserver sudo nginx -t sudo nginx -s reload这个脚本简单粗暴适合个人项目或小团队。大团队建议用流水线工具比如Jenkins或GitHub Actions但思路是一样的构建阶段产出的dist目录就是部署的输入物后续服务器上只要拉取产物然后重载Nginx即可。5.3 别忘了服务器上的日志和监控部署不等于万事大吉。Nginx的访问日志和错误日志是排查问题的第一手资料。Ubuntu上日志默认在/var/log/nginx/access.log和/var/log/nginx/error.log。当用户反馈页面异常时先去看这两份日志往往能直接看到问题所在。Shell里用这个命令实时跟踪错误日志tail -f /var/log/nginx/error.log同时建议观察磁盘空间日志文件长时间不清理会长得很快我之前遇到过一次服务器磁盘被Nginx日志占满导致服务异常的事故。解决办法就是配置logrotate定期切割和清理日志这个属于服务器运维基本功。5.4 回滚预案一定要有发布最怕的不是发布失败而是发现问题后不知道怎么快速回滚。如果用的是上一个版本目录的方式部署回滚就很简单把Nginx的root指回上一个目录nginx -s reload一分钟内完成回滚。如果直接用rsync --delete覆盖式发布回滚就比较麻烦最好在发布前先备份一份当前目录# 发布前备份当前版本 cp -r /var/www/vue-app /var/www/vue-app-backup-$(date %Y%m%d)这样即使发布出问题也能用备份目录顶回去。回滚预案平时看着多余真正遇到线上事故的时候能救你一命建议所有项目都保留这个习惯。根据我踩过这么多次坑的经验部署工作最重要的一步不是后面那些花哨的优化而是打包前老老实实确认环境变量、无误后一次性把dist产物和Nginx配置对清楚。这个基础打牢了后续不管是加CDN、做HTTPS还是上高可用集群都不会太费劲。实际上我自己现在接手一个新项目第一件事就是先把这个流程跑通让页面先能在线上看到再说其他。好记忆不如烂笔头你在这条路上踩过的每一个坑攒成自己的部署检查清单之后后面就是一条平路。
返回列表