《大前端进阶 Node.js》系列 脚手架/CI入门(下)

14,309 阅读13分钟

前言

Coding 应当是一生的事业,而不仅仅是 30 岁的青春🍚
本文已收录 Github https://github.com/ponkans/F2E,欢迎 Star,持续更新💧

本文中 cli 已发布至 npm 仓库,如下:


每篇文章都希望你能收获到东西,这篇是前端项目的自动化构建部署,希望你看完,能够有这些收获:

  • CLI 创建远端仓库
  • CLI 打包
  • Nginx 部署
  • Webhook 触发 Jenkins 打包部署服务
  • Jenkins 打包部署
  • CI 构建

架构图

下图中左边部分的项目初始化、模板拉取、项目运行部分,在《大前端进阶 Node.js》系列 P6 必备脚手架/CI 构建能力(上)中,已经实现了。

今天实现右边部分,也就是 CI 部分(大家平时经常用的前端项目发布系统,大致就是这么个东西)。

完整架构
完整架构

前期准备

GitHub 账号

项目如果只是存储在本地很容易因为一些意外情况(比如咖啡倒了、和媳妇吵架电脑摔了等等)导致代码丢失,而且不方便多人合作开发维护,所以我们都是需要远端仓库存储项目的,本文使用的是 GitHub 仓库,如果大家想要跟踪实践,要先准备好 GitHub 账号。

server

为了让用户可以通过网络浏览器之类的客户端在因特网上访问我们的网页,我们需要一台 server 来部署项目,这样用户就可以通过公网 IP 访问我们的网页了。

本文用的是 aliyun server,有条件的话也可以准备一个,当然没条件也不要慌,我们电脑也是一台 server,有它在手四海八荒都可以走一朝。

server 部署

  • 安装 Nginx

  • 安装 node

  • 安装 yum

    PS:yum 是一个 Shell 前端软件包管理器。基于 RPM 包管理,能够从指定的 server 自动下载 RPM 包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载、安装。

    比如,Jenkins 使用 yum 安装就很方便快捷。

CLI 创建远端仓库

命令行创建仓库

有时候为了将本地的项目仓库同步到 Github,我们还得打开浏览器去自己的 Github 账户下创建一个空仓库,打断了自己的工作流,如果我们可以通过命令行的形式创建 Github 仓库并关联本地项目岂不是完美,并且命令行还可以集成到我们的 CLI 工具里,只要想不到没有做不到的,下面我们就介绍下如何通过命令行创建仓库。

首先在你的 Github 上创建一个 token 创建地址,在命令行创建项目的时候需要这个 token 做校验

(select scopes 我全部勾上了,毕竟加班加点赶文章,来不及仔细研究,见谅见谅)

一定要把生成的 personal access token 保存下来,只会显示一遍,不记下来以后就找不到了

通过命令行创建 Github 仓库
curl -u "$username:$token" https://api.github.com/user/repos -d '{"name":"$repo_name"}'

这里需要把上述 username 和 token 分别换成实际的用户名和刚才记住的 personal access token,把 repo_name 换成任何想要的仓库名。

将命令行创建 Github 仓库的功能集成到 CLI 工具里

我们上期文章有介绍到 CLI 有个初始化的功能,接下来我们将命令行创建 Github 仓库的功能补充到初始化命令里,先列 yi 一下 CLI 初始化要做的事情:

  • Git 初始化
  • 创建 Github 仓库
  • 关联 Github 仓库
  • 更新 package.json 的 repository 配置
  • 提交代码到 Github 仓库
  • 安装依赖

相关代码在 little-bird-cli/src/init.js

try {
  await loadCmd(`git init`'git初始化');
  if (username === '' || token === '') {
    console.log(symbol.warning, chalk.yellow('缺少入参无法创建远端仓库'));
  } else {
    const projectName = process.cwd().split('/').slice(-1)[0];

    await loadCmd(`curl -u "${username}:${token}" https://api.github.com/user/repos -d '{"name": "${projectName}"}'`'Github仓库创建')
    await loadCmd(`git remote add origin https://github.com/${username}/${projectName}.git`'关联远端仓库')
    let loading = ora();
    loading.start(`package.json更新repository: 命令执行中...`);
    await updateJsonFile('package.json', {
      "repository": {
        "type""git",
        "url"`https://github.com/${username}/${projectName}.git`
      }
    }).then(() => {
      loading.succeed(`package.json更新repository: 命令执行完成`);
    });

    await loadCmd(`git add .`'执行git add')
    await loadCmd(`git commit -a -m 'init'`'执行git commit')
    await loadCmd(`git push --set-upstream origin master`'执行git push')
  }
  await loadCmd(`npm install`'安装依赖')
} catch (err) {
  console.log(symbol.error, chalk.red('初始化失败'));
  console.log(symbol.error, chalk.red(err));
  process.exit(1);
}

