说在前面
都 2025 了,你的前端项目还是手动打包上传部署的吗?手动嫌麻烦,流水线不想搞,那就直接写个一键部署脚本吧,这里以 vue 项目为例,简单来实现一个一键部署脚本。
实现思路
1、配置信息
首先我们需要先配置好部署项目的相关信息,主要信息如下:
(1)仓库地址
gitAddress 为需要拉取的项目仓库地址;
gitBranch 为需要拉取的项目分支,默认为 master 分支。
(2)项目部署信息
projectFolder 为需要打包的目录,默认为拉取项目的根目录,如以下项目,前端项目文件在blog目录中,所以我们需要打包的目录为 blog 目录,需要在配置中写上"projectFolder": "blog"
assetsRoot 为项目打包生成的 “dist包” 目录,默认为 dist;
distFolder 为项目打包后 “dist包” 存放的位置,即部署项目的目录。
(3)私密配置
privateConfigurationFile 为需要替换的配置文件,格式为:
{
"项目文件路径":"替换文件路径"
}
2、项目拉取
配置好部署项目的相关信息之后我们就可以根据配置信息来拉取项目了。
(1)拉取项目到本地
function cloneProject() {
console.log("正在拉取项目到本地,请稍等……");
const { gitAddress, gitBranch = "master" } = config;
const command = `git clone -b ${gitBranch} ${gitAddress} ${localCloneDir}`;
child_process.execSync(command);
}
- git clone 参数说明:
-b ${gitBranch}
:指定要克隆的分支名称;
${gitAddress}
:远程仓库的地址;
${localCloneDir}
:本地克隆目录,即克隆下来的项目将存储在这个目录中。
(2)判断项目是否有更新
- 获取最后一次提交的hash
async function getLastCommit() {
const command = `git -C ${localCloneDir} log -1"`;
const logStdout = await child_process
.execSync(command)
.toString()
.split(rowReg)
.filter((item) => !rowReg.test(item));
return logStdout[0].split(" ")[1];
}
git -C ${localCloneDir} log -1
获取到的信息如下:
我们取第一行的 hash 值即可。
- 判断hash是否有变化
每次部署的时候我们都会将获取到的hash值更新保存到tmp.json中,我们只需要取出tmp.json中对应的hash值进行比较即可。
async function isHashChange(hash) {
const { gitAddress, gitBranch } = config;
const hashKey = gitAddress + "-" + gitBranch;
const oldHash = tmpConfig[hashKey];
if (oldHash === hash) {
return false;
}
tmpConfig[hashKey] = hash;
fs.writeFileSync("./tmp.json", JSON.stringify(tmpConfig, null, 2));
return true;
}
(3)私密配置替换
正常情况下我们都不会把私密信息直接上传到git仓库中,比如:接口加密秘钥等…… 上面配置就会在打包前将blog/src/config/config.js
中的内容使用blogConfig.js
中的内容来替换。
- blog/src/config/config.js
- blogConfig.js
async function replaceConfig() {
const { privateConfigurationFile = {} } = config;
for (const key in privateConfigurationFile) {
if (!fs.existsSync(privateConfigurationFile[key])) {
console.log(`${privateConfigurationFile[key]}文件不存在,跳过`);
continue;
}
const content = fs.readFileSync(privateConfigurationFile[key]).toString();
const tmpPath = Path.join(localCloneDir, key);
if (!fs.existsSync(tmpPath)) {
console.log(`${tmpPath}文件不存在,跳过`);
continue;
}
fs.writeFileSync(tmpPath, content);
console.log(`已将${tmpPath}替换为${privateConfigurationFile[key]}`);
}
}
3、项目部署
(1)获取需要打包的项目路径
const { projectFolder = "./" } = config;
const folder = Path.join(localCloneDir, projectFolder);
(2)安装依赖
const installCommand = `cd ${folder} && npm install`;
console.log("正在安装依赖,请稍等……");
await child_process.execSync(installCommand);
(3)项目打包
const buildCommand = `cd ${folder} && npm run build`;
console.log("正在打包项目,请稍等……");
await child_process.execSync(buildCommand);
(4)移动dist包到部署目录
async function moveDistToDeployDir() {
const { projectFolder = "./", assetsRoot = "dist", distFolder } = config;
const folder = Path.join(localCloneDir, projectFolder, assetsRoot);
const list = fs.readdirSync(folder);
for (const item of list) {
const tmpPath = Path.join(folder, item);
fs.copySync(tmpPath, Path.join(distFolder, item), { overwrite: true });
}
}
4、自动更新
要实现自动更新的方案有以下两个:
(1)服务器定时脚本
可以直接定时执行脚本,比如5分钟执行一次。
Linux 系统(使用 cron)
在 Linux 系统中,cron
是一个常用的定时任务调度工具,它允许用户根据设定的时间规则来执行特定的脚本或命令。
*/5 * * * * /path/to/your/script.sh
每隔 5 分钟执行一次 /path/to/your/script.sh
脚本。cron
时间表达式由 5 个字段组成,分别表示分钟(0 - 59)、小时(0 - 23)、日期(1 - 31)、月份(1 - 12)和星期(0 - 7,0 和 7 都表示周日)。*/5
表示每 5 分钟。
Windows 系统(使用任务计划程序)
Windows 系统提供了任务计划程序,允许用户创建和管理定时任务。
按下 Win + R
组合键,输入 taskschd.msc
并回车,打开任务计划程序,在里面配置即可。
(2)githook + 接口调用
可以编写一个接口,用于主动调用部署脚本,并增加一个githook(post-update),在项目推送到远程仓库的时候调用接口出发自动部署。
总结
项目上线少不了部署环节,公司大型项目大多数会使用流水线部署,借助诸如 Jenkins、GitLab CI/CD 等工具,确实能够实现自动化的构建、测试和部署流程,大大提高部署的效率和稳定性,但搭建和维护这样的流水线并非易事,需要熟悉相关工具的配置和使用,了解不同环境下的部署细节,还需要投入一定的时间和精力来确保流水线的正常运行。
对于个人项目来说,很多时候其实没有必要使用到流水线部署,编写一个简单的自动化部署脚本就可以满足自己的需求。
源码
gitee
🌟觉得有帮助的可以点个star~
🖊有什么问题或错误可以指出,欢迎pr~
📬有什么想要实现的脚本或想法可以联系我~
公众号
关注公众号『前端也能这么有趣
』,获取更多有趣内容。
公众号发送 加群 可以加入群聊,一起来学习(摸鱼)吧~
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。