第7章 7.4 部署:Vercel / Netlify / Nginx
(本文是「Vue3 从入门到精通」系列第 34 章,承接上一章「7.3 Monorepo:pnpm workspace」,建议先阅读上一章再继续)
上一章我们学会了用 pnpm workspace 管理 Monorepo 项目,多个子项目可以共享依赖、互相引用,终于不用一个项目装一遍 node_modules 了。但是代码写完了,总不能一直跑在本地吧?你得把它部署到服务器上,让全世界的人都能访问你的网站。
这一章我们不写 Vue 代码,换换口味——用 Python 写一个「部署配置生成器」,帮你一键生成 Vercel、Netlify、Nginx 的配置文件。你不需要懂 Vue,也不需要装 Node,光靠这个 Python 脚本,以后每次新建项目都能自动生成对应的部署配置,省时省力。
学完这章,你就能:
- 用 Python 读写 JSON/YAML 配置文件
- 自动生成 Vercel 的 vercel.json
- 自动生成 Netlify 的 _redirects\n\n\n\n\n\n
- 自动生成 Nginx 的 nginx.conf
🎯 开场 3 分钟:为什么要学这个?
真实场景
假设你刚用 Vue3 + Vite 写完一个组件库,准备发布到 npm。在本地跑得好好的,但当你试图:
1. 部署到 Vercel 时,不知道该配什么构建命令
2. 部署到 Netlify 时,重定向规则老写错
3. 部署到自己的服务器时,Nginx 配置看着像天书
每个平台配置格式都不一样,查文档查到头秃。
痛点
- 配置格式不统一:Vercel 用 JSON、Netlify 用纯文本重定向规则、Nginx 有自己的语法
- 容易写错:一个分号、一个斜杠错了,网站就 404
- 重复劳动:每个新项目都要重新配一遍
解决什么问题
用 Python 写一个配置文件生成器,你告诉它「我要部署到 Vercel」,它就给你生成好能用的 vercel.json。以后新建项目,跑一下脚本,配置文件全自动生成。
🧱 基础 25 分钟:核心概念
什么是配置文件?
生活类比:你去餐厅吃饭,菜单就是「配置文件」——上面写了有什么菜、价格多少、忌口要提前说。厨房(程序)照着菜单做菜,不会乱来。
为什么要用:项目大了,配置项可能十几个甚至几十个。硬编码在代码里,改一个要改好几处;用配置文件,改一处全生效。
Python 里怎么用:
import json
# 模拟 vercel.json 配置文件
vercel_config = {
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "vite"
}
# 写入文件
with open("vercel.json", "w", encoding="utf-8") as f:
json.dump(vercel_config, f, indent=2)
print("配置文件生成成功!")
运行结果:
配置文件生成成功!
json.dump() 把字典转成 JSON 字符串,写入文件。相当于把「点菜单」写成纸质文件保存下来。
什么是 YAML 格式?
YAML 是一种比 JSON 更易读的配置文件格式,Netlify 和很多 CI/CD 工具喜欢用它。
生活类比:JSON 像「正式合同」,每条规则都要用引号、逗号、括号框起来;YAML 像「便签纸」,能用缩进表示层级,更像 human 自然语言。
为什么要用:Nginx 的配置、GitHub Actions 的 workflow,都用 YAML。学会读/写 YAML,能搞定一半运维配置。
Python 里怎么用(需要安装 pyyaml):
# 先 pip install pyyaml
import yaml
# 模拟 Nginx 配置文件(YAML 格式)
nginx_config = {
"server": {
"listen": 80,
"server_name": "example.com",
"locations": [
{"path": "/", "proxy_pass": "http://localhost:3000"},
{"path": "/api", "proxy_pass": "http://localhost:8000"}
]
}
}
# 写入文件
with open("nginx.yaml", "w", encoding="utf-8") as f:
yaml.dump(nginx_config, f, allow_unicode=True, default_flow_style=False)
print("Nginx 配置生成成功!")
运行结果:
Nginx 配置生成成功!
yaml.dump() 把字典转成 YAML 格式。default_flow_style=False 让输出更易读(不用强行压成一行)。
什么是字符串模板?
生成配置文件时,内容大部分是固定的,只有少部分需要变化。字符串模板就是「填空题」——先写好固定部分,用占位符标记需要填的地方。
生活类比:结婚请帖模板——「恭请 [姓名] 出席婚礼」,方括号就是占位符,填上具体人名就成了一张真请帖。
Python 里怎么用:
# 方式1:f-string(简单场景)
name = "小明"
age = 25
print(f"{name} 今年 {age} 岁")
# 方式2:str.format()(复杂模板)
template = "网站域名:{domain},端口:{port},是否启用SSL:{ssl}"
config = template.format(domain="example.com", port=443, ssl=True)
print(config)
运行结果:
小明 今年 25 岁
网站域名:example.com,端口:443,是否启用SSL:True
f-string 用 {} 包裹变量名,适合简单替换。str.format() 适合大段模板。
什么是命令行参数?
你的 Python 脚本可能会给不同人用,每个人想要的配置不一样。命令行参数让用户跑脚本时指定「我要部署到哪个平台」「域名是什么」,不用改代码。
生活类比:自助取票机让你选「起点站」「终点站」,不同人取不同票,但机器是同一台。
Python 里怎么用:
import sys
# sys.argv 是命令行参数列表
# python deploy.py vercel example.com
# sys.argv = ["deploy.py", "vercel", "example.com"]
if len(sys.argv) < 3:
print("用法:python deploy.py <平台> <域名>")
print("例如:python deploy.py vercel mysite.com")
sys.exit(1)
platform = sys.argv[1]
domain = sys.argv[2]
print(f"准备为 {platform} 生成配置,域名为 {domain}")
运行:
python deploy.py netlify mysite.netlify.app
输出:
准备为 netlify 生成配置,域名为 mysite.netlify.app
sys.argv[0] 是脚本名,sys.argv[1] 是第一个参数,以此类推。
什么是文件读写?
生成配置后要写入文件,用户才能拿去用。读文件和写文件是最基础的操作。
生活类比:写配置文件就像「写信」——写信(写文件)是把脑子里的想法变成纸上的字,读信(读文件)是把纸上的字变回脑子里的想法。
Python 里怎么用:
# 读取已有配置文件
with open("vercel.json", "r", encoding="utf-8") as f:
content = f.read()
print("文件内容:", content)
# 写入新配置文件
config_text = '{"version": 2, "buildCommand": "npm run build"}'
with open("output.json", "w", encoding="utf-8") as f:
f.write(config_text)
print("写入完成!")
运行结果:
文件内容: {"buildCommand": "npm run build", "framework": "vite", "outputDirectory": "dist"}
写入完成!
open() 的第二个参数 "r" 表示读(read),"w" 表示写(write,会覆盖原文件)。
🔥 实战 35 分钟:3 个递进的小项目
项目 1(5 分钟):生成 Vercel 配置文件
目标:输入项目信息,生成一个可用的 vercel.json。
完整代码:
import json
import sys
def generate_vercel_config(project_name, build_command="npm run build", output_dir="dist"):
"""生成 Vercel 配置文件"""
config = {
"projectName": project_name,
"buildCommand": build_command,
"outputDirectory": output_dir,
"framework": None, # None 表示自动检测
"rewrites": [
{"source": "/(.*)", "destination": "/index.html"}
]
}
return config
def save_vercel_json(config, filename="vercel.json"):
"""保存配置到文件"""
with open(filename, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print(f"✅ 已生成 {filename}")
if __name__ == "__main__":
# 模拟命令行参数
project_name = sys.argv[1] if len(sys.argv) > 1 else "my-vue-app"
config = generate_vercel_config(project_name)
save_vercel_json(config)
print("\n生成的配置内容:")
print(json.dumps(config, indent=2, ensure_ascii=False))
运行:
python deploy_vercel.py my-component-lib
预期输出:
✅ 已生成 vercel.json
生成的配置内容:
{
"projectName": "my-component-lib",
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": null,
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}
解释:这个脚本生成了一个 Vercel 配置,包含 SPA 路由重写规则——所有路径都回退到 index.html,解决 Vue Router 的 History 模式 404 问题。
项目 2(15 分钟):生成 Netlify 配置文件(含重定向规则)
目标:读取一个 CSV 文件(包含重定向规则),生成 Netlify 的 _redirects 文件。
准备一个 CSV 文件 redirects.csv:
from,to,status
/,/home,301
/login,/auth,302
/dashboard,/app/dashboard,200
完整代码:
import csv
import sys
def read_redirects_from_csv(csv_file):
"""从 CSV 读取重定向规则"""
redirects = []
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
redirects.append({
"from": row["from"],
"to": row["to"],
"status": int(row["status"])
})
return redirects
def generate_netlify_redirects(redirects):
"""生成 Netlify _redirects 文件内容"""
lines = []
for rule in redirects:
status_part = f"={rule['status']}" if rule["status"] != 200 else ""
line = f"{rule['from']} {rule['to']}{status_part}"
lines.append(line)
return "\n".join(lines) + "\n"
def save_redirects_file(content, filename="_redirects"):
"""保存重定向文件"""
with open(filename, "w", encoding="utf-8") as f:
f.write(content)
print(f"✅ 已生成 {filename}")
def show_preview(content):
"""显示文件预览"""
print("\n📄 文件内容预览:")
print("-" * 40)
print(content)
print("-" * 40)
if __name__ == "__main__":
csv_file = sys.argv[1] if len(sys.argv) > 1 else "redirects.csv"
print(f"📖 读取 CSV 文件:{csv_file}")
redirects = read_redirects_from_csv(csv_file)
print(f"📊 读取到 {len(redirects)} 条重定向规则")
content = generate_netlify_redirects(redirects)
save_redirects_file(content)
show_preview(content)
预期输出:
📖 读取 CSV 文件:redirects.csv
📊 读取到 3 条重定向规则
✅ 已生成 _redirects
📄 文件内容预览:
----------------------------------------
/ /home =301
/login /auth =302
/dashboard /app/dashboard
----------------------------------------
解释:Netlify 的 _redirects 语法和 Nginx 不一样——用空格分隔,状态码用 =<code> 后缀。200 表示 rewrite(不改 URL),301/302 表示跳转。
项目 3(15 分钟):一个完整的「部署配置生成器」
目标:综合前两个项目,写一个命令行工具,输入 python deploy.py vercel mysite.com 就生成对应平台的配置文件。
完整代码:
#!/usr/bin/env python3
"""
部署配置生成器
支持 Vercel / Netlify / Nginx 配置文件自动生成
"""
import json
import yaml
import csv
import os
import sys
def generate_vercel(project_name, build_command, output_dir, domain):
"""生成 Vercel 配置"""
config = {
"projectName": project_name,
"buildCommand": build_command,
"outputDirectory": output_dir,
"installCommand": "npm install",
"framework": None,
"rewrites": [
{"source": "/(.*)", "destination": "/index.html"}
],
"redirects": [
{
"source": "/api/(.*)",
"destination": f"https://{domain}/api/$1",
"permanent": False
}
]
}
return config
def generate_netlify_redirects_from_csv(csv_file):
"""从 CSV 生成 Netlify 重定向规则"""
redirects = []
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
status = row.get("status", "200")
status_part = f"={status}" if status != "200" else ""
redirects.append(f"{row['from']} {row['to']}{status_part}")
return "\n".join(redirects) + "\n"
def generate_nginx_config(domain, port, vue_port):
"""生成 Nginx 配置"""
config = {
"server": {
"listen": port,
"server_name": domain,
"root": "/var/www/html",
"index": ["index.html"],
"locations": {
"/": {
"try_files": ["$uri", "$uri/", "/index.html"]
},
"/api/": {
"proxy_pass": f"http://localhost:{vue_port}/",
"proxy_set_header": {
"Host": "$host",
"X-Real-IP": "$remote_addr"
}
}
}
}
}
return config
def save_file(content, filename):
"""保存文件"""
with open(filename, "w", encoding="utf-8") as f:
f.write(content)
print(f" ✅ {filename}")
def main():
if len(sys.argv) < 3:
print("用法:python deploy.py <平台> <域名> [参数...]")
print("")
print("平台选项:")
print(" vercel - 生成 vercel.json")
print(" netlify - 生成 _redirects(需要 redirects.csv)")
print(" nginx - 生成 nginx.conf")
print("")
print("示例:")
print(" python deploy.py vercel mysite.com")
print(" python deploy.py netlify mysite.netlify.app")
print(" python deploy.py nginx example.com 80 3000")
sys.exit(1)
platform = sys.argv[1].lower()
domain = sys.argv[2]
print(f"\n🚀 部署配置生成器")
print(f" 平台:{platform}")
print(f" 域名:{domain}")
print("-" * 40)
if platform == "vercel":
build_cmd = sys.argv[3] if len(sys.argv) > 3 else "npm run build"
output_dir = sys.argv[4] if len(sys.argv) > 4 else "dist"
config = generate_vercel("my-project", build_cmd, output_dir, domain)
content = json.dumps(config, indent=2, ensure_ascii=False)
save_file(content, "vercel.json")
print(f"\n📝 vercel.json 已生成,包含 SPA 路由重写规则")
elif platform == "netlify":
csv_file = "redirects.csv"
if not os.path.exists(csv_file):
print(f"❌ 找不到 {csv_file},请先创建重定向规则文件")
sys.exit(1)
content = generate_netlify_redirects_from_csv(csv_file)
save_file(content, "_redirects")
print(f"\n📝 _redirects 已生成(从 {csv_file} 读取)")
elif platform == "nginx":
port = int(sys.argv[3]) if len(sys.argv) > 3 else 80
vue_port = int(sys.argv[4]) if len(sys.argv) > 4 else 3000
config = generate_nginx_config(domain, port, vue_port)
content = yaml.dump(config, allow_unicode=True, default_flow_style=False)
save_file(content, "nginx.conf")
print(f"\n📝 nginx.conf 已生成,监听 {port} 端口,API 代理到 {vue_port}")
else:
print(f"❌ 不支持的平台:{platform}")
sys.exit(1)
print("\n✨ 完成!将生成的配置文件放到项目根目录即可。\n")
if __name__ == "__main__":
main()
运行示例 1:
python deploy.py vercel my-component-lib
预期输出:
🚀 部署配置生成器
台:vercel
名:my-component-lib
----------------------------------------
✅ vercel.json
📝 vercel.json 已生成,包含 SPA 路由重写规则
✨ 完成!将生成的配置文件放到项目根目录即可。
运行示例 2:
python deploy.py nginx example.com 8080 5173
预期输出:
🚀 部署配置生成器
台:nginx
名:example.com
----------------------------------------
✅ nginx.conf
📝 nginx.conf 已生成,监听 8080 端口,API 代理到 5173
✨ 完成!将生成的配置文件放到项目根目录即可。
解释:这个脚本综合了前两个项目的功能,用 if/elif 判断平台,读取不同参数,生成不同格式的配置。学会了这种「主函数 + 子函数」的结构,你就能写任何命令行工具。
💪 进阶 20 分钟:常见坑 + 性能小贴士
坑 1:JSON 的引号必须是双引号
# ❌ 错误:Python 字符串用单引号,JSON 不认
json_str = "{'name': '小明'}"
json.loads(json_str) # 报错!
# ✅ 正确:用双引号
json_str = '{"name": "小明"}'
data = json.loads(json_str)
print(data["name"]) # 输出:小明
原因:JSON 规范要求字符串必须用双引号,Python 的 json 模块会自动处理这个转换。
坑 2:YAML 缩进必须一致
# ❌ 错误:混用空格和 Tab,YAML 解析可能出错
config = {
"server": {
"listen": 80, # 缩进不一致
"name": "test"
}
}
# ✅ 正确:全部用 2 或 4 个空格
config = {
"server": {
"listen": 80,
"name": "test"
}
}
原因:YAML 用缩进表示层级,Tab 和空格混用会导致解析出莫名其妙的结果。
坑 3:读取文件路径要处理编码
# ❌ 错误:不指定编码,Windows 默认用 GBK 读UTF-8文件会乱码
with open("vercel.json", "r") as f:
content = f.read() # 中文可能乱码
# ✅ 正确:明确指定 UTF-8
with open("vercel.json", "r", encoding="utf-8") as f:
content = f.read() # 稳妥
原因:Windows 默认编码是 GBK,macOS 和 Linux 是 UTF-8。指定编码是最佳实践。
坑 4:命令行参数索引从 1 开始
# ❌ 错误:以为 sys.argv[0] 是第一个参数
script_name = sys.argv[1] # 错!这是脚本自己
# ✅ 正确:sys.argv[0] 是脚本路径,参数从 1 开始
script_name = sys.argv[0]
first_arg = sys.argv[1] # 才是第一个参数
原因:sys.argv 列表的第一个元素永远是脚本文件名。
坑 5:写入文件前确认目录存在
# ❌ 错误:直接写文件,但目录不存在
with open("output/vercel.json", "w") as f:
f.write(content) # 报错:目录不存在
# ✅ 正确:先创建目录
import os
os.makedirs("output", exist_ok=True)
with open("output/vercel.json", "w") as f:
f.write(content) # 稳妥
原因:open() 不会自动创建父目录,写入前要确保路径存在。
性能小贴士:批量写入用上下文管理器
# ✅ 好习惯:用 with 自动关闭文件
with open("vercel.json", "w", encoding="utf-8") as f:
json.dump(config, f, indent=2)
# 不用手动 f.close(),with 块结束自动关闭
原因:文件句柄是稀缺资源,用 with 确保及时释放。
调试技巧:print 大法
def generate_vercel_config(project_name):
print(f"[调试] 输入项目名:{project_name}") # 打印中间值
config = {
"projectName": project_name,
"buildCommand": "npm run build"
}
print(f"[调试] 生成配置:{config}") # 打印结果
return config
遇到问题先加 print,看看变量实际值是什么,比盯着代码猜快多了。
✏️ 练习题
练习 1(2 分钟):改平台名
项目 1 的代码,只改一个地方,让它生成的项目名变成 "awesome-ui"。
- 输入:运行
python deploy_vercel.py(不传参数) - 预期输出:
"projectName": "awesome-ui" - 提示:找
sys.argv那行,改默认值
练习 2(2 分钟):加一个条件判断
在项目 1里,加一个 if 判断:如果 build_command 是 "npm run build",就打印 "使用默认构建命令";否则打印 "使用自定义构建命令:xxx"。
- 输入:
python deploy_vercel.py - 预期输出:包含
"使用默认构建命令"的日志 - 提示:在
generate_vercel_config函数里加 if 判断
练习 3(3 分钟):处理新的 CSV
新建一个 routes.csv,包含 2 条规则:
from,to,status
/products,/shop,301
/about,/info,200
用项目 2的方法处理这个新文件。
- 输入:运行
python deploy_netlify.py routes.csv - 预期输出:生成包含
/products /shop =301的_redirects文件 - 提示:改
sys.argv[1]的默认值或传参
练习 4(3 分钟):串起两个项目
把项目 2的 CSV 读取功能,集成到项目 3里——让 Vercel 模式也能读取 CSV 生成重定向规则。
- 输入:运行
python deploy.py vercel myapp.com - 预期输出:
vercel.json里包含redirects数组 - 提示:在
generate_vercel函数里调用 CSV 读取函数
练习 5(5 分钟):分析报错
看下面这段代码的运行结果,为什么 config["user"] 取不到值?
import json
json_str = '{"name": "小明", "age": 25}'
config = json.loads(json_str)
print(config["user"])
- 预期输出:报错
KeyError: 'user' - 提示:JSON 里的字段名和代码里写的要一致
作业:做一个「多环境配置文件生成器」
需求描述:
开发项目通常有多个环境:开发(development)、测试(staging)、生产(production)。每个环境的 API 地址、调试开关都不一样。用 Python 写一个配置生成器,能根据环境生成对应的配置文件。
功能点:
1. 支持 dev / staging / prod 三种环境
2. 每个环境有不同的 API_BASE_URL 和 DEBUG 开关
3. 生成 JSON 格式的环境配置文件
4. 命令行传入环境名
加分项:
1. 支持 -o 参数指定输出目录
2. 生成 .env.example 文件(列出所有可配置项)
验收标准:
- 运行 python env_generator.py dev 生成 env.dev.json
- 运行 python env_generator.py prod -o ./config 生成 ./config/env.prod.json
- 文件内容包含 API_BASE_URL 和 DEBUG 字段
📚 总结 + 资源
本文学到的 3 个核心点
- 配置文件是「菜单」:用 JSON/YAML 格式保存配置,程序读菜单干活,不把配置写死在代码里
- 字符串模板是「填空题」:用
f-string或format()把可变部分填进固定模板 - 命令行参数是「点菜」:用户跑脚本时告诉程序要什么,程序根据参数生成不同结果
延伸学习资源
- Python 官方文档 - json 模块:JSON 操作的完整指南
- PyYAML 官方文档:YAML 读写的更多用法
- Real Python - Command Line Apps:更深入的命令行参数处理(argparse)
互动钩子
你在部署 Vue 项目时遇到过什么坑?Vercel 的冷启动慢、Netlify 的重定向不生效、还是 Nginx 的跨域配置调崩了?评论区聊聊你的惨痛经历,老粉优先回复!
下一章我们要做一个综合实战:把前几章学的 Monorepo 管理、组件库开发、部署配置全部串起来,从零开始搭建一个可发布的 Vue3 组件库。敬请期待!

评论(0)