76 lines
18 KiB
JavaScript
76 lines
18 KiB
JavaScript
import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.B-QBKwc1.js";const A=JSON.parse('{"title":"前端部署","description":"本节说明前端项目的构建与部署流程,包括构建命令、Nginx 配置、Gzip 压缩和部署步骤。","frontmatter":{},"headers":[],"relativePath":"zh/deploy/frontend.md","filePath":"zh/deploy/frontend.md"}'),t={name:"zh/deploy/frontend.md"};function p(h,s,e,k,d,r){return a(),n("div",null,[...s[0]||(s[0]=[l(`<h1 id="_11-5-前端部署" tabindex="-1">11.5 前端部署 <a class="header-anchor" href="#_11-5-前端部署" aria-label="Permalink to "11.5 前端部署""></a></h1><div class="tip custom-block"><p class="custom-block-title">概述</p><p>本节说明前端项目的构建与部署流程,包括构建命令、Nginx 配置、Gzip 压缩和部署步骤。适用于将前端静态资源部署到 Nginx 服务器。</p></div><h2 id="前置要求" tabindex="-1">前置要求 <a class="header-anchor" href="#前置要求" aria-label="Permalink to "前置要求""></a></h2><table tabindex="0"><thead><tr><th>依赖</th><th>版本要求</th><th>说明</th></tr></thead><tbody><tr><td>Node.js</td><td>>= 18.0</td><td>JavaScript 运行时</td></tr><tr><td>pnpm</td><td>>= 8.0</td><td>包管理工具</td></tr><tr><td>Nginx</td><td>>= 1.20</td><td>Web 服务器</td></tr></tbody></table><h2 id="构建" tabindex="-1">构建 <a class="header-anchor" href="#构建" aria-label="Permalink to "构建""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 进入前端项目目录</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">cd</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 安装项目依赖(从 pnpm-lock.yaml 精确安装,确保版本一致)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">pnpm</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> install</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 执行生产环境构建(Vite 会压缩代码、Tree-shaking、分包)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">pnpm</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> build</span></span></code></pre></div><p>构建产物在 <code>ui/dist/</code> 目录。</p><h3 id="环境变量配置" tabindex="-1">环境变量配置 <a class="header-anchor" href="#环境变量配置" aria-label="Permalink to "环境变量配置""></a></h3><p>构建前可修改环境变量:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># .env.production — 生产环境构建配置</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#B07D48;">VITE_GLOB_API_URL</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">/api</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # API 基础路径(Nginx 代理到后端)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#B07D48;">VITE_GLOB_API_URL_PREFIX</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # API 路径前缀(一般留空)</span></span></code></pre></div><h2 id="Nginx-配置" tabindex="-1">Nginx 配置 <a class="header-anchor" href="#Nginx-配置" aria-label="Permalink to "Nginx 配置""></a></h2><div class="language-nginx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># Nginx 站点配置 — Vue3 前端 SPA</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 用途:托管前端静态资源,API 请求反向代理到后端</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 配置路径:/etc/nginx/sites-available/rxthinkcmf-admin</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">server</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 监听 80 端口(生产环境建议改为 443 + SSL)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> listen </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">80</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 绑定域名(替换为实际域名)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> server_name </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">admin.example.com</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 前端构建产物目录(pnpm build 输出)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> root </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/www/admin/dist</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> index </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">index.html</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # Vue Router History 模式</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # SPA 路由在浏览器端处理,Nginx 需要将所有非文件请求回退到 index.html</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 例:访问 /user/list → 实际由 Vue Router 在浏览器端渲染</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # try_files 依次尝试:$uri(真实文件)→ $uri/(目录)→ /index.html(回退)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> location</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;"> / </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> try_files </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">uri</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">uri</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/ /index.html</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 静态资源缓存</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # Vite 构建的文件名包含 content hash(如 app.a1b2c3.js),</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 文件内容变化 → 文件名变化 → 浏览器自动请求新文件</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 因此可以放心设置长期缓存(30 天)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> location</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ~*</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;"> \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> expires </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">30d</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> add_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">Cache-Control </span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">"public, immutable"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # API 反向代理</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # -----------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 将 /api/ 开头的请求转发到后端 ThinkPHP 服务</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # proxy_pass 末尾的 / 表示替换匹配的路径前缀</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> location</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;"> /api/ </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_pass </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">http://127.0.0.1:8000</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 后端服务地址</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_set_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">Host </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">host</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 传递原始 Host 头</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> proxy_set_header </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">X-Real-IP </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">remote_addr</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 传递客户端真实 IP</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> }</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">}</span></span></code></pre></div><h2 id="部署步骤" tabindex="-1">部署步骤 <a class="header-anchor" href="#部署步骤" aria-label="Permalink to "部署步骤""></a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 第 1 步:构建前端项目</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">cd</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> pnpm</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> install</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> pnpm</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> build</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装依赖并执行生产构建</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 第 2 步:将构建产物复制到 Nginx 站点目录</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -r → 递归复制目录</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># dist/* → 构建产物(HTML、JS、CSS、图片等)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">cp</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -r</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> dist/</span><span style="--shiki-dark:#BF9EEE;--shiki-dark-font-style:italic;--shiki-light:#A65E2B;--shiki-light-font-style:inherit;">*</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /www/admin/dist/</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 第 3 步:重载 Nginx 配置(不中断服务)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># reload → 优雅重载(不断开现有连接)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 与 restart 的区别:restart 会断开所有连接,reload 不会</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">nginx</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -s</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> reload</span></span></code></pre></div><h2 id="常见问题" tabindex="-1">常见问题 <a class="header-anchor" href="#常见问题" aria-label="Permalink to "常见问题""></a></h2><table tabindex="0"><thead><tr><th>问题</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td>刷新 404</td><td>Nginx 未配置 try_files</td><td>添加 <code>try_files $uri $uri/ /index.html</code></td></tr><tr><td>API 404</td><td>代理配置错误</td><td>检查 <code>proxy_pass</code> 地址</td></tr><tr><td>静态资源 404</td><td>路径错误</td><td>检查 <code>root</code> 路径是否正确</td></tr><tr><td>白屏</td><td>构建失败或路径错误</td><td>检查构建日志和 Nginx 错误日志</td></tr><tr><td>样式错乱</td><td>字体文件加载失败</td><td>检查字体文件路径和 CORS 配置</td></tr></tbody></table><h2 id="相关文档" tabindex="-1">相关文档 <a class="header-anchor" href="#相关文档" aria-label="Permalink to "相关文档""></a></h2><ul><li><a href="/zh/deploy/backend.html">后端部署</a></li><li><a href="/zh/deploy/docker.html">Docker 生产部署</a></li><li><a href="/zh/frontend/env-config.html">环境与构建配置</a></li></ul>`,18)])])}const c=i(t,[["render",p]]);export{A as __pageData,c as default};
|