为了方便大家体验,我这里是把 username 和 token 作为命令行入参传进来的,如果是你自己的项目,可以将其直接写死在代码里,在你的项目目录下执行 lbc init -u username -t ​token 如果得到以下结果,那么恭喜你成功啦,快去 Github 远程仓库查看你的项目代码

image-20200330133928513

至此,大家就可以直接跨越千山和万水,开始 Coding 啦,两耳不闻窗外事,一心只用写代码,果然是很爽

手动打包 & 部署

打包

打包可以理解为上线发布时的预处理工作, 会将浏览器不能识别的语法做预处理转换,把所有的 js 文件, css 文件都分别压缩合并为一个 All in One 的 .js 和 .css 文件。

这样浏览器就可以通过少量的 HTTP 请求获取到所需要的前端资源了, 节省流量, 加快页面加载速度,目前比较流行的打包工具有 Gulp, Grunt, Webpack 等。

我们的 CLI 工具已经引入了 webpack,所以打包这一步还是使用 webpack 来实现。

lbc build

little-bird-cli/src/main.js命令管理文件里增加打包命令lbc build

webpack.build.js

增加 webpack 打包配置文件webpack.build.js,它和我们的本地项目启动 webpack 配置文件的主要区别是增加了打包输出,减少一些不需要的方法比如监听。

output: {
  filename:'[name].[hash].js',
  path: process.cwd() + '/dist',
  publicPath'/',
}
执行脚本

增加 build 执行脚本文件 little-bird-cli/src/build.js

let build = () => {
    webpack(config, (error) => {
        if (error !== null){
            console.log(symbol.error, chalk.red(error));
        } else {
            console.log(symbol.success, chalk.green('打包完成'));
        }
        process.exit(1);
    });
}

在项目目录下执行lbc build,查看 dist 目录就可以看到打包生成的 html/js 文件了

部署

在开始自动打包部署之前我们先来体验下手动打包部署,正好可以校验下我们的 CLI 打包命令在 server 端 是否可以正常使用。

接下来的操作都是在 server 环境哦~😯

登录

