让NodeJS在项目中发光发热系列文章, 没看过这个的朋友建议先看一下,否则直接这个可能会有点吃力。html
最近离职了,闲着也是闲着。就想起来了以前Node
相关的文章还有一部分没写,恰好有时间,今天给续上。现现在的前端开发,经过Node
能够高度自定义的为咱们的项目打造一条龙服务。既然一条龙那么不只仅是开发阶段,打包以后的事情,咱们也要处理。这篇文章就聊一聊打包以后的一些用得上的hooks
。一样的这篇文章也是抛砖引玉的做用,文章里涉及的都是一些简单的部分,深层次的骚操做还要各位朋友本身去挖掘。前端
首先来看一下大体的效果vue
准备一个项目,Vue/React/Angular
的均可以,咱们这里以vue-base-template为项目模板node
由于我使用的是Vue-cli3.0
版本的脚手架,它打包的命令是经过vue-cli-service build
命令来执行。npm
直接运行的话咱们就无法加hooks
了, 全部咱们本身写一个Node
脚原本执行打包命令, 在scripts
文件夹下新建build.js
,这个脚本用来组织咱们全部的打包相关东西。git
build.js
的职责其实很简单:github
hooks
有了需求再去写功能,对你们来讲都是小case,下面就来实现这三个需求。vue-cli
这个参数就是咱们在命令行中输入的参数,也就是package.json scripts
中写好的参数,例如npm
"scripts": { "build": "node scripts/build.js --mode production" }
这里咱们暂时不对参数作特殊的处理,仅仅取出来给打包命令用,若是你须要复杂的参数建议你使用commander.js,我这个项目如今还没涉及到复杂的打包参数。因此直接使用process.argv
取出来就好了,关于process
具体使用感兴趣能够本身看看文档json
const scriptArgv = process.argv.slice(2) // 删除node scripts/build.js const args = scriptArgv.join(' ') // 组装成正常格式
这个对Node
来讲,这个很简单。经过child_process
就能完美实现,我比较懒,直接用了tasksfile这个库。你也能够本身采用原生Node
写,不过要注意异步的问题。segmentfault
const { sh } = require('tasksfile') // 同步执行打包命令 sh(`vue-cli-service build ${args}`, { silent: false })
Hooks
,这就是执行个方法。下面是build.js
中所有的代码。
const ora = require('ora') const { sh } = require('tasksfile') const { Notify } = require('./util') const builtHooks = require('./build-hooks') const scriptArgv = process.argv.slice(2) const args = scriptArgv.join(' ') const spinner = ora(`building for ${process.env.NODE_ENV}...\n`) spinner.start() // real pack command sh(`vue-cli-service build ${args}`, { silent: false }) // build success spinner.succeed("打包完成") // notify Notify.showNotify("打包完成", "即将进行下一步操做") // delay 2s setTimeout(() =>{ // run hooks builtHooks() },2000)
这个发挥的空间有点大,大部分都是为了提高咱们的效率的,我就写几个我本身认为经常使用一点的。
在执行完build.js
的前两步以后,接着就会运行hooks
。由于hooks
脚本存在的目的是为开发者最大可能性的节约时间。因此就设计为了非强制性的选项。
首先新建文件build-hooks.js
第一步设计hooks
选项,一样的使用咱们的老朋友inquirer
const builtHooks = () => { inquirer.prompt([ { type: 'list', message: `检测到production环境打包完成,请选择下一步操做`, name: 'next', choices: [ { name: '退出脚本', value: 0 }, { name: '发布到服务器', value: 1 }, { name: '本地预览', value: 2 }, { name: '生成Zip文件', value: 3 }, { name: '备份Zip文件到本地', value: 4 } ] } ]).then(answers => { afterHooks.get(answers.next)() }) }
第二步设计不一样选项对应的行为
const afterHooks = new Map([ [0, () => { Log.logger('退出程序') process.exit(0) }], [1, () => { Log.logger('即将进行发布🎈') require('./deploy') }], [2, () => { Log.logger('开始本地预览💻') require('./server') }], [3, async () => { Log.logger('开始压缩zip文件👜') await FileUtil.zipDir() }], [4, async () => { Log.logger('开始备份Zip文件到本地📦') await Backup.doBackup() }] ])
是否是很是简单,简洁易懂哈哈哈。 下面咱们来看一下具体的操做实现细节
这个在这里就不说了, 能够直接看这里。
简单问题了,无非是在本地搭建一个轻量级的Web
服务器, 用第三方库实现的话就更简单了。代码以下server.js
const http = require('http') const fs = require('fs') const path = require('path') const { Log } = require('./util') const httpPort = 8088 const filePath = path.resolve(__dirname, '../dist/index.html') const open = require('open') // create current http server http.createServer((req, res) => { Log.logger(req.url) try { const content = fs.readFileSync(filePath, 'utf-8') // deal resource if (req.url.indexOf('static') !== -1 || req.url.indexOf('vendor') !== -1 || req.url == "/favicon.ico") { const data = fs.readFileSync(path.resolve(__dirname, `../dist${req.url}`)) return res.end(data) } // index.html res.setHeader('Content-Type','text/html;charset=utf-8') res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) res.end(content) } catch (error) { Log.error('We cannot open "index.htm" file.') } }).listen(httpPort, async () => { const location = `http://localhost:${httpPort}` Log.success(`Server listening on: ${location}, Open in the browser after 3 seconds`) // open default browser setTimeout(async ()=> { // 自动打开默认浏览器 await open(location) }, 3000) })
效果以下:
这个也没什么好说的😂, 就是经过Node
压缩dist
文件夹,在这里我用了[zip-local]()来实现需求(你也可使用Node
实现, 可是我比较懒哈哈哈)代码以下
/** * 压缩文件夹 * @param {*} dir 要压缩的文件夹 默认 ROOTPATH.distDir * @param {*} zipedPath 压缩以后 的zip存放路径 */ static async zipDir (dir = ROOTPATH.distDir, zipedPath = ROOTPATH.distZipPath) { try { if(fs.existsSync(zipedPath)) { Log.logger('zip已经存在, 即将删除压缩包') fs.unlinkSync(zipedPath) } else { Log.logger('即将开始压缩zip文件') } await zipper.sync.zip(dir).compress().save(zipedPath); Log.success('文件夹压缩成功') } catch (error) { Log.error(error) Log.error('压缩dist文件夹失败') } }
压缩+备份(就是复制一份文件到指定文件夹)
我在深思熟虑以后仍是决定把备份给加上,我反正是吃过没备份的亏😂, 这个选项会为咱们在backups
文件目录下生成一个新的以当前日期命名的压缩文件。
熟悉Node
的文件系统的话这个对你们来讲就很简单了。backup.js
代码以下:
const path = require('path') const { FileUtil, StringUtil, DateUtil, ROOTPATH, Log, Notify } = require('./util') class Backup { /** * @author: etongfu * @description: 清空全部备份 */ static clearBackups () { } /** * @author: etongfu * @description: 执行备份 * @param {type} {*} * @returns: {*} */ static async doBackup () { try { // 文件名是当前日期 精确到秒 let date = StringUtil.trim(DateUtil.getCurrentDate("YYYY-MM-DD hh:mm:ss"), 1) date = StringUtil.replaceAll(date,"-", "") date = StringUtil.replaceAll(date,":", "") let targetPath = path.resolve(__dirname, `../backups/${date}.backup.zip`) if(FileUtil.fileExist(targetPath)) { return Log.warning(`${targetPath}已存在,已放弃备份`) } // Zip File await FileUtil.zipDir(ROOTPATH.distDir, targetPath) Log.success(`本地备份完成, 文件:${targetPath}`) Notify.showNotify("本地备份", `本次备份完成, 文件地址:${targetPath}`) } catch (error) { Log.error(`备份文件失败:${error}`) } } } module.exports = Backup
效果以下:
其实hooks彻底没必要和打包耦合在一块儿,彻底能够拆出来使用,不过这个是下一个版本的需求哈哈哈😀。写完这些脚本再亲身使用了一段时间以后,真的感受能够节省下来很多时间。免去了一些繁琐的手工操做。推荐你们尝试一下,毕竟自定义程度贼高,为团队造福。
原文地址 若是以为有用得话给个⭐吧