
1. 项目概述与方案选型1.1 这次要完成什么你在 WebStorm 里写了一个 Vue 项目本地跑npm run dev一切正常但总不能把开发服务器永久开在自己电脑上给别人访问。所以要做两件事第一用 WebStorm 把 Vue 源码打包成浏览器可以直接运行的静态文件dist 目录第二把这堆静态文件上传到服务器再用 Nginx 托管起来让用户通过域名或 IP 访问到你的页面。整体流程不复杂核心链路就一条源码 - WebStorm 执行 npm 脚本 - 生成 dist 目录 - 上传服务器 - Nginx 指向 dist - 浏览器访问成功。但这条链路上每一步都有可踩的坑尤其是 Vue 路由用了 history 模式、接口地址写死、静态资源用了绝对路径这几种情况打包出来看着是好的部署上去全白屏新手很容易在这上面卡一整天。1.2 为什么用 WebStorm 来操作很多人觉得打包就是敲npm run build用不用 IDE 无所谓。但 WebStorm 在工程管理上的优势非常明显。它对 Vue 语法、TS 类型、ESLint 的校验是开箱即用的写代码的时候就能拦截掉不少低级错误。真正到了打包环节WebStorm 内置的 npm 工具窗口可以直接可视化运行 package.json 里的脚本点一下运行控制台输出和你敲 CLI 完全一样还能保存运行配置下次一键重跑。对于不常接触命令行的前端同学来说WebStorm 提供的这个图形化入口非常友好。你不需要记npm run build还是npm run prod在 npm 工具窗口能直接看到所有脚本名。我建议你不管用什么工具都把 WebStorm 的 npm 窗口用熟练因为后面跑测试、检查 lint、生成构建报告都用得上。1.3 部署方案怎么选Vue 打包产物的本质是静态文件所以部署方案灵活度很高。主流有以下几种最简单的做法把 dist 里的文件通过 scp、rsync 或 FTP 传到服务器然后包一层 Nginx 静态站进阶一点把 dist 提交到 Git 仓库服务器上拉代码再拷贝到 web 目录再往上走配置 CI/CD 流水线push 代码后自动构建、自动发布。标题既然点名“部署到服务器”我就以手动部署为主线因为手动部署一次能让你把整个链路彻底摸透。了解底层逻辑之后你再看 CI/CD 的配置会轻松很多。服务器这边默认用 Linux Nginx这是目前 Vue 项目最主流的托管方式静态文件解析效率高配置也简单。1.4 这篇内容适合谁看适合刚接触 Vue 项目、第一次准备把自己写的页面挂到公网服务器上的开发者。也适合那些本地能跑起来、一到服务器就白屏的倒霉蛋。内容从环境准备开始讲一直说到排查问题不挑操作系统Windows 和 macOS 都通用只要别把命令里的路径照抄错。2. 环境准备与 WebStorm 配置2.1 Node.js 环境必须对齐版本打包 Vue 项目第一步是确认 Node.js 版本。WebStorm 本身不负责编译 JS它只是把你的命令转交给 Node.js 环境去执行所以 Node 版本错了后面全是白忙活。Vue CLI 创建的老项目vue.config.js 那套一般要求 Node 12 以上Vite 创建的新项目vite.config.js 那套要求 Node 16 甚至 18 以上。你在终端里先执行node -v和npm -v看一下版本。如果版本太老建议直接去官网下载 LTS 版本装最新稳定版。装完 Node.js 之后WebStorm 需要知道你用的是哪个 Node 解释器。注意如果你电脑上装了多个 Node 版本比如 nvm 管理一定要在 WebStorm 里指定同一个解释器否则命令行能跑WebStorm 里报找不到 Node非常容易踩。打开 WebStorm 的Settings | Languages Frameworks | Node.js把 Node interpreter 选到你的 node 可执行文件路径。npm 那一栏会自动识别。2.2 WebStorm 里跑 npm 命令的三种方式第一种打开项目里的 package.json你会在文件右侧看到一个绿色的运行箭头或者一个写着 npm 的小面板直接点脚本名称即可执行。第二种点击底部工具窗口的Terminal在这里敲命令。这个方式和在系统终端里敲命令完全一样而且它自动继承了当前项目的环境变量我平时用这种方式更多。第三种通过Settings | Tools | Tasks | npm添加运行配置。这种方式适合自定义命令比如npm run build -- --modeproduction可以把固定参数存成一个运行配置下次直接点运行。三种方式没有高下之分我个人的习惯是日常调试用 Terminal打包和发版用 WebStorm 的 npm 配置因为配置可以命名部署构建、测试构建下次一眼就能认出是哪个环境。2.3 推荐的项目结构接手的 Vue 项目无论用 Vue CLI 还是 Vite都需要确认几个关键目录和文件是否存在。一个标准的项目通常包含package.json项目依赖和脚本入口node_modules依赖包目录一般由npm install生成public/或static/静态资源目录打包时会原样拷贝到 distsrc/源码目录vue.config.js或vite.config.js构建配置入口。如果你拿到的是一个空目录只需要在 WebStorm 的 Terminal 里执行npm create vuelatest或按照官方文档初始化项目即可。这里不展开脚手架细节但要注意用 WebStorm 打开项目时最好让 IDE 索引完成再操作否则脚本窗口可能显示空白。2.4 初始化构建脚本检查在 WebStorm 底部 npm 工具窗口里展开 scripts正常情况下能看到serve、build、lint、preview之类的脚本。打包请认准build脚本一般是vue-cli-service build或者vite build。先运行一次npm install确保依赖齐全。Windows 上如果出现node-sass或者python相关的编译报错说明项目的原生依赖比较老可以直接在 Terminal 里执行npm install --force或者npm install --legacy-peer-deps碰碰运气。Linux 服务器上也一样。3. 打包环节的关键细节3.1 一次完整构建过程发生了什么执行npm run build之后WebStorm 会把命令交给 npmnpm 再调用构建工具将 Vue 的 SFC单文件组件编译成普通的 HTML、CSS、JavaScript。Vue CLI 底层走 webpack会先解析入口文件接着递归读取所有 import 依赖通过 loader 处理 vue、js、css、图片等资源最后做代码合并、压缩、资源指纹生成输出到 dist 目录。Vite 的思路不太一样它开发时用原生 ESM快得离谱构建时则用 Rollup 完成打包同样生成 dist。不管底层用哪个最终产物都是浏览器能直接识别的静态文件不需要后端在运行时做任何编译。这也是 Vue 项目能部署到任意静态服务器上的原因。3.2 打包前必须确认的几个配置这是打包环节最影响成败的部分。我见过太多人本地npm run dev是好的build 完部署上去就白屏原因基本都出在下面几点。第一publicPath 或 base 配置。Vue CLI 项目里vue.config.js中的publicPath默认是/意思是打包后的 JS、CSS 资源路径会写成/js/app.js。如果你的网站部署在域名根路径没问题如果部署在子路径比如http://server:8080/myapp/资源路径就会变成/js/app.js请求打到根路径去自然 404 白屏。解决办法很简单// vue.config.js module.exports { publicPath: ./ }Vite 项目对应的是base配置// vite.config.js export default { base: ./ }设成相对路径后资源加载会基于当前页面路径来找安全性更高子目录部署和根路径部署都能跑。第二路由模式。Vue Router 默认是 hash 模式URL 长这样http://server/#/home部署最省心。如果为了好看改成 history 模式URL 变成http://server/home服务器没有做 try_files 重写的话刷新一下就是 404。这个坑我在下一章配置 Nginx 时会详细讲反正打包前先确认自己项目路由用的是哪个模式。第三接口地址。项目里写的axios请求地址如果是http://localhost:8080/api打包后还是这个地址用户浏览器拿到页面后请求的却是用户自己的 localhost。这个问题一般通过区分环境变量解决在.env.production里写VUE_APP_API_URLhttps://api.example.com代码里读process.env.VUE_APP_API_URL。Vite 项目则用import.meta.env.VITE_API_BASE。3.3 执行打包与产出检查在 WebStorm 的 npm 工具窗口里双击build或者直接在 Terminal 里npm run build构建过程会输出到控制台。构建完成后项目根目录会多一个dist文件夹。我建议构建结束后不要急着上传先在本地做一次预览。Vue CLI 项目可以执行cd dist npx serveVite 项目一般自带 preview 脚本npm run preview浏览器打开预览地址如果能正常显示页面并且没有红色报错说明这次构建的产物没问题。这一步能帮你把“代码问题”和“部署问题”隔离开后面服务器上出问题时就少一个排查方向。3.4 打包体积优化选项打包体积太大会影响首屏速度顺带说几个优化点。先查看npm run build最后输出的文件列表看看哪些 chunk 体积最大。Vue CLI 项目可以用webpack-bundle-analyzer插件辅助分析。常见优化操作是路由懒加载即在路由配置里把组件改成const Home () import(/views/Home.vue)这样首页不会一次性把全部页面代码拉下来。然后是第三方库优化比如 lodash 改成按需引入Element UI 或 Ant Design Vue 使用按需加载插件。对于小项目这些优化可以放到后期不急于第一次部署就做。4. 服务器部署实操4.1 服务器与 Nginx 环境准备部署要用的服务器建议选 Linux 系统Ubuntu 22.04 或 CentOS 7 都行。你拿到服务器后先做一件事用 SSH 连上去然后安装 Nginx。Ubuntu/Debian 系统sudo apt update sudo apt install nginxCentOS/RHEL 系统sudo yum install nginx安装完成后执行sudo systemctl status nginx看到 activerunning就说明基础环境跑起来了。如果服务器有防火墙记得放行 80 端口sudo ufw allow 80还需要确认你买服务器的云服务商安全组策略里入方向规则是否放行了 80 端口。很多人本地 Nginx 配好了防火墙也关了外网还是打不开十有八九是云控制台的安全组没放行。4.2 把 dist 传到服务器的几种办法打包生成的 dist 目录通常在本地项目根目录下。接下来要做的就是把 dist 里的内容上传到服务器。第一种推荐先用 scp简单直接。在本地 Terminal不是 WebStorm 里的 Terminal除非你配置了 SSH执行scp -r dist/* rootyour_server_ip:/var/www/vue-app/前提是服务器上先创建好目录ssh rootyour_server_ip mkdir -p /var/www/vue-app如果你有固定域名并且想后续反复同步可以试试rsync支持增量同步传大项目时比 scp 快很多rsync -avz --delete dist/ rootyour_server_ip:/var/www/vue-app/如果想用可视化界面操作FileZilla 或者 WebStorm 自带的 FTP 部署功能都可以。WebStorm 在Tools | Deployment | Configuration里配置 SFTP设置好服务器地址、账号密码、映射目录后右键 dist 目录就能直接上传。这种方式对不熟命令行的新手最友好但要注意别把整个 dist 目录里的缓存文件传漏了。下表简单对比一下几种方式方式优点缺点适合场景scp简单一条命令全量拷贝慢一次部署rsync增量同步快命令参数稍多频繁更新FileZilla可视化需要额外软件新手入门WebStorm Deployment不离开 IDE配置映射略麻烦喜欢 IDE 操作4.3 Nginx site 配置详解文件传上去之后最关键的一步来了配置 Nginx 站点指向你的 dist 目录。在 Ubuntu/Nginx 里推荐在/etc/nginx/sites-available/下新建配置文件然后在sites-enabled里建软链接。创建一个vue-app文件sudo vim /etc/nginx/sites-available/vue-app写入如下配置server { listen 80; server_name your_domain_or_ip; root /var/www/vue-app; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这段配置里root指向你上传静态文件的路径try_files是专门为 history 路由模式准备的兜底方案。当用户访问/home这个路径时服务器发现磁盘上没有对应的home文件也不会直接返回 404而是回退到index.html由前端路由接管页面渲染。如果你用的是 hash 路由模式try_files有没有都不太影响但写上不会出错。再看/api/的proxy_pass这是提供给前端打包后接口请求的代理。如果你没有后端接口或者接口已经配置了跨域可以去掉这个 location。有了它前端代码里写/api/login请求会被 Nginx 转发到本机 8080 端口避免浏览器触发跨域拦截。启用站点配置sudo ln -s /etc/nginx/sites-available/vue-app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx执行nginx -t会检查配置语法看到syntax is ok再 reload不然配置错了会直接把 Nginx 搞挂。注意如果服务器上同时存在默认站点/etc/nginx/sites-enabled/default并且监听了同一个端口你需要把默认站点删掉或改掉否则访问时会打到默认页面而不是你的 Vue 应用。4.4 部署后的验证清单配置完成后打开浏览器输入服务器 IP 或域名正常会看到 Vue 应用的首页。第一次验证时我按下面这个顺序排查首页是否正常渲染F12 控制台有没有红色报错Network 面板里 JS、CSS 是否都加载成功状态码是不是 200刷新一个内页路由比如/home确认不会变成 404点一个需要调用接口的功能看/api请求有没有正常返回。这四条都过了这次部署就算成功了。如果某一步翻车直接跳到下一章看排查方法。5. 常见问题排查手册5.1 打包后页面白屏白屏十有八九是资源路径错误。你打开浏览器 F12看 Console 报错如果是类似Failed to load resource: the server responded with a status of 404 (Not Found)再去 Network 面板看是哪个 JS 文件 404。这时候检查打包配置publicPath或base。如果项目部署在域名根路径publicPath: /是正常的如果部署在子路径比如http://ip:8080/foo/就要设置成/foo/或相对路径./。相对路径虽然省事但有的时候会遇到 CSS 里的图片、字体路径问题。比较稳妥的做法是把 vue.config.js改为publicPath: process.env.NODE_ENV production ? /your-sub-path/ : /然后 Nginx 增加对应 location或者把站点根目录指向子路径。具体看你项目实际部署的位置。另外还要检查是不是路由 history 模式在本地 preview 没问题但在服务器上刷新 404。这种情况按 5.2 处理。5.2 路由刷新 404如果你的 URL 是http://server/home这种没有#的形式刷新一下就 404基本可以确定是 history 模式服务端没兜底。处理办法就是刚才配置里的location / { try_files $uri $uri/ /index.html; }注意这行配置必须写在location /块里如果只写在某个子路径下内页路由照样 404。如果你用的是 Apache 或者其他 Web 服务器原理一样都是把不存在的路径重写到 index.html。如果你完全不想折腾服务端也有一个省事方案把 Vue Router 改成 hash 模式。const router new VueRouter({ mode: hash, routes })Vite 项目的路由配置类似把createWebHistory改成createWebHashHistory。坏处是 URL 里多个#不够美观好处是部署难度骤降任何静态文件服务器都能直接跑不会出现刷新 404 的问题。5.3 接口连不上或跨域部署后页面能打开但数据全是空的接口请求一直报错这种情况要分几类看。第一类接口地址写死了localhost。前面说过环境变量没区分打包产物里全是http://localhost:8080用户浏览器一执行就会去请求用户自己的电脑必挂。重新配置.env.production里的请求地址然后重新打包。第二类接口域名是 https页面是 http浏览器会报混合内容拦截。要么页面也走 https要么接口降级为 http总之协议要一致。第三类跨域问题。如果接口地址和页面地址不同源浏览器会拦截。解决办法是在 Nginx 层做反向代理前端始终请求同源地址/api/xxxNginx 再把请求转发到真实后端。因此我们在 Nginx 配置里提前写好/api/的 proxy_pass就是为这个场景准备的。要注意proxy_pass http://127.0.0.1:8080;后面有没有斜杠行为有区别。带斜杠的http://127.0.0.1:8080/会去掉/api前缀不带斜杠则保留完整路径。按需选择即可。5.4 更新后还是旧页面改了代码重新 build 再上传用户浏览器还是旧页面这种问题根源在缓存。最科学的应对方案是用好文件名指纹。Vue CLI 和 Vite 打包时带 hash 的文件名规则一般是app.8f3k2c.js只要文件内容变化文件名就会变浏览器自然会请求新文件。所以你需要保证 index.html 不被强缓存。Nginx 里可以这样处理location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; } location /static/ { expires 30d; add_header Cache-Control public, immutable; }这样 HTML 每次都回源检查带 hash 的静态资源可以放心长缓存。如果你没有自定义静态资源目录而是按默认放在根路径可以根据实际目录结构调整 location。关键思路是HTML 不缓存JS/CSS 缓存。上传文件时用 rsync 的--delete参数可以清理服务器上已经不再使用的旧文件避免旧资源还在但是新代码引用了新文件名最终把服务器磁盘堆满。5.5 WebStorm 侧提示问题如果你在 WebStorm 里点 npm 脚本没反应首先检查右下角有没有显示 Node.js interpreter 未配置。到Settings | Languages Frameworks | Node.js选对 Node 路径问题马上解决。如果构建时内存溢出控制台报JavaScript heap out of memory可以在 package.json 的 build 脚本里加参数build: node --max_old_space_size4096 node_modules/vue/cli-service/bin/vue-cli-service build或者给 Vite 项目设置NODE_OPTIONS--max_old_space_size4096 npm run buildWindows 下NODE_OPTIONS写法略有差异可以搜索一下对应系统语法。6. 个人踩坑后的几点体会这套 Vue 打包部署流程我自己第一次跑通花了两天整其中一大半时间耗在白屏和跨域上。走通之后你会发现真正难的不是命令而是理解打包生成的资源路径、路由和服务器的关系。说几个后来才悟到的经验第一所有路径问题先分清“前端资源路径”和“浏览器 URL 路径”。前者由 publicPath 或 base 控制后者由 Nginx 的 root 和 try_files 控制两者不是一回事很多人搞混。第二无论用哪种 IDE打包前先在本地把 dist 用静态服务器跑一遍成本极低但能提前暴露 80% 的部署问题。省下的时间远比敲那两行命令多。第三Nginx 配置改完一定要nginx -t检查再 reload。我有一次手滑少写了一个分号整个站直接挂了云监控疯狂报警。多一条检查流程不是保守是保命。最后再说一个小技巧如果你经常需要更新部署建议花五分钟写一个简单的部署脚本把打包、上传、远程刷新三步合并成一条命令。比如在本地项目根目录放一个deploy.sh内容用 rsync 指向服务器路径配合 SSH 免密登录以后更新就一行搞定。脚本别写太复杂核心就三步npm run build、rsync -avz --delete dist/ rootserver:/var/www/vue-app/、ssh rootserver nginx -t systemctl reload nginx。第一次配好之后每一次发布都会很舒服。希望这篇把能踩的坑都写到的实战记录能帮你少走点弯路。