本文已参与「新人创作礼」活动,一起开启掘金创作之路。
背景:
前端项目采用Nginx部署在云上
server {
server_name www.domain.com;
client_max_body_size 10m;
location /chairong/dist {
root /home/user/frontend;
try_files $uri $uri/ /project-name/dist/index.html;
}
location = / {
rewrite (.*) project-name/dist permanent;
}
...
}
本地安装了python3.8+和fabric(如果是windows系统需配置一下,让fab命令可用)
$catpython123 fabfi服务器价格le.py # 该文件放在前端代码仓库里,与package.json同级目录
__author__ = "WJ"
"""
Auto update server deploy
~~~~~~~~~~~~~~~~~~~~~~~~~
前端`output_dir`包自动部署脚本
自动将yarn pre构建出来的`output_dir`文件夹,替换掉测试服务器上的旧文件夹
Usage:
- For windows
1. Install python3.8
2. pip install fabric
3. add folder of fab.exe to environment path
# Example: /c/Users/Administrator/AppData/Roaming/Python/Python38/Scripts/
4. then open git bash and run the following command:
$ fab pre
- For linux
1. just run:
$ cd /path/to/project && (which fab||pip install fabric --user) && fab dist
"""
import os
from datetime import datetime
from os.path import getmtime
from pathlib import Path
from typing import Union
from fabric import Connection, task
PROJECT = Path().resolve().name # 假设当前文件夹名就是项目名
HOST = "user@www.domain.com"
PATH = f"~/frontend/{PROJECT}" # 服务器上dist包放置的位置
DELTA = 60 * 1 # 这个时间内(1 min),如果output_dir已存在,不再重新yarn build
DEPLOY_DIR = "dist" # 服务器上部署的文件夹名
OUTPUT_DIR = "bundle" # yarn pre生成的文件夹名
def parse_args(domain=None, host=None, port: int = 22):
if host is None:
if domain is None:
host = HOST
else:
user = os.getenv(f"{domain}_user".replace(".", "_"))
host = f"{user}@{domain}"
if domain is None:
domain = host.split("@")[-1]
if (p := os.getenv(f"{domain}_port")) : # noqa: E231, E203
port = int(p) # type: ignore
return domain, host, port
def make_connection(domain=None, host=None, port: int = 22):
domain, host, port = parse_args(domain, host, port)
passwd = os.getenv(f"{domain}_passwd")
c = Connection(host, port=port, connect_kwargs={"password": passwd})
print(f"Success to make a connection with {host}")
return c
def seconds_from_last_updated(fpath: Union[str, Path]) -> int:
"""return the seconds passed after `fpath` last motified"""
mtime = datetime.fromtimestamp(getmtime(fpath))
passed = datetime.now() - mtime
return passed.seconds
def run_and_echo(cmd: str, run_func=None) -> int:
"""运行cmd,并打印运行的语句"""
print("-->", cmd)
if run_func is None:
run_func = os.system
return run_func(cmd)
def build_compiled_dir(action: str = "pre", verbose: str = "") -> None:
"""自动给yarn管理的项目编译出output_dir文件夹"""
actions = [i for i in (action, verbose) if i]
cmds = [
f"{tool} {action}"
for tool in ("yarn", "npm run")
for action in actions
]
for cmd in cmds:
if run_and_echo(cmd) == 0:
break
def zip_output_dir(folder: str) -> None:
"""如果output_dir文件夹不存在,则编译后用zip压缩,否则直接压缩"""
actions = ("pre",) if folder == "bundle" else ("b", "build")
if not (p := Path(folder)).exists(): # noqa: E231, E203
build_compiled_dir(*actions)
elif seconds_from_last_updated(p) > DELTA:
run_and_echo(f"rm -rf {p}")
build_compiled_dir(*actions)
run_and_echo(f"zip -qr {folder}.zip {folder}/")
def create_or_fresh_zip(folder: str = OUTPUT_DIR) -> str:
p = Path(f"{folder}.zip")
if not p.exists():
zip_output_dir(folder)
elif seconds_from_last_updated(p) > DELTA:
run_and_echo(f"mv {folder}.zip {folder}.zip.bak")
zip_output_dir(folder)
return folder
def scp_to_server(
folder: str,
domain: Union[str, None] = None,
port: int = 22,
host: Union[str, None] = None,
path: str = PATH,
) -> None:
_, host, port = parse_args(domain, host, port)
run_and_echo(f"scp -P {port} {folder}.zip {host}:{path}")
def deploy(c, folder: str):
deploy_dir = DEPLOY_DIR
with c.cd(PATH):
run_and_echo(f"rm -rf {deploy_dir}", c.run)
# c.run("rm -rf dist.zip")
# c.put("./dist.zip", ".")
run_and_echo(f"unzip -q {folder}.zip", c.run)
if deploy_dir != folder:
run_and_echo(f"mv {folder} {deploy_dir}", c.run)
@task
def pre(c):
"""自动部署前端yarn pre出来的文件夹到测试服务器"""
folder = create_or_fresh_zip()
scp_to_server(folder)
c = make_connection()
deploy(c, folder)
print("success to deploy the static files")
@task
def es(c):
"""自动部署前端yarn build出来的文件夹到生产服务器"""
folder = create_or_fresh_zip("dist")
domain = "www.domain-of-production-server.com"
scp_to_server(folder, domain)
c = make_connection(domain)
deploy(c, folder)
print("success to deploy the static files at production server.")
@task
def dev(c):
"""自动部署前端yarn f出来的文件夹到内部服务器"""
folder = create_or_fresh_zip("dist")
host = "dev@dev.esoaru.com"
scp_to_server(folder, host=host)
c = make_connection(host=host)
deploy(c, folder)
print("success to deploy the static files at production server.")