登录你的 server,将项目代码 clone 到你的 server( clone 后别忘了安装依赖npm install

安装脚手架 npm 包

全局安装 CLI 包 npm i -g little-bird-cli@latest

lbc build 打包

在项目目录执行 lbc build 打包命令,查看在你 clone 的项目的 dist 目录是不是生成了 html/js 文件,如果有的话代表 CLI 打包功能在服务端正常运转。

Nginx

修改 Nginx 配置,打开配置文件vim /etc/nginx/nginx.conf,root 为你 clone 项目的 dist 目录

启动 Nginx 服务,重启 Nginx 服务 nginx -s reload,通过 ip:80 端口就可以访问你的页面了

虽然通过手动操作也能够提供我们的项目网页给用户使用,但是每次有代码更新的时候,都需要本地 push 代码到远端仓库, 然后登录 server pull 代码再打包代码,重复性的工作能省则省,工具都是懒人发明的😆,下面懒人法宝就要登场了,一劳永逸 ~

很多公司有自己的一套前端发布系统,并不是自动部署滴,需要手动去触发打包、部署

自动打包 & 部署基础建设

接下我们通过使用 Jenkins+Github+Webhook 自动打包部署项目,实现 master 分支进行提交的时候,自动执行脚本进行打包部署操作。

大家可能会疑问 Jenkins 是什么

Jenkins 是一款开源 CI 软件,用于自动化各种任务,包括构建、测试和部署软件。想了解更多大家可以去官网查看。

Webhook 又是什么呢

通常称其为钩子(不是 React Hook,hhhh~~),通过定制 Webhook 来检查 Github 上的各种事件,最常见的就是 push 事件了。

如果你设置了一个监听 push 事件的 Webhook,每次你的项目有任何提交,这个 Webhook 都会被触发,这时 Github 会发送一个 HTTP POST 请求到你配置好的地址。

概念先简单了解下(具体的自行 Google),接下来我们要正式开始了哦~

部署 server

我们第一步先来部署 server,首先要登录你的 server(我好像废话了,哈哈😝)。

接下来为你的 server 安装 Jenkins。因为 jenkins 的运行需要 JDK 环境,所以我们还需要在自己的 server 上安装 java 运行环境。

安装 java 运行环境

查看你的 server 是否安装了 JDK

java -version

如果出现以上信息则表示没有按照 JDK。可以通过 yum 安装,步骤如下

执行命令 yum -y list java* 查看可安装 java 版本

选择一个 java 版本进行安装 yum install java-1.8.0-openjdk-devel.x86_64,根据提示完成安装。

输入java -version 查看是否安装成功

安装 Jenkins

yum 的 repos 中默认是没有 Jenkins 的,需要先将 Jenkins 存储添加到 yum repos

sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

执行 yum install jenkins 安装 Jenkins

修改 Jenkins 配置

默认情况下 Jenkins 是使用 Jenkins 用户启动的,但是这个用户目前系统是没有赋予权限的,所以我们将启动用户改为 root,另外 Jenkins 默认端口 8080,如果你没有其他服务占用 8080 端口可以不修改。

vim /etc/sysconfig/jenkins

修改配置

JENKINS_USER = 'root'
JENKINS_PORT = '8001'

执行 service jenkins start 启动 Jenkins 服务

出现上述信息表示 Jenkins 启动成功,在浏览器输入*ip:8001访问 Jenkins 登录页面。

然而~然而~一直在转圈圈,访问不了,我是谁我在哪发生了什么❓

懵逼 1 秒钟,开始排查问题

首先确认下 Jenkins 是否真的启动成功了,执行 systemctl status jenkins 查看 Jenkins 状态

Jenkins 运行正常,为何无法访问呢,噢!!!

再来检测下防火墙,执行systemctl status firewalld查看防火墙状态

防火墙未启动,好的, 没问题,让我们来启动它 systemctl start firewalld

防火墙已启动,让我们来查看防火墙有没有开放我们设置的 Jenkins 端口,执行 firewall-cmd --list-ports 发现没有 Jenkins 的端口,没有也没问题我们开启就好了

firewall-cmd --permanent --zone=public --add-port=80/tcp  // 开启已配置好的Jenkins端口
systemctl reload firewalld // 重启防火墙,重启上一步才会生效

当我满怀希望, 信誓旦旦去访问时,又心痛了~~~

接着查看 aliyun 防火墙,aliyun server 自带防火墙,默认只开发 80 端口,我们用了其他端口需要去 aliyun 防火墙开放端口才行

再试试,泪目~~ 总算可以访问了

配置 Jenkins

Jenkins 给我们提供了网页配置界面 爱了 爱了

进入登录页面后,Jenkins 提示我们需要输入超级管理员密码进行解锁。根据提示,我们可以在/var/lib/jenkins/secrets/initialAdminPassword文件里找到密码。

tail /var/lib/jenkins/secrets/initialAdminPassword

找到密码后,复制密码,粘贴到 Jenkins 解锁页面,点击Continue继续初始化配置。短暂的等待后,进入插件安装页面。

这里我们点击的 Install suggested plugins,安装默认插件,当然你也可以点击另一个按钮安装指定的插件。点击后,页面进入了插件下载安装页面。

全部安装完成后,页面自动进入管理员账户注册页面。

输完信息点击 save and finish,进入 Jenkins 欢迎页(此图省了),然后点击 start using Jenkins,进入 Jenkins 主页面。

至此,Jenkins 基本配置完成,大家不要慌~不要慌~,还有事情要做,接下来我们还要对 Jenkins 全局做些其他配置。

在 Github 插件的配置中,点击“高级”按钮,启用 Hook URL,并将 Hook URL 复制出来,并保存刚才的设置,这样他让它可以接受 Github 的请求。

配置 Github 仓库

因为 Github 经常有代码处理动作,需要配置 Github 项目仓库在处理这些动作的同时会发送信号至 Jenkins,才能触发 Jenkins 自动构建。

在"Webhooks"选项卡中,点击"Add webhook",将在 Jenkins 生成的 Hook URL 填入至 Payload URL 中,另外,选择自主事件,events 里选择了 pushes,当 Github 收到了客户端有 Push 动作时,会触发一个 Hook

image-20200326180636869
image-20200326180636869

配置完成后,展示如下

自动打包部署实战

前期准备已经差不多了,实战开始,先送上自动打包 CI 架构图

其实就是文章开头架构图中的**右边 CI 部分的详细版😝~

创建

创建 Jenkins 项目,选择 freestyle project

配置

配置项目,点击 Configure 进入配置页面,进行相关配置

配置 Github 项目的项目 URL: https://github.com/xxxxx/test

配置 Git 仓库地址:https://github.com/xxxxx/test.git

配置构建触发事件

配置构建脚本

保存之后,serve r 里就有了我们的仓库代码了,可以去/var/lib/jenkins/workspace 目录下里查看,或者网页的 workspace 查看,网页查看至少需要构建一次才有。


执行构建

构建完成后,可以去 workspace 里查看 dist 里是否有打包文件

修改 nginx 配置文件,手动打包的时候我们已经配过 nginx 了,指向目录是我们手动 clone 项目的 dist 目录。

接下来我们把 root 指向地址换成 jenkins 创建的项目 dist 目录 /var/lib/jenkins/workspace/hello/dist,重新启动 nginx,访问的就是我们 jenkins 服务创建的项目了

好啦,该写的都写了,该做的也都做了,下面见证奇迹的时刻到了,修改你的代码 =》git push =》 稍等一下,刷新页面看是否成功更新。哇偶~