本文介绍如何使用gulp作为工具帮我们自动化部署前端代码到后端服务器,以及如何使用.env文件来管理环境变量,管理不同环境的账密。
1 背景
在开发过程中,经常会需要把代码部署到开发或者测试环境,如果每次都需要手动打包好再拷贝到服务器,那就太麻烦了。先说一下部署的过程:连接服务器,然后把我们的代码上传到服务器指定位置。建一套部署工具,自动实现打包部署,可以省很多事,还不容易出错。
2 实现简易部署
2.1 安装依赖
npm i gulp gulp-sftp-up4 --save-dev
2.2 配置gulp
首先,在项目根目录下新建gulp.js,新建一个test-deploy的gulp task
const gulp = require("gulp");
const sftp = require("gulp-sftp-up4");
gulp.task("test-deploy", function() {
return gulp.src("dist" + "/**").pipe(
sftp({
host: "服务IP",
user: "账户",
pass: "密码",
port: "端口 默认值是22",
remotePath: `文件放置的路径`
})
);
});
2.3 配置命令
在package.json中的scripts下添加命令
"test-deploy": "vue-cli-service build && gulp test-deploy"
2.4 测试部署
在控制台输入 npm run test-deploy
即可自动打包,部署,没出意外的话,可以在服务器对应的目录下看到刚刚上传的文件。没有线上服务器的话,可以用虚拟机试试。
简易的部署就到这里结束了。
在上面的部署中,我们把服务器的账户和密码都写在了gulp.js中,这个文件会被提交到git,这样是非常不安全的,所以接下来会介绍如何使用.env文件管理环境变量和账密,这适合用于有多个环境的管理,如果觉得太麻烦的话,也可以直接用 .ftppass 文件,它是gulp-sftp的配置文件。
3 .env文件的使用
3.1 新增.env文件
在根目录下新增 .env.dev 和.env.prod 两个环境文件,文件中会放除了账号密码之外的其他环境配置,比如
HOST = 192.168.2.88
REMOTE_PATH = /web-dev
3.2 新增.env.local文件
在根目录下新增 .env.dev.local 和.env.prod.local .local文件中的配置会和之前的配置做一个Object.assign的操作,.local文件用来存放账密,.local文件不会被提交到git上,而是在本地存放(为了示例完整,我会放上github),现在在本地可以看到四个.env文件
3.3 新增env.config.js
根目录下新建一个文件夹builder,新建文件env.config.js,里面的代码如下
const glob = require("glob");
const fs = require("fs");
const dotenv = require("dotenv");
const gutil = require("gulp-util");
const argv = Object.assign({ mode: null }, gutil.env);
//列出.local文件,用于第一步询问需要部署哪个环境
const listLocal = glob.sync(".env.*.local").map(i => {
const [lenPrefix, lenSuffix] = [".env.".length, ".local".length];
return i.substr(lenPrefix, i.length - lenSuffix - lenPrefix);
});
//把env文件中的设置的参数放入process.env
const setEnv = mode => {
let envSetting = getEnv(mode);
Object.keys(envSetting).forEach(
_key => (process.env[_key] = envSetting[_key])
);
};
//合并.local文件, 比如合并 .env.dev 和 .env.dev.local, .local文件的配置会覆盖前面的
const getEnv = mode => {
let data = [`.env.${mode || ""}`, `.env.${mode || ""}.local`];
console.log("data11", data);
data = data.filter(i => fs.existsSync(i));
console.log("data", data);
data = data.map(i => dotenv.config({ path: i }).parsed);
return Object.assign.apply(this, data);
};
module.exports = { mode: argv.mode, listLocal, getEnv, setEnv };
3.4 修改task deploy方法
在builder目录下,新增task-deploy.js文件
文件中引入了一个prompt包,在我们执行npm deploy之后,会询问要部署的环境,如下图
选择好要部署的环境后(chooseEnviroments),就会开启批量部署流程(batchDeploy),根据需要部署的环境,执行打包命令和上传到对应位置,批量部署完成后,则本次部署完成
const { execSync } = require("child_process");
const prompts = require("prompts");
const gulp = require("gulp");
const sftp = require("gulp-sftp-up4");
//deploy task
const taskDeploy = ({ listLocal, setEnv, mode }, _callback) => {
if (mode !== null) {
return Promise.resolve()
.then(() => console.log(`Deploy starting...`))
.then(() => setEnv(mode)) // 设置环境变量
.then(() => {
return buildApp({ mode }); //打包项目
})
.then(() => {
return deploy();
})
.catch(_error => console.log(`x ${_error.message && _error}`))
.finally(_callback);
} else {
// 没有指定打包环境,就执行下面这段代码,下面这段代码的实际作用就是根据命令行中的选择,构建出每个环境最终的gulp deploy task命令,
// 执行命令的时候,因为mode不为空了,就会执行上面if中的代码了
chooseEnviroments({ envs: listLocal })
.then(({ environments }) => batchDeploy({ environments }))
.catch(_error => console.log("error", _error))
.finally(_callback);
}
};
//使用prompts,在部署过程中提供友好的交互式命令行提示
const chooseEnviroments = ({ envs }) => {
return prompts([
{
type: "multiselect",
name: "environments",
message: "Which environments do you want to deploy?",
choices: envs.map(i => ({ title: i, value: i })),
validate: environments =>
environments.length === 0 ? "environments is required" : true
}
]);
};
//循环获取之前选择要部署的环境,挨个部署这些环境,这里如果不需要分环境打包,可以优化一下不用重复打包
const batchDeploy = ({ environments }) => {
let envDeploySuccess = [];
environments.forEach(_env => {
let cmd = `gulp deploy --mode ${_env}`;
let execResult = execCommandSync(cmd).toString();
console.log(execResult);
if (execResult.includes("Deploy Succeeded")) envDeploySuccess.push(_env);
console.log("exec", cmd, "done");
});
};
//执行gulp deploy task
const execCommandSync = _cmd => {
console.log("exec command:", _cmd);
try {
return execSync(_cmd)
.toString()
.trim();
} catch (e) {
return null;
}
};
// 使用 vue cli 编译打包项目
const buildApp = ({ environment }) => {
console.log(`Vue Cli Building for ${environment} ...`);
let execResult = execCommandSync(
`vue-cli-service build --mode ${environment}`
).toString();
console.log(execResult);
return Promise.resolve();
};
//使用sftp上传文件到服务器
const deploy = () => {
gulp.src("dist" + "/**").pipe(
sftp({
host: process.env.HOST,
user: process.env.USER,
pass: process.env.PASSWORD,
port: "22", //默认值就是22
remotePath: process.env.REMOTE_PATH
})
);
};
module.exports = { taskDeploy };
3.5 gulp.js使用 taskDeploy,配置package.json
gulp.js使用 taskDeploy
gulp.task("deploy", _callback => taskDeploy(envConfig, _callback));
配置package.json,在scripts下添加
"deploy": "gulp deploy"
可以为某个环境单独配置一条命令
"deploy-dev": "gulp deploy --mode dev"
结语
利用.env文件,还可以实现一些个性化的部署,比如为某个环境打包专属的element theme。文章到这里就结束了,欢迎在留言区分享一下大家的部署方式,有用的话请点个赞,代码放在了github:github.com/daisygogogo…