1.config-lite
config-lite 是一个轻量的读取配置文件的模块。config-lite 会根据环境变量(NODE_ENV)的不同从当前执行进程目录下的 config 目录加载不同的配置文件。如果不设置 NODE_ENV,则读取默认的 default 配置文件,如果设置了 NODE_ENV,则会合并指定的配置文件和 default 配置文件作为配置,config-lite 支持 .js、.json、.node、.yml、.yaml 后缀的文件。
如果程序以NODE_ENV=test node app启动,则通过require(‘config-lite’)会依次降级查找config/test.js、config/test.json、config/test.node、config/test.yml、config/test.yaml并合并 default 配置;
如果程序以NODE_ENV=production node app启动,则通过require(‘config-lite’)会依次降级查找config/production.js、config/production.json、config/production.node、config/production.yml、config/production.yaml并合并 default 配置
用法:
const config = require('config-lite')(__dirname);// orconst config = require('config-lite')({filename: 'test',config_basedir: __dirname,config_dir: 'config'});
options:
- filename: 配置文件名, 默认:
default, 支持:['.js', '.json', '.node', '.yaml', '.yml', '.toml']. - config_basedir: 开始冒泡查找配置目录的目录
- config_dir: 配置目录名称, 默认:
config - config: 覆盖配置文件的默认配置对象
2.http-proxy-middleware
用于后台将请求转发给其他服务器,用于把请求代理转发到其他服务器的中间件
例如:
当前主机A为http://localhost:3000/,现在浏览器发送一个请求,请求接口/api,这个请求的数据在另个一台服务器B(http://192.192.10.11:4000)上,这时就可通过A主机设置代理,直接将请求发送给B主机。
简单实现代码如下:
var express = require('express')var proxy = require('http-proxy-middleware')var app = express()app.use('/api', proxy({target: 'http://192.192.10.11:4000', changeOrigin: true}))app.listen(3000)
说明:利用express在3000端口启动了一个小型服务器,利用了app.use('/api', proxy({target: 'http://192.192.10.11:4000', changeOrigin: true}))这句话,使发到3000端口的/api请求转发到了4000端口。即请求http://localhost:3000/api相当于请求http://192.192.10.11:4000/api
用法和接口说明
1. proxy([context,] config)
var proxy = require('http-proxy-middleware');var apiProxy = proxy('/api', {target: 'http://www.example.org'});// \____/ \_____________________________/// | |// 需要转发的请求 目标服务器// 'apiProxy' 现在已经准备作为一个中间件了。
- options.target: target 由协议和主机组成
说明:第一个参数是可以省略的
2. proxy(uri [, config])
// 上例的简洁写法
var apiProxy = proxy('http://www.example.org/api');
下边示例是用Express构建的服务器中用法:
// 引用依赖
var express = require('express')
var proxy = require('http-proxy-middleware')
// proxy 中间件的选择项
var options = {
target: 'http://www.example.org', // 目标服务器 host
changeOrigin: true, // 默认false,是否需要改变原始主机为目标 url
ws: true, // 是否代理 websockets
pathRewrite: {
'^/api/old-path': '/api/new-path', // 重写请求,比如我们源访问的是 api/old-path, 那么请求会被解析为api/new-path
'^/api/remove/path' : '/path' // 同上
},
router: {
// 如果请求主机 == 'dev.localhost:3000'
// 重写目标服务器 'http://www.example.org' 为 'http://localhost:8080'
'dev.localhost:3000': 'http://localhost:8080'
}
}
// 创建代理
var exampleProxy = proxy(options)
// 使用代理
var app = express()
app.use('/api', exampleProxy)
app.listen(3000)
参数详解:
1. [context]详解
上下文匹配
假如你不能使用主机的路径参数来创建代理,或者你需要更灵活的方式来创建代理的话,这里提供了选择性的方式来决定哪些请求会被转发;
下边是一个完整地址划分:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
协议 主机 路径 查询 碎片
第一个参数主要设置要代理的路径,该参数具有如下用法:
- 可以省略
proxy({...}): 匹配任何路径,所有请求将被转发 - 可以设置为路径字符串
proxy('/', {...}): 匹配任何路径,所有请求将被转发
proxy('/api', {...}): 匹配/api开头的请求 - 可以设置为数组
proxy(['/api', '/ajax', '/something'], {...}): 匹配多个路径 - 可以设置为函数(自定义配置规则) ```javascript var filter = function (pathname, req) { return (pathname.match(‘^/api’) && req.method === ‘GET’) }
var apiProxy = proxy(filter, {target: ‘http://www.example.org'})
1. 可以设置为通配符<br />
细粒度的匹配可以使用通配符匹配,`Glob` 匹配模式由 `micromatch`创造,访问 `micromatch` or `glob` 查找更多用例。
- proxy('**', {...}) 匹配任何路径,所有请求将被转发;
- proxy('**/*.html', {...}) 匹配任何以.html结尾的请求;
- proxy('/*.html', {...}) 匹配当前路径下以html结尾的请求;
- proxy('/api/**/*.html', {...}) 匹配/api下以html为结尾的请求;
- proxy(['/api/**', '/ajax/**'], {...}) 组合
- proxy(['/api/**', '!**/bad.json'], {...}) 不包括**/bad.json
<a name="0hi30"></a>
#### 2. config详解
```javascript
// proxy 中间件的选择项
var options = {
target: 'http://www.example.org', // 目标服务器 host
changeOrigin: true, // 默认false,是否需要改变原始主机为目标 url
ws: true, // 是否代理 websockets
pathRewrite: {
'^/api/old-path': '/api/new-path', // 重写请求,比如我们源访问的是 api/old-path, 那么请求会被解析为api/new-path
},
router: {
// 如果请求主机 == 'dev.localhost:3000'
// 重写目标服务器 'http://www.example.org' 为 'http://localhost:8080'
'dev.localhost:3000': 'http://localhost:8080'
}
}
// 创建代理
var exampleProxy = proxy(options)
pathRewrite
重写目标url路径。// 重写 pathRewrite: {'^/old/api' : '/new/api'} // 移除 pathRewrite: {'^/remove/api' : ''} // 添加 pathRewrite: {'^/' : '/basepath/'} // 自定义 pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }router
重写指定请求转发目标// 使用主机或者路径进行匹配,返回最先匹配到结果 // 所以配置的顺序很重要 router: { 'integration.localhost:3000' : 'http://localhost:8001', // host only 'staging.localhost:3000' : 'http://localhost:8002', // host only 'localhost:3000/api' : 'http://localhost:8003', // host + path '/rest' : 'http://localhost:8004' // path only } // 自定义 router: function(req) { return 'http://localhost:8004'; }3. 事件http-proxy-middleware还提供了一些请求监听事件
option.onError
// 监听proxy的onerr事件 proxy.on('error', function (err, req, res) { res.writeHead(500, { 'Content-Type': 'text/plain' }) res.end('Something went wrong.And we are reporting a custom error message') })option.onProxyRes: 监听
proxy的回应事件proxy.on('proxyRes', function (proxyRes, req, res) { console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); });option.onProxyReq:监听proxy的请求事件
proxy.on('proxyReq', function onProxyReq(proxyReq, req, res) { proxyReq.setHeader('x-added', 'foobar'); });option.onProxyReqWs
function onProxyReqWs(proxyReq, req, socket, options, head) { proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); }option.onOpen:监听来自目标服务器的信息
proxy.on('open', function (proxySocket) { proxySocket.on('data', hybiParseAndLogMessage); });option.onClose:展示websocket链接分离
proxy.on('close', function (res, socket, head) { console.log('Client disconnected'); });4. 参考资料
3.opn
用法
const open = require('open');
(async () => {
// 在默认图像查看器中打开图像,等待打开的应用程序退出
await open('unicorn.png', {wait: true});
console.log('图像查看器应用程序退出');
// 在默认浏览器中打开URL
await open('https://sindresorhus.com');
// 在指定的浏览器中打开URL
await open('https://sindresorhus.com', {app: 'firefox'});
// 指定应用参数
await open('https://sindresorhus.com', {app: ['google chrome', '--incognito']});
})();
4.webpack-dev-server
用来快速搭建本地运行环境的工具,命令简单webpack-dev-server或配置命令脚本快捷运行
webpack-dev-server主要是启动了一个使用express的Http服务器。它的作用主要是用来伺服资源文件。此外这个Http服务器和client使用了websocket通讯协议,原始文件作出改动后,webpack-dev-server会实时的编译,但是最后的编译的文件并没有输出到目标文件夹,即output中的配置:
output: {
path: './dist/js',
filename: 'bundle.js'
}
注意:你启动webpack-dev-server后,你在目标文件夹中是看不到编译后的文件的,实时编译后的文件都保存到了内存当中。
**在使用webpack 进行开发的时候,通常是使用webpack-dev-server 进行开发,因为它的热加载,实时更新。而在生产上版本的时候,则是使用wepback命令进行打包,生成一个js 文件。上面的publicPath的使用说法适用于生产环境。当使用webpack命令进行打包上生产时,它确实是在静态资源路径前面加上publicPath的值。 但是当我们使用webpack-dev-server 进行开发时,它却不是在静态文件的路径上加publicPath的值,相反,它指的是webpack-dev-server 在进行打包时生成的静态文件所在的位置。也就是说publicPath的使用是分环境的。
webpack-dev-server会进行打包吗?webpack-dev-server也会进行打包,代码只要一变动,它就会打包,只不过它打包到的地方是计算机的内存,在硬盘中看不到。再具体一点,默认情况下,webpack-dev-server 会把打包后的文件放到项目的根目录下,文件名是在output配置中的filename. 但是当有publicPath 配置的时候,就不一样了。Webpack 会把所有的文件打包到publicPath指定的目录下,就是相当于在项目根目录下创建了一个publicPath目录, 然后把打包成的文件放到了它里面,只不过我们看不到而已, 文件名还是output配置中的filename。
配置
- open: 第一次构建完成时,自动用浏览器打开网页,默认是true
openPage: 配置项用于打开指定 URL 的网页。
openPage: '/different/page'hot: 启用 webpack 的模块热替换特性。DevServer默认的行为是在发现源代码被更新后会通过自动刷新整个页面来做到实现预览,开启模块热替换功能后在不刷新整个页面的情况下通过用心模块替换老模块来实现实时预览。
- host: 用于配置DevServer服务器监听的地址
- proxy: 当您有一个单独的API后端开发服务器,并且想要在同一个域上发送API请求时,则代理这些 url ,解决开发环境的跨域问题
- allowedHosts: 配置一个白名单列表,只有HTTP请求的HOST在列表里才正常返回
- compress: 配置是否启用 gzip 压缩。boolean 为类型,默认为 false
- overlay: 出现编译器错误或警告时,在浏览器中显示全屏覆盖层,默认false
- stats: 用来控制编译的时候shell上的输出内容.
没有设置devServer.stats时候编译输出是这样子的(其中看起来有许多看似不重要的文件也被打印出来了)
stats: “errors-only”表示只打印错误
我们把配置改成:
devServer: {
contentBase: path.join(__dirname, "dist"),
stats: "errors-only"
}
因为只有错误才被打印,所以,大多数信息都略过了
- quiet: 和devServer.stats属于同一类型的配置属性
当它被设置为true的时候,控制台只输出第一次编译的信息,当你保存后再次编译的时候不会输出任何内容,包括错误和警告
5.html-wepack-plugin
基本作用就是生成html文件:
- 为html文件中引入的外部资源如
script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题 - 可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个
html-webpack-plugin可以生成N个页面入口原理: 将 webpack中
entry配置的相关入口chunk 和extract-text-webpack-plugin抽取的css样式 插入到该插件提供的template或者templateContent配置项指定的内容基础上生成一个html文件,具体插入方式是将样式link插入到head元素中,script插入到head或者body中。
实例化该插件时可以不配置任何参数,例如:
var HtmlWebpackPlugin = require('html-webpack-plugin')
webpackconfig = {
...
plugins: [
new HtmlWebpackPlugin()
]
}
配置项
插件提供的配置项比较多,通过源码可以看出具体的配置项如下:
this.options = _.extend({
template: path.join(__dirname, 'default_index.ejs'),
filename: 'index.html',
hash: false,
inject: true,
compile: true,
favicon: false,
minify: false,
cache: true,
showErrors: true,
chunks: 'all',
excludeChunks: [],
title: 'Webpack App',
xhtml: false
}, options);
title: 生成的html文档的标题。配置该项,它并不会替换指定模板文件中的title元素的内容,除非html模板文件中使用了模板引擎语法来获取该配置项值,如下ejs模板语法形式:
<title>{%= o.htmlWebpackPlugin.options.title %}</title>filename: 输出文件的文件名称,默认为index.html,不配置就是该文件名;此外,还可以为输出文件指定目录位置(例如’html/index.html’)。filename的路径是相对于
output.path的,而在webpack-dev-server中,则是相对于webpack-dev-server配置的publicPath。- 如果webpack-dev-server的
publicPath和output.publicPath不一致,在使用html-webpack-plugin可能会导致引用静态资源失败,因为在devServer中仍然以output.publicPath引用静态资源,和webpack-dev-server的提供的资源访问路径不一致,从而无法正常访问。 - 有一种情况除外,就是output.publicPath是相对路径,这时候可以访问本地资源,所以一般情况下都要保证devServer中的
publicPath与output.publicPath保持一致。 - filename配置的html文件目录是相对于webpackConfig.output.path路径而言的,不是相对于当前项目目录结构的。
- 指定生成的html文件内容中的link和script路径是相对于生成目录下的,写路径的时候请写生成目录下的相对路径。
- 如果webpack-dev-server的
- template: 本地模板文件的位置,支持加载器(如handlebars、ejs、undersore、html等)。
template只有定义在webpack的context下才会被识别,webpack context的默认值为process.cwd(),既运行 node 命令时所在的文件夹的绝对路径- template配置项在html文件使用file-loader时,其所指定的位置找不到,导致生成的html文件内容不是期望的内容。
- 为template指定的模板文件没有指定任何loader的话,默认使用ejs-loader。如template: ‘./index.html’,若没有为.html指定任何loader就使用ejs-loader
- templateContent: string|function,可以指定模板的内容,不能与template共存。配置值为function时,可以直接返回html字符串,也可以异步调用返回html字符串。
- inject: 向template或者templateContent中注入所有静态资源,不同的配置值注入的位置不经相同。
- true或者body:所有JavaScript资源插入到body元素的底部
- head: 所有JavaScript资源插入到head元素中
- false: 所有静态资源css和JavaScript都不会注入到模板文件中
- favicon: 添加特定favicon路径到输出的html文档中,这个同
title配置项,需要在模板中动态获取其路径值 hash: true|false,是否为所有注入的静态资源添加webpack每次编译产生的唯一hash值,添加hash形式如下所示
<script type="text/javascript" src="common.js?a3e1396b501cdd9041be"></script>chunk: chunks主要用于多入口文件,当你有多个入口文件,那就回编译后生成多个打包后的文件,那么chunks 就能选择你要使用那些js文件 ```javascript entry: { index: path.resolve(dirname, ‘./src/index.js’), devor: path.resolve(dirname, ‘./src/devor.js’), main: path.resolve(__dirname, ‘./src/main.js’) }
plugins: [ new httpWebpackPlugin({ chunks: [‘index’,’main’] }) ]
编译后:
```html
<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="main.js"></script>
而如果没有指定 chunks 选项,默认会全部引用。
- excludeChunk: 这个与
chunks配置项正好相反,用来配置不允许注入的thunk。 ```javascript entry: { index: path.resolve(dirname, ‘./src/index.js’), devor: path.resolve(dirname, ‘./src/devor.js’), main: path.resolve(__dirname, ‘./src/main.js’) }
plugins: [ new httpWebpackPlugin({ excludeChunks: [‘devor.js’]// 和上面的例子等效 }) ]
编译后:
```html
<script type=text/javascript src="index.js"></script>
<script type=text/javascript src="main.js"></script>
- chunkSortMode: none | auto| function,默认auto; 允许指定的thunk在插入到html文档前进行排序。
- function值可以指定具体排序规则;auto基于thunk的id进行排序; none就是不排序
- xhtml: true|fasle, 默认false;是否渲染
link为自闭合的标签,true则为自闭合标签 - cache: true|fasle, 默认true; 如果为true表示在对应的thunk文件修改后就会emit文件
- showErrors: true|false,默认true;是否将错误信息输出到html页面中。这个很有用,在生成html文件的过程中有错误信息,输出到页面就能看到错误相关信息便于调试。
minify: {….}|false;传递 html-minifier 选项给 minify 输出,false就是不使用html压缩
plugins:[ new HtmlWebpackPlugin({ //部分省略,具体看minify的配置 minify: { //是否对大小写敏感,默认false caseSensitive: true, //是否简写boolean格式的属性如:disabled="disabled" 简写为disabled 默认false collapseBooleanAttributes: true, //是否去除空格,默认false collapseWhitespace: true, //是否压缩html里的css(使用clean-css进行的压缩) 默认值false; minifyCSS: true, //是否压缩html里的js(使用uglify-js进行的压缩) minifyJS: true, //Prevents the escaping of the values of attributes preventAttributesEscaping: true, //是否移除属性的引号 默认false removeAttributeQuotes: true, //是否移除注释 默认false removeComments: true, //从脚本和样式删除的注释 默认false removeCommentsFromCDATA: true, //是否删除空属性,默认false removeEmptyAttributes: true, // 若开启此项,生成的html中没有 body 和 head,html也未闭合 removeOptionalTags: false, //删除多余的属性 removeRedundantAttributes: true, //删除script的类型属性,在h5下面script的type默认值:text/javascript 默认值false removeScriptTypeAttributes: true, //删除style的类型属性, type="text/css" 同上 removeStyleLinkTypeAttributes: true, //使用短的文档类型,默认false useShortDoctype: true, } }), ]
example:
new HtmlWebpackPlugin({
title:'rd平台',
template: 'entries/index.html', // 源模板文件
filename: './index.html', // 输出文件【注意:这里的根路径是module.exports.output.path】
showErrors: true,
inject: 'body',
chunks: ["common",'index']
})
配置多个html页面
html-webpack-plugin的一个实例生成一个html文件,如果单页应用中需要多个页面入口,或者多页应用时配置多个html时,那么就需要实例化该插件多次;
即有几个页面就需要在webpack的plugins数组中配置几个该插件实例:
...
plugins: [
new HtmlWebpackPlugin({
template: 'src/html/index.html',
excludeChunks: ['list', 'detail']
}),
new HtmlWebpackPlugin({
filename: 'list.html',
template: 'src/html/list.html',
thunks: ['common', 'list']
}),
new HtmlWebpackPlugin({
filename: 'detail.html',
template: 'src/html/detail.html',
thunks: ['common', 'detail']
})
]
配置自定义的模板
不带参数的html-webpack-plugin默认生成的html文件只是将thunk和css样式插入到文档中,可能不能满足我们的需求;
另外,如上面所述,三个页面指定了三个不同html模板文件;在项目中,可能所有页面的模板文件可以共用一个,因为html-webpack-plugin插件支持不同的模板loader,所以结合模板引擎来共用一个模板文件有了可能。
所以,配置自定义模板就派上用场了。具体的做法,借助于模板引擎来实现,例如插件没有配置loader时默认支持的ejs模板引擎,下面就以ejs模板引擎为例来说明;
例如项目中有2个入口html页面,它们可以共用一个模板文件,利用ejs模板的语法来动态插入各自页面的thunk和css样式,代码可以这样:
<!DOCTYPE html>
<html style="font-size:20px">
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
<% for (var css in htmlWebpackPlugin.files.css) { %>
<link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet">
<% } %>
</head>
<body>
<div id="app"></div>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
</body>
</html>
自定义模板上下文数据
html-webpack-plugin在生成html文件的过程中,插件会根据配置生成一个对当前模板可用的特定数据,模板语法可以根据这些数据来动态生成html文件的内容。
从源码中可以看出模板引擎具体可以访问的数据如下:
var templateParams = {
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin:
files: assets,
options: self.options
}
};
- compitation: 为所有webpack插件提供的都可以访问的一个编译对象
- webpack: webpack 的stats对象,注意一点:这个可以访问的stats对象是htm文件生成时所对应的stats对象,而不是webpack运行完成后所对应的整个stats对象。
- webpackConfig: 通过这个属性可以获取webpack的相关配置项,如通过
webpackConfig.output.publicPath来获取publicPath配置。当然还可以获取其他配置内容 htmlWebpackPlugin:
html-webpack-plugin插件对应的数据。它包括两部分:htmlWebpackPlugin.files: 此次html-webpack-plugin插件配置的chunk和抽取的css样式。该files值其实是webpack的stats对象的assetsByChunkName属性代表的值,该值是插件配置的chunk块对应的按照webpackConfig.output.filename映射的值。例如对应上面配置插件各个属性配置项例子中生成的数据格式如下:"htmlWebpackPlugin": { "files": { "css": [ "inex.css" ], "js": [ "common.js", "index.js"], "chunks": { "common": { "entry": "common.js", "css": [ "index.css" ] }, "index": { "entry": "index.js", "css": ["index.css"] } } } }这样,就可以是用如下模板引擎来动态输出script脚本:
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script> <% } %>htmlWebpackPlugin.options: 传递给插件的配置项,具体的配置项如上面插件配置项小节所描述的。
6.HappyPack
7.morgan
一个功能非常强大的日志中间件。它能对用户的行为和请求时间进行记录。而这对于分析异常行为和可能的站点崩溃来说非常有用。大多数时候 Morgan 也是 Express 中日志中间件的首选。
相关文档
8.ora
优雅的终端旋转器
const ora = require('ora');
const spinner = ora('Loading unicorns').start();
setTimeout(() => {
spinner.color = 'yellow';
spinner.text = 'Loading rainbows';
}, 1000);
9.body-parser
- node.js body 解析中间件
- 处理程序之前,在中间件中对传入的请求体进行解析(response body)
10.cookie-parser
方便操作客户端中的cookie值引入
```javascript const cookieParser = require(‘cookie-parser’)
app.use(cookieParser(‘123456’)) // 使用cookie中间件,传入签名123456进行加密
<a name="CayYl"></a>
## 设置cookie,需要设置signed签名
```javascript
res.cookies('key', 'value', option)
其中option要求json格式,有以下选项:
- domain: 域名,设置子域名(二级域名)是否可访问cookie。eg: domain: ‘主域名’ name = value键值对,可以设置要保存的key/value,注意这里的name不能和其他属性项的名字一样
- expires:过期时间(秒),在设置的某个时间点后该cookie就会失效
- maxAge: 最大失效时间(毫秒),设置在多少时间后失效
- secure: 当secure为true时,cookie在HTTP中是无效的,在HTTPS中才有效
- path: 表示cookie影响到的路由,如path = /。如果路径不能匹配时,浏览器则不发送这个cookie
- httpOnly: 默认为false,建议设置为true,客户端将无法通过document.cookie读取到cookie信息,可防止XSS攻击产生
- signed:表示签名是否加密cookie,设为true会对这个cookie签名加密,这样就需要用res.signedCookies访问它,前提是需要设置中间件app.use中传参,未签名则用res.cookies访问
- 被篡改的签名cookie会被服务器拒绝,并且cookie值会重置为它的原始值
res.cookies('cart', {item: [1, 2, 3]}, {maxAge: 10000 * 4, signed: true, httpOnly: true})
res.cookies('username', 'caae', {maxAge: 10000 * 2, signed: true})
res.cookies('age', '28', {maxAge: 10000 * 3, signed: true})
获取cookie
console.log(req.signedCookies)
console.log(req.signedCookies.cart)
console.log(req.signedCookies.username)
console.log(req.signedCookies.age)
删除cookie
res.cookie('username', 'caae', {maxAge: 0})
11.minimist
轻量级的命令行参数解析引擎
nodejs的命令行参数解析工具有很多,比如:argparse、optimist、yars、commander。
minimist的特性较全面:
- short options
- long options
- Boolean 和 Number类型的自动转化
- options alias
minimist整体的解析过程,代码大致是:
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (/^--.+=/.test(arg)) {
...
} else if (/^--no-.+/.test(arg)) {
...
} else if (/^--.+/.test(arg)) {
...
} else if (/^-[^-]+/.test(arg)) {
...
} else {
...
}
}
解析过程中,minimist会依次匹配不同的模式,从long options到short options,匹配之后再进行相应的解析工作。
例子:
// test.js
var args = require('minimist')(process.argv.slice(2));
console.log(args.hello);
$ node test.js --hello=world
// world
$ node test.js --hello world
// world
$ node test.js --hello
// true 注意:不是空字符串而是true
不过,minimist在解析接口当中提供的string选项来修改上面的解析过程。string选项可以传入一个数组,数组中的参数会被一直解析成字符串。我们修改一下上面的test.js
// test.js
var args = require('minimist')(process.argv.slice(2), {
string: ['hello']
});
console.log(args.hello);
$ node test.js --hello world
// world
$ node test.js --hello
// ""
minimist还支持boolean、number选项
// test.js
var args = require('minimist')(process.argv.slice(2), {
boolean: ['hello']
});
console.log(args.hello);
$ node test.js --hello world
// true
// [ 'world' ]
$ node test.js
// false
// []
除了string和boolean以外,minimist还提供了default和alias两个选项,分别用来设定默认值和option alias。
