在前端工程化方面我们使用的各种工具,绝大部分都是使用 Nodejs
写的。
比如,打包工具 webpack 及 rollup;前端框架 Vue 自带的脚手架工具 vue-cli;以及 CSS 样式工具scss、less等等。
在日常工作中难免会遇到一些需求,需要自己创建一个脚手架工具来提升整个团队的研发部署效率。
目前,npm上汇集了大量优秀的开发脚手架的第三库,熟练掌握这些库,可以大大提升我们的开发效率。本文将介绍一些在开发前端脚手架方面非常常用的第三方库,希望能帮助到你。
npmlog
这个工具用来定制各种打印日志,比如颜色,字体粗细等,让打印的日志更加清晰。
js
var log = require('npmlog')
// additional stuff ---------------------------+
// message ----------+ |
// prefix ----+ | |
// level -+ | | |
// v v v v
log.info('fyi', 'I have a kitty cat: %j', myKittyCat)
它主要包括:日志级别(info),前缀(prefix),打印信息(message)。
level
level 表示日志的级别,在此级别或以上的任何日志都将被显示。
它的默认级别是info
,它还有其他的级别,比如:
js
log.addLevel('silly', -Infinity, { inverse: true }, 'sill')
log.addLevel('verbose', 1000, { fg: 'blue', bg: 'black' }, 'verb')
log.addLevel('info', 2000, { fg: 'green' })
log.addLevel('timing', 2500, { fg: 'green', bg: 'black' })
log.addLevel('http', 3000, { fg: 'green', bg: 'black' })
log.addLevel('notice', 3500, { fg: 'blue', bg: 'black' })
log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN')
log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!')
级别的大小通过数字表示,info的级别大小是2000。
我们还可以增加 level,比如增加了 success,它的级别是2000:
js
log.addLevel('success', 2000, { fg: 'green', bold: true })
下面的代码执行打印 info 级别的日志,因为目前的级别是 info ,verbose的级别是1000比2000小,所以不会打印出来。
js
log.level = 'info'
log.verbose()
log.info()
还可以设置前缀:
js
log.heading = 'yijing'
log.headingStyle = { fg: 'red', bg: 'white' }
// 打印
log.success('test', 'success')
dotenv
它能将从.env
文件里面设置的环境变量加载到 process.env
中。
所谓环境变量就是一个全局变量,不管在哪个位置都能访问到这个变量
使用方法非常简单,步骤如下:
- 在项目中安装 dotenv
- 根目录下创建 .env 文件
js
FOO=BAR
- 使用
js
require('dotenv').config({ path: '.env' })
console.log(process.env.FOO) // BAR
使用 dotenv
可以让我们免于在各个文件中引入配置文件,也可以很好的解决敏感信息的泄漏,利于后期代码维护
semver
用于版本号相关的操作。
javascript
const semver = require('semver')
// 验证是否是合法的版本号
semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
// 规范版本号
semver.clean(' =v1.2.3 ') // '1.2.3'
// 筛选满足条件的版本号
// '1.x || >=2.5.0 || 5.0.0 - 7.2.3'是筛选条件
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
// 比对版本号的大小
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
// 小于等于 大于等于
semver.lte
semver.gte
minimist
它的作用是进行命令行参数解析。
首先需要先了解下process.argv
:
js
node process-argv.js one two=three four
// process.argv 输出:
0: /usr/local/bin/node // process.execPath
1: /Users/mjr/work/node/process-args.js // 脚本文件的地址
2: one
3: two=three
4: four
我们常用process.argv.slice(2)
来获取参数。再来看minimist
的用法及例子:
js
const args = require('minimist')(process.argv.slice(2))
node test.js -a a -b b
// args: {_: [], a: 'a', b: 'b'}
node test.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
// { _: [ 'foo', 'bar', 'baz' ],
// x: 3,
// y: 4,
// n: 5,
// a: true,
// b: true,
// c: true,
// beep: 'boop' }
minimist 会解析参数,并放到一个对象中,方便在脚本中读取。特别要说明的是其中首个key是_
,它的值是个数组,包含的是所有没有关联选项的参数。
colors
colors
是一个纯粹的设置node.js console
颜色的库。chalk
这个库是改变打印文字的颜色,两个库都差不多。
js
const colors = require('colors/safe')
// 文字为红色
console.log(colors.red('当前用户主目录不存在'))
fs-extra
这个框架是对 node fs
模块的封装,并提供了promise的支持。在使用时,你不必再引用const fs = require('fs')
,而是直接引用const fse = require('fs-extra')
。
这个库的每个方法当然也包括同步和异步,它们的使用如下:
javascript
const fs = require('fs-extra')
// Async with promises: 异步primoise形式
fs.copy('/tmp/myfile', '/tmp/mynewfile')
.then(() => console.log('success!'))
.catch(err => console.error(err))
// Async with callbacks: 异步callback形式
fs.copy('/tmp/myfile', '/tmp/mynewfile', err => {
if (err) return console.error(err)
console.log('success!')
})
// Sync: 同步
try {
fs.copySync('/tmp/myfile', '/tmp/mynewfile')
console.log('success!')
} catch (err) {
console.error(err)
}
// Async/Await: 通过async/await进行同步的写法,本质还是异步
async function copyFiles () {
try {
await fs.copy('/tmp/myfile', '/tmp/mynewfile')
console.log('success!')
} catch (err) {
console.error(err)
}
}
copyFiles()
url-join
将所有参数连接在一起,并规范化结果URL。
js
import urlJoin from 'url-join';
const fullUrl = urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123');
console.log(fullUrl); // 'http://www.google.com/a/b/cd?foo=123'
pkg-dir
找到 npm 项目中package.json
所在的目录:
js
└── Users
└── sindresorhus
└── foo
├── package.json
└── bar
├── baz
└── example.js
javascript
import {packageDirectory} from 'pkg-dir';
console.log(await packageDirectory());
// '/Users/sindresorhus/foo'
cli-spinner
脚手架开发中如果要安装一个比较大的文件,此时最好有一个 loading 效果,cli-spinner
的功能就是在命令行中产生一个loading效果。
js
function spinnerStart(msg, spinnerString = '|/-\\') {
const Spinner = require('cli-spinner').Spinner
const spinner = new Spinner(msg + ' %s')
spinner.setSpinnerString(spinnerString)
spinner.start()
return spinner
}
const spinner = spinnerStart('正在下载模板...')
// 进程暂停1s,查看效果
await sleep()
spinner.stop(true)
inquirer
交互式的命令行信息收集器。
js
{
type: 'input' // 交互组件类型
name: 'name' // 数据属性名称
message: '用户名' // 交互提示
default: '' // 默认值
choices: '' // 当交互类型为`选择类型`时, 该属性配置可选项目
// 校验函数, 函数以当前回答为参数。 返回: true 通过 false 不通过,无提示 Error
validate(value){
return !value.length ? new Error('项目名称不能为空') : true
}
// 过滤器, 返回修改后的回答。优先级高于 `validte`
filter(value){
return /vue/.test(value) ? `${value}-demo` : value
}
// 转换器, 返回转换后的值,只作为显示,不影响收集结果
transformer(value){
return /vue/.test(value) ? `${value}-demo` : value
}
}
validate
如果不通过,按照上面的写法是不会给用户提示的,为了当用户输错时,给用户提示需要这么写:
js
const projectNamePrompt = {
type: 'input',
name: 'projectName',
message: `请输入${title}名称`,
default: '',
validate: function (v) {
const done = this.async()
setTimeout(function () {
if (!isValidateName(v)) {
done(`请输入合法的${title}名称`)
return
}
done(null, true)
}, 0)
},
filter: function (v) {
return v
}
}
glob
glob
最早是出现在类Unix系统的命令行中, 是用来匹配文件路径的。比如,lib/**/*.js
匹配 lib 目录下所有的 js 文件。
除了在命令行中,我们在程序中也会有匹配文件路径的需求。于是,很多编程语言有了对 glob 的实现 ,如 Python 中的 glob
模块; php 中的 glob
方法。
nodejs中没有对glob
进行实现,但是我们可以安装glob
这个库进行使用。
js
const glob = require('glob')
glob(
// 匹配所有js文件
'**/*.js',
{
// 排除node_modules下的所有文件
ignore: ['node_modules/**']
},
function (err, files) {
console.log(files)
}
)
kebab-case
把驼峰形式转化为中划线形式。
perl
var kebabCase = require("kebab-case");
kebabCase("WebkitTransform");
// "-webkit-transform"
kebabCase.reverse("-webkit-transform");
// "WebkitTransform"
以上介绍的第三方库都是开发前端脚手架经常用到的,熟练使用它们能提升你的开发速度和效率。