使用 fjpublish 发布前端项目(基础篇) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
manman51

使用 fjpublish 发布前端项目(基础篇)

  •  1
     
  •   manman51 2017 年 11 月 18 日 3413 次点击
    这是一个创建于 3077 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本系列文章共分为基础篇,安全篇,拓展篇。

    前言

    曾几何时,我相信部分 Web Developer (包括我)使用的项目发布方式比较传统(使用 xftp 或者 sublime text 的插件 sftp 等),发布方式简单又粗暴,想发布哪个目录就直接上传覆盖...

    但是这种方式对于现在的前端项目有些弊端:

    • 若项目包含 webpack\gulp 等构建工具,则每次发布都需要等待构建完成后再手动上传,效率低;

    • 若项目为前端的服务端渲染项目,例如 vue 的服务端渲染,那么项目上传服务器后还得登录服务器重启进程;

    • 发布时由于选错文件或者选错发布环境导致的上传(><)悲剧,可没有后悔药吃。

    我知道你想告诉我还可以使用 git webhook 等自动化工具,的确这是一种比较高级的用法,也非常可靠,但是搭建过程对于新手还是比较麻烦的,而且前端还是不太同于服务端,前端项目大多需要构建,那么构建过程究竟放在服务端还是本地,这是一个问题。

    我理想中的发布器应该是易于搭建,通过配置文件就能选择发布到不同的环境,敲完一行发布命令就可以去泡杯茶,让它自己完成整个发布流程。

    于是,fjpublish就诞生了。它是一个不同于 git webhook 的发布思路,基于 nodejs 的能力自动化整个发布流程,顺便把 git 提交一下...

    安装

    如果你已经安装了 nodejs (6.0+),那么只需要一个命令就能完成 fjpublish 的安装

    npm install fjpublish -g 

    全局安装就可以在任意路径下使用 fjpublish 这个命令了。 注意: fjpublish 依赖一份配置文件,默认是 fjpublish.config.js ,如果不想在版本库中提交服务器安全信息,请千万记得把它加入忽略文件中,如.gitignore

    配置文件结构

    fjpublish 命令行默认会读取当前工作目录下的fjpublish.config.js文件,该文件返回一个对象,举例结构如下:

    module.exports = { //modules 开始 modules: [{ name: '测试环境', //标识要发布的环境描述 env: 'test', //发布环境的唯一标识 ssh: { host: '12.23.345.678', //远程服务器 ip username: 'root', //登录服务器的用户名 //rc 版本的 user 选项和 userName 选项请在未来统一配置为 username password: '12345678', //登录服务器的密码 }, buildCommand: 'build', //要进行构建的命令 build => npm run build localPath: 'example', //项目中要发布的目录 remotePath: '/www/example', //项目中要发布到远程服务器的目录 tag: '123' //标注发布的版本,可不设置 }, { ... }], //modules 结束 nobuild: true, //modules 外的字段可用于每一个 module 继承,这里仅用于举例 tag: 'v1', //modules 外的字段可用于每一个 module 继承,这里仅用于举例 } 

    以上展示了一个简单的配置,关于使用 fjpublish 和阅读本文档,还需明白以下几个概念:

    • modules 数组中每一个对象(也称module)代表一个发布环境,在本文档中module指在配置文件中任意一个环境配置 module

    • 在本文档中config指代 module.exports 输出的所有字段(包含 modules 在内)的对象。

    • config中 modules 字段外的字段在初始后将并入每一个module,优先级为module > config,也可以理解为module继承自config

    • config中 modules 字段外的字段不仅仅为了继承给module 实例也可以是为了定义某些全局的配置字段。

    听起来好像一头雾水,建议看完例子再重新理解以上内容

    例子

    让我们闲话少说,先上几个例子来了解 fjpublish 能做什么。

    1. 简单例子

    发布一个项目文件到远程环境,并备份旧文件。

    任务描述

    • 以提示器的方式选择发布到测试环境

    配置文件

    // 项目根目录下 fjpublish.config.js module.exports = { modules: [{ name: '测试环境', env: 'test', ssh: { host: '192.168.0.xxx', username: 'root', //rc 版本的 user 选项和 userName 选项请在未来统一配置为 username password: 'xxxxxx', }, buildCommand: 'webpack', localPath: 'example', remotePath: '/www/manman/test', },{ name: '预发布环境', env: 'pre_release', //剩余配置参考‘测试环境’ },{ name: '正式环境', env: 'pre_release', //剩余配置参考‘测试环境’ }] } 
    // 项目根目录下 package.json // 用于使用构建命令 npm run webpack 来调用 webpack ... "scripts": { "webpack": "webpack --config example/webpack/build/build.js" }, ... 

    发布命令

    fjpublish env -s 

    动态图

    <center><font color="#999" size="1">简单例子</font></center>

    更多内容

    • 可以使用命令fjpublish env <env> --diff开启差异化发布,每次发布只上传有改动的文件,极大的缩短上传时间。

    • 对于不需要构建的项目,不需要准备 package.json,并在配置文件中设置nobuild选项;

    nobuild: true 
    • 对于某次发布临时不需要构建的,请在命令中使用--nobuild选项
    fjpublish env <env> --nobuild 

    2. 多目录发布

    有些时候我们的项目需要发布的文件夹不止一个,或者需要忽略某些文件,那么就需要调整发布方式。

    任务描述

    • 使用modulelocalPathEntries来发布多个目录;

    • 使用modulelocalPathIgnore忽略所有 txt 结尾的文件。

    项目文件结构

    配置文件

    // 项目根目录下 fjpublish.config.js module.exports = { modules: [{ name: '测试环境', env: 'test', ssh: { host: '192.168.0.xxx', username: 'root', //rc 版本的 user 选项和 userName 选项请在未来统一配置为 username password: 'xxxxx', }, buildCommand: 'webpack', localPathEnries: ['example', 'lib'], localPathIgnore: '**/*.txt', remotePath: '/www/manman/multiple', }], } 

    发布命令

    fjpublish env test 

    动态图

    <center><font color="#999" size="1">多目录发布</font></center>

    更多

    • 如果把配置改一下,那么发布的项目结构将完全不同,那么聪明的你猜猜修改上文配置的localPathlocalPathEntries会发生什么吧;
    ... localPath: 'example/webpack', //当 localPathEntries 存在时 localPath 可不填,不填意味着项目根目录 localPathEntries: ['build', 'dist'], ... 
    • 若项目为多目录发布,则远程目录的备份规则也将变为以这些子目录为备份源。

    3. 远程后置命令

    对于需要重启服务的项目,fjpublish 也是支持的。

    任务描述

    • 使用module的配置项postCommands在项目发布后重启 pm2 进程;

    • 忽略当次构建过程并提交一次 git ;

    • 使用module的配置项ssh2shell设置每个远程命令超时时间为 20 秒。

    配置文件

    // 项目根目录下 fjpublish.config.js module.exports = { modules: [{ name: '测试环境', env: 'test', ssh: { host: '192.168.0.xxx', username: 'root', //rc 版本的 user 选项和 userName 选项请在未来统一配置为 username password: 'xxxxxx', }, ssh2shell: { idleTimeOut: 20000 }, postCommands: ['pm2 reload xxx'], buildCommand: 'build', localPath: 'example', remotePath: '/www/manman/test', }] } 

    发布命令

    fjpublish env test --nobuild --commit '远程后置命令' 

    动态图

    <center><font color="#999" size="1">远程后置命令</font></center>

    4.快速还原

    有备份项目的功能那当然得有还原的办法啦。

    任务描述

    • 还原版本预发布环境至tag标记为‘自定义 tag 的版本’的版本;

    配置文件

    // 项目根目录下 fjpublish.config.js module.exports = { modules: [{ name: '预发布环境', env: 'pre_release', ssh: { //略 }, localPath: 'example', remotePath: '/www/zhangchao/pre_release', }], } 

    还原命令

    fjpublish recover pre_release 

    动态图

    <center><font color="#999" size="1">快速还原</font></center>

    更多

    • 可以使用命令fjpublish recover pre_release -p, --previous 快速还原至上个版本而不需要选择;

    • 可以使用选项recoverTemplate自定义版本列表模板;

    • 快速还原一样也会执行postCommands配置的后置命令。

    结语

    以上的例子描述了fjpublish中最基本的功能,fjpublish 也有强大拓展能力,感兴趣的童鞋可以直接移步官方文档了解更多,别忘了在 github 上给我点个star哦。

    下一期我们将谈论如何使用 fjpublish 进行安全发布,拜拜∩__∩y。

    fjpublish 官方交流群:608809145

    11 条回复    2017-11-19 11:09:46 +08:00
    bramblex
        1
    bramblex  
       2017 年 11 月 18 日
    虽然这种轮子已经有很完善的, 不过造轮子不易, 给个 star 支持一下吧
    manman51
        2
    manman51  
    OP
       2017 年 11 月 18 日
    @bramblex 谢谢,之前是没找到这种类似方案才决定造一个轮子。
    Loerise
        3
    Loerise  
       2017 年 11 月 18 日
    @bramblex 还有什么其他的,说说,我研究下呢,谢谢。
    ibegyourpardon
        4
    ibegyourpardon  
       2017 年 11 月 18 日
    大多数轮子在造的时候可能还真没考虑过这个问题,就是前端和部分后端有一个特性差异在于,前端有个构建过程。

    需要通过一个构建过程完成了,才能得到我要的可调式的工程代码(还不见得是最终在浏览器里执行的代码),这个构建过程放在哪里,本地跑还是服务器跑,各有利弊。

    都用 hook 或者 git 的方式甩到服务器上去,让服务器做这件事当然可以,对源码管理倒也变得简单了,但在调试的时候有麻烦多多。在本地构建的话,代码混杂,源码和构建编译后的代码发布过去的位置还不一样,还最好能统一在一套系统里一起做完。

    这也是为啥大家总是找轮子却又总觉得别人的不尽如人意的原因之一,别人的总归很难那么好的适配到自己所用的那套流程里。

    当然,等回头试完楼主这套东西,估计我也会参考下,然后再造个自己的轮子了。。。
    manman51
        5
    manman51  
    OP
       2017 年 11 月 18 日
    @ibegyourpardon 相比而言,我喜欢把构建过程放在本地,也懒得折腾 webhook
    zhlssg
        6
    zhlssg  
       2017 年 11 月 18 日 via iPhone
    从流程上来说,发布通过 webhook 自动构建还是省心的,如果从多人协作的角度,两种方式那种更优?
    manman51
        7
    manman51  
    OP
       2017 年 11 月 18 日
    @zhlssg 懒得学 webhook 就用 fjpublish 咯,和协作不协作也没啥关系。
    zhlssg
        8
    zhlssg  
       2017 年 11 月 18 日 via iPhone
    @manman51 协作的话不是涉及到发布权限的问题嘛?
    rashawn
        9
    rashawn  
       2017 年 11 月 19 日 via iPhone
    还可以前端只用 js 写 更新的时候只需要把 js 更新到 cdn
    manman51
        10
    manman51  
    OP
       2017 年 11 月 19 日
    @zhlssg 配置文件是被忽略的,且 fjpublish 解决的是开箱即用的问题,目标用户不是已经有好的发布方案的开发者。
    manman51
        11
    manman51  
    OP
       2017 年 11 月 19 日
    @rashawn 是的,但是也有不用 cdn 的项目,且测试环境总不能也上 cdn 吧。fjpublish 也可以配置钩子函数来自动化发布 cdn,我觉得发布和 cdn 解耦开比较合适。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5512 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 89ms UTC 07:16 PVG 15:16 LAX 00:16 JFK 03:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86