A server library tries to understand what developers really need.
The philosophy behind NoBone is providing possibilities rather than telling developers what they should do. All the default behaviors are just examples of how to use NoBone. All the APIs should dance together happily. So other than javascript, the idea should be ported to any other language easily.
- Code you program, not configure.
- Built for performance.
- Not only a good dev-tool, but also good at production.
- Supports programmable plugins.
- Cross platform.
- Pure js, supports coffee by default.
Install as an dependency:
npm install nobone
# View a better nobone documentation than Github readme.
node_modules/.bin/nobone --doc
Or you can install it globally:
npm i -g nobone
# View a better nobone documentation than Github readme.
nobone -d
- How to view the documentation with TOC (table of contents) or offline?
If you have installed nobone globally, just execute
nobone --doc
ornobone -d
. If you are on Windows or Mac, it will auto open the documentation.
If you have installed nobone with
npm install nobone
in current directory, executenode_modules/.bin/nobone -d
.
- Why I can't execute the entrance file with nobone cli tool?
Don't execute
nobone
with a directory path when you want to start it with an entrance file.
- Why doesn't the auto-reaload work?
Check if the
process.env.NODE_ENV
is set todevelopment
.
- When serving
jade
orless
, it doesn't work.
These are optinal packages, you have to install them first. For example, if you want nobone to support
jade
:npm install -g jade
.
For more examples, go through the examples folder.
process.env.NODE_ENV = 'development'
nobone = require 'nobone'
port = 8219
# If you want to init without a specific module,
# for example 'db' and 'service' module, just exclude them:
# nobone {
# renderer: {}
# }
# By default it only loads two modules: `service` and `renderer`.
nb = nobone {
db: { db_path: './test.db' }
proxy: {}
renderer: {}
service: {}
}
# Service
nb.service.get '/', (req, res) ->
# Renderer
# It will auto-find the 'examples/fixtures/index.ejs', and render it to html.
# You can also render jade, coffee, stylus, less, sass, markdown, or define custom handlers.
# When you modify the `examples/fixtures/index.ejs`, the page will auto-reload.
nb.renderer.render('examples/fixtures/index.html')
.done (tpl_fn) ->
res.send tpl_fn({ name: 'nobone' })
# Launch express.js
nb.service.listen port, ->
# Kit
# A smarter log helper.
nb.kit.log 'Listen port ' + port
# Open default browser.
nb.kit.open 'http://127.0.0.1:' + port
# Static folder for auto-service of coffeescript and stylus, etc.
nb.service.use nb.renderer.static('examples/fixtures')
# Database
# Nobone has a build-in file database.
# Here we save 'a' as value 1.
nb.db.loaded.done ->
nb.db.exec (jdb) ->
jdb.doc.a = 1
jdb.save('DB OK')
.done (data) ->
nb.kit.log data
# Proxy
# Proxy path to specific url.
nb.service.get '/proxy.*', (req, res) ->
# If you visit "http://127.0.0.1:8013/proxy.js",
# it'll return the "http://127.0.0.1:8013/main.js" from the remote server,
# though here we just use a local server for test.
nb.proxy.url req, res, "http://127.0.0.1:#{port}/main." + req.params[0]
close = ->
# Release all the resources.
nb.close().done ->
nb.kit.log 'Peacefully closed.'
Install nobone globally: npm install -g nobone
# Help info
nobone -h
# Use it as a static file server for current directory.
# Visit 'http://127.0.0.1/nobone' to see a better nobone documentation.
nobone
# Use regex to filter the log info.
# Print out all the log if it contains '.ejs'
log_reg='.ejs' nobone
# Use custom logic to start up.
nobone app.js
watch_persistent=off nobone app.js
# Scaffolding helper
nobone bone -h
Here I give a simple instruction. For a real example, see nobone-sync.
NoBone support a simple way to implement npm plugin. And your npm package doesn't have to waist time to install nobone dependencies. The package.json
file can only have these properties:
{
"name": "nobone-sample",
"version": "0.0.1",
"description": "A sample nobone plugin.",
"main": "main.coffee"
}
The name
of the plugin should prefixed with nobone-
.
The main.coffee
file may looks like:
{ kit } = require 'nobone'
kit.log 'sample plugin'
Suppose we have published the nobone-sampe
plugin with npm.
Other people can use the plugin after installing it with either npm install nobone-sample
or npm install -g nobone-sample
.
To run the plugin simply use nobone sample
.
You can use nobone ls
to list all installed plugins.
It's highly recommended reading the API doc locally by command nobone --doc
NoBone has several modules and a helper lib.
All the modules are optional.
Only the kit
lib is loaded by default and is not optional.
Most of the async functions are implemented with [Promise][Promise]. [Promise]: https://github.com/petkaantonov/bluebird
Main constructor.
-
param:
modules
{ Object }By default, it only load two modules,
service
andrenderer
:{ service: {} renderer: {} db: null proxy: null lang_dir: null # language set directory }
-
param:
opts
{ Object }Other options.
-
return: { Object }
A nobone instance.
Release the resources.
-
return: { Promise }
The NoBone client helper.
-
static:
-
param:
opts
{ Object }The options of the client, defaults:
{ auto_reload: kit.is_development() lang_current: kit.lang_current lang_data: kit.lang_data host: '' # The host of the event source. }
-
param:
use_js
{ Boolean }By default use html. Default is false.
-
return: { String }
The code of client helper.
It is just a Express.js wrap.
-
extends: { Express }
[Ref][express] [express]: http://expressjs.com/4x/api.html
Create a Service instance.
-
param:
opts
{ Object }Defaults:
{ auto_log: kit.is_development() enable_remote_log: kit.is_development() enable_sse: kit.is_development() express: {} }
-
return: { Service }
The server object of the express object.
-
type: { http.Server }
A Server-Sent Event Manager.
The namespace of nobone sse is /nobone-sse
.
For more info see [Using server-sent events][Using server-sent events].
NoBone use it to implement the live-reload of web assets.
[Using server-sent events]: https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events
-
type: { SSE }
-
property:
sessions
{ Array }The sessions of connected clients.
-
property:
retry
{ Integer }The reconnection time to use when attempting to send the event, unit is ms. Default is 1000ms. A session object is something like:
{ req # The express.js req object. res # The express.js res object. }
-
example:
You browser code should be something like this:
es = new EventSource('/nobone-sse') es.addEventListener('event_name', (e) -> msg = JSON.parse(e.data) console.log(msg)
This event will be triggered when a sse connection started. The event name is a combination of sse_connected and req.path, for example: "sse_connected/test"
-
event: { sse_connected }
-
param:
session
{ SSE_session }The session object of current connection.
This event will be triggered when a sse connection closed.
-
event: { sse_close }
-
param:
session
{ SSE_session }The session object of current connection.
Create a sse session.
-
param:
req
{ Express.req } -
param:
res
{ Express.res } -
return: { SSE_session }
Emit message to client.
-
param:
event
{ String }The event name.
-
param:
msg
{ Object | String }The message to send to the client.
Broadcast a event to clients.
-
param:
event
{ String }The event name.
-
param:
msg
{ Object | String }The data you want to emit to session.
-
param: { String }
[path] The namespace of target sessions. If not set, broadcast to all clients.
An abstract renderer for any content, such as source code or image files. It automatically uses high performance memory cache. This renderer helps nobone to build a passive compilation architecture. You can run the benchmark to see the what differences it makes. Even for huge project the memory usage is negligible.
-
extends: { events.EventEmitter }
Create a Renderer instance.
-
param:
opts
{ Object }Defaults:
{ enable_watcher: kit.is_development() auto_log: kit.is_development() # If renderer detects this pattern, it will auto-inject `nobone_client.js` # into the page. inject_client_reg: /<html[^<>]*>[\s\S]*</html>/i cache_dir: '.nobone/renderer_cache' cache_limit: 1024 file_handlers: { '.html': { default: true ext_src: ['.ejs', '.jade'] extra_watch: { path1: 'comment1', path2: 'comment2', ... } # Extra files to watch. encoding: 'utf8' # optional, default is 'utf8' dependency_reg: { '.ejs': /<%[\n\r\s]*include\s+([^\r\n]+)\s*%>/ '.jade': /^\s*(?:include|extends)\s+([^\r\n]+)/ } compiler: (str, path, data) -> ... } # Simple coffee compiler '.js': { ext_src: '.coffee' compiler: (str, path) -> ... } # Browserify a main entrance file. '.jsb': { type: '.js' ext_src: '.coffee' dependency_reg: /require\s+([^\r\n]+)/ compiler: (str, path) -> ... } '.css': { ext_src: ['.styl', '.less', '.sass', '.scss'] dependency_reg: { '.styl': /@(?:import|require)\s+([^\r\n]+)/ '.less': /@import\s*(?:\(\w+\))?\s*([^\r\n]+)/ '.sass': /@import\s+([^\r\n]+)/ '.scss': /@import\s+([^\r\n]+)/ } compiler: (str, path) -> ... } '.md': { type: 'html' # Force type, optional. ext_src: ['.md', '.markdown'] compiler: (str, path) -> ... } } }
-
return: { Renderer }
The compiler can handle any type of file.
-
context: { File_handler }
Properties:
{ ext: String # The current file's extension. opts: Object # The current options of renderer. dependency_reg: RegExp # The regex to match dependency path. Regex or Table. dependency_roots: Array | String # The root directories for searching dependencies. # The source map informantion. # If you need source map support, the `source_map`property # must be set during the compile process. If you use inline source map, # this property shouldn't be set. source_map: String or Object }
-
param:
str
{ String }Source content.
-
param:
path
{ String }For debug info.
-
param:
data
{ Any }The data sent from the
render
function. when you call therender
directly. Default is an object:{ _: lodash inject_client: kit.is_development() }
-
return: { Promise }
Promise that contains the compiled content.
You can access all the file_handlers here. Manipulate them at runtime.
-
type: { Object }
-
example:
# We return js directly. renderer.file_handlers['.js'].compiler = (str) -> str
The cache pool of the result of file_handlers.compiler
-
type: { Object }
Key is the file path.
Set a static directory proxy. Automatically compile, cache and serve source files for both deveopment and production.
-
param:
opts
{ String | Object }If it's a string it represents the root_dir of this static directory. Defaults:
{ root_dir: '.' # Whether enable serve direcotry index. index: kit.is_development() inject_client: kit.is_development() # Useful when mapping a normal path to a hashed file. # Such as map 'lib/main.js' to 'lib/main-jk2x.js'. req_path_handler: (path) -> decodeURIComponent path }
-
return: { Middleware }
Experss.js middleware.
Render a file. It will auto-detect the file extension and choose the right compiler to handle the content.
-
param:
path
{ String | Object }The file path. The path extension should be the same with the compiled result file. If it's an object, it can contain any number of following params.
-
param:
ext
{ String }Force the extension. Optional.
-
param:
data
{ Object }Extra data you want to send to the compiler. Optional.
-
param:
is_cache
{ Boolean }Whether to cache the result, default is true. Optional.
-
param:
req_path
{ String }The http request path. Support it will make auto-reload more efficient.
-
return: { Promise }
Contains the compiled content.
-
example:
# The 'a.ejs' file may not exists, it will auto-compile # the 'a.ejs' or 'a.html' to html. renderer.render('a.html').done (html) -> kit.log(html) # if the content of 'a.ejs' is '<% var a = 10 %><%= a %>' renderer.render('a.ejs', '.html').done (html) -> html == '10' renderer.render('a.ejs').done (str) -> str == '<% var a = 10 %><%= a %>'
Release the resources.
Release memory cache of a file.
-
param:
path
{ String } -
event: { compile_error }
-
param:
path
{ string }The error file.
-
param:
err
{ Error }The error info.
-
event: { watch_file }
-
param:
path
{ string }The path of the file.
-
param:
curr
{ fs.Stats }Current state.
-
param:
prev
{ fs.Stats }Previous state.
-
event: { file_deleted }
-
param:
path
{ string }The path of the file.
-
event: { file_modified }
-
param:
path
{ string }The path of the file.
Set handler cache.
-
param:
handler
{ File_handler } -
return: { Promise }
Generate a file handler.
-
param:
path
{ String } -
return: { File_handler }
See my [jdb][jdb] project. [jdb]: https://github.com/ysmood/jdb
Create a JDB instance.
-
param:
opts
{ Object }Defaults:
{ db_path: './nobone.db' }
-
return: { Jdb }
A promise object that help you to detect when the db is totally loaded.
- type: { Promise }
For test, page injection development. A cross platform Fiddler alternative. Most time used with SwitchySharp.
-
extends: { http-proxy.ProxyServer }
Create a Proxy instance.
-
param:
opts
{ Object }Defaults:
{ }
-
return: { Proxy }
For more, see [node-http-proxy][node-http-proxy] [node-http-proxy]: https://github.com/nodejitsu/node-http-proxy
Use it to proxy one url to another.
-
param:
req
{ http.IncomingMessage } -
param:
res
{ http.ServerResponse } -
param:
url
{ String }The target url forced to. Optional. Such as force 'http://test.com/a' to 'http://test.com/b', force 'http://test.com/a' to 'http://other.com/a', force 'http://test.com' to 'other.com'.
-
param:
opts
{ Object }Other options. Default:
{ bps: null # Limit the bandwidth byte per second. global_bps: false # if the bps is the global bps. agent: custom_http_agent }
-
param:
err
{ Function }Custom error handler.
-
return: { Promise }
Http CONNECT method tunneling proxy helper. Most times used with https proxing.
-
param:
req
{ http.IncomingMessage } -
param:
sock
{ net.Socket } -
param:
head
{ Buffer } -
param:
host
{ String }The host force to. It's optional.
-
param:
port
{ Int }The port force to. It's optional.
-
param:
err
{ Function }Custom error handler.
-
example:
nobone = require 'nobone' { proxy, service } = nobone { proxy:{}, service: {} } # Directly connect to the original site. service.server.on 'connect', proxy.connect
A pac helper.
-
param:
curr_host
{ String }The current host for proxy server. It's optional.
-
param:
rule_handler
{ Function }Your custom pac rules. It gives you three helpers.
url # The current client request url. host # The host name derived from the url. curr_host = 'PROXY host:port;' # Nobone server host address. direct = "DIRECT;" match = (pattern) -> # A function use shExpMatch to match your url. proxy = (target) -> # return 'PROXY target;'.
-
return: { Function }
Express Middleware.
All the async functions in kit
return promise object.
Most time I use it to handle files and system staffs.
-
type: { Object }
kit extends all the promise functions of [fs-more][fs-more]. [fs-more]: https://github.com/ysmood/fs-more
-
example:
kit.readFile('test.txt').done (str) -> console.log str kit.outputFile('a.txt', 'test').done()
The lodash lib.
-
type: { Object }
An throttle version of Promise.all
, it runs all the tasks under
a concurrent limitation.
-
param:
limit
{ Int }The max task to run at the same time. It's optional. Default is Infinity.
-
param:
list
{ Array | Function }If the list is an array, it should be a list of functions or promises, and each function will return a promise. If the list is a function, it should be a iterator that returns a promise, when it returns
undefined
, the iteration ends. -
param:
save_resutls
{ Boolean }Whether to save each promise's result or not. Default is true.
-
param:
progress
{ Function }If a task ends, the resolve value will be passed to this function.
-
return: { Promise }
-
example:
urls = [ 'http://a.com' 'http://b.com' 'http://c.com' 'http://d.com' ] tasks = [ -> kit.request url[0] -> kit.request url[1] -> kit.request url[2] -> kit.request url[3] ] kit.async(tasks).then -> kit.log 'all done!' kit.async(2, tasks).then -> kit.log 'max concurrent limit is 2' kit.async 3, -> url = urls.pop() if url kit.request url .then -> kit.log 'all done!'
Creates a function that is the composition of the provided functions.
Besides it can also accept async function that returns promise.
It's more powerful than _.compose
.
-
param:
fns
{ Function | Array }Functions that return promise or any value. And the array can also contains promises.
-
return: { Function }
A composed function that will return a promise.
-
example:
# It helps to decouple sequential pipeline code logic. create_url = (name) -> return "http://test.com/" + name curl = (url) -> kit.request(url).then -> kit.log 'get' save = (str) -> kit.outputFile('a.txt', str).then -> kit.log 'saved' download = kit.compose create_url, curl, save # same as "download = kit.compose [create_url, curl, save]" download 'home'
Daemonize a program.
-
param:
opts
{ Object }Defaults: { bin: 'node' args: ['app.js'] stdout: 'stdout.log' stderr: 'stderr.log' }
-
return: { Porcess }
The daemonized process.
A simple decrypt helper
-
param:
data
{ Any } -
param:
password
{ String | Buffer } -
param:
algorithm
{ String }Default is 'aes128'.
-
return: { Buffer }
A simple encrypt helper
-
param:
data
{ Any } -
param:
password
{ String | Buffer } -
param:
algorithm
{ String }Default is 'aes128'.
-
return: { Buffer }
A shortcut to set process option with specific mode, and keep the current env variables.
-
param:
mode
{ String }'development', 'production', etc.
-
return: { Object }
process.env
object.
A log error shortcut for kit.log(msg, 'error', opts)
-
param:
msg
{ Any } -
param:
opts
{ Object }
A better child_process.exec
.
-
param:
cmd
{ String }Shell commands.
-
param:
shell
{ String }Shell name. Such as
bash
,zsh
. Optinal. -
return: { Promise }
Resolves when the process's stdio is drained.
-
example:
kit.exec """ a=10 echo $a """ # Bash doesn't support "**" recusive match pattern. kit.exec """ echo **/*.css """, 'zsh'
See my project [fs-more][fs-more]. [fs-more]: https://github.com/ysmood/fs-more
A scaffolding helper to generate template project.
The lib/cli.coffee
used it as an example.
-
param:
opts
{ Object }Defaults:
{ src_dir: null patterns: '**' dest_dir: null data: {} compile: (str, data, path) -> compile str }
-
return: { Promise }
See the https://github.com/isaacs/node-glob
-
param:
patterns
{ String | Array }Minimatch pattern.
-
param:
opts
{ Object }The glob options.
-
return: { Promise }
Contains the path list.
See my [jhash][jhash] project. [jhash]: https://github.com/ysmood/jhash
It will find the right key/value
pair in your defined kit.lang_set
.
If it cannot find the one, it will output the key directly.
-
param:
cmd
{ String }The original text.
-
param:
name
{ String }The target language name.
-
param:
lang_set
{ String }Specific a language collection.
-
return: { String }
-
example:
lang_set = cn: China: '中国' open: formal: '开启' # Formal way to say 'open'. casual: '打开' # Casual way to say 'open'. jp: human: '人間' 'find %s men': '%sっ人が見付かる' kit.lang('China', 'cn', lang_set) # -> '中国' kit.lang('open|casual', 'cn', lang_set) # -> '打开' kit.lang('find %s men', [10], 'jp', lang_set) # -> '10っ人が見付かる'
-
example:
Supports we have two json file in
langs_dir_path
folder.- cn.js, content:
module.exports = { China: '中国' }
- jp.coffee, content:
module.exports = 'Good weather.': '日和。'
kit.lang_load 'langs_dir_path' kit.lang_current = 'cn' 'China'.l # '中国' 'Good weather.'.lang('jp') # '日和。' kit.lang_current = 'en' 'China'.l # 'China' 'Good weather.'.lang('jp') # 'Good weather.'
- cn.js, content:
Language collections.
-
type: { Object }
-
example:
kit.lang_set = { 'cn': { 'China': '中国' } }
Current default language.
-
type: { String }
-
default:
'en'
Load language set directory and save them into
the kit.lang_set
.
-
param:
dir_path
{ String }The directory path that contains js or coffee files.
-
example:
kit.lang_load 'assets/lang' kit.lang_current = 'cn' kit.log 'test'.l # -> '测试'. kit.log '%s persons'.lang([10]) # -> '10 persons'
For debugging use. Dump a colorful object.
-
param:
obj
{ Object }Your target object.
-
param:
opts
{ Object }Options. Default: { colors: true, depth: 5 }
-
return: { String }
Nobone use it to check the running mode of the app.
Overwrite it if you want to control the check logic.
By default it returns the rocess.env.NODE_ENV == 'development'
.
-
return: { Boolean }
Nobone use it to check the running mode of the app.
Overwrite it if you want to control the check logic.
By default it returns the rocess.env.NODE_ENV == 'production'
.
-
return: { Boolean }
A better log for debugging, it uses the kit.inspect
to log.
You can use terminal command like log_reg='pattern' node app.js
to
filter the log info.
You can use log_trace='on' node app.js
to force each log end with a
stack trace.
-
param:
msg
{ Any }Your log message.
-
param:
action
{ String }'log', 'error', 'warn'.
-
param:
opts
{ Object }Default is same with
kit.inspect
Monitor an application and automatically restart it when file changed. When the monitored app exit with error, the monitor itself will also exit. It will make sure your app crash properly.
-
param:
opts
{ Object }Defaults:
{ bin: 'node' args: ['app.js'] watch_list: ['app.js'] mode: 'development' }
-
return: { Process }
The child process.
Node version. Such as v0.10.23
is 0.1023
, v0.10.1
is 0.1001
.
-
type: { Float }
Open a thing that your system can recognize. Now only support Windows, OSX or system that installed 'xdg-open'.
-
param:
cmd
{ String }The thing you want to open.
-
param:
opts
{ Object }The options of the node native
child_process.exec
. -
return: { Promise }
When the child process exits.
-
example:
# Open a webpage with the default browser. kit.open 'http://ysmood.org'
String padding helper.
-
param:
str
{ Sting | Number } -
param:
width
{ Number } -
param:
char
{ String }Padding char. Default is '0'.
-
return: { String }
-
example:
kit.pad '1', 3 # '001'
A comments parser for coffee-script. Used to generate documentation automatically. It will traverse through all the comments.
-
param:
module_name
{ String }The name of the module it belongs to.
-
param:
code
{ String }Coffee source code.
-
param:
path
{ String }The path of the source code.
-
param:
opts
{ Object }Parser options:
{ comment_reg: RegExp split_reg: RegExp tag_name_reg: RegExp type_reg: RegExp name_reg: RegExp name_tags: ['param', 'property'] description_reg: RegExp }
-
return: { Array }
The parsed comments. Each item is something like:
{ module: 'nobone' name: 'parse_comment' description: 'A comments parser for coffee-script.' tags: [ { tag_name: 'param' type: 'string' name: 'code' description: 'The name of the module it belongs to.' path: 'http://the_path_of_source_code' index: 256 # The target char index in the file. line: 32 # The line number of the target in the file. } ] }
Node native module
Block terminal and wait for user inputs. Useful when you need in-terminal user interaction.
-
param:
opts
{ Object } -
return: { Promise }
Contains the results of prompt.
The promise lib.
-
type: { Object }
Much much faster than the native require of node, but you should follow some rules to use it safely.
-
param:
module_name
{ String }Moudle path is not allowed!
-
param:
done
{ Function }Run only the first time after the module loaded.
-
return: { Module }
The module that you require.
A powerful extended combination of http.request
and https.request
.
-
param:
opts
{ Object }The same as the [http.request][http.request], but with some extra options:
{ url: 'It is not optional, String or Url Object.' body: true # Other than return `res` with `res.body`, return `body` directly. redirect: 0 # Max times of auto redirect. If 0, no auto redirect. # Set null to use buffer, optional. # It supports GBK, Shift_JIS etc. # For more info, see https://github.com/ashtuchkin/iconv-lite res_encoding: 'auto' # It's string, object or buffer, optional. When it's an object, # The request will be 'application/x-www-form-urlencoded'. req_data: null auto_end_req: true # auto end the request. req_pipe: Readable Stream. res_pipe: Writable Stream. }
And if set opts as string, it will be treated as the url. [http.request]: http://nodejs.org/api/http.html#http_http_request_options_callback
-
return: { Promise }
Contains the http response object, it has an extra
body
property. You can also get the request object by usingPromise.req
, for example:p = kit.request 'http://test.com' p.req.on 'response', (res) -> kit.log res.headers['content-length'] p.done (body) -> kit.log body # html or buffer kit.request { url: 'https://test.com' body: false } .done (res) -> kit.log res.body kit.log res.headers
A safer version of child_process.spawn
to run a process on Windows or Linux.
It will automatically add node_modules/.bin
to the PATH
environment variable.
-
param:
cmd
{ String }Path of an executable program.
-
param:
args
{ Array }CLI arguments.
-
param:
opts
{ Object }Process options. Same with the Node.js official doc. Default will inherit the parent's stdio.
-
return: { Promise }
The
promise.process
is the child process object. When the child process ends, it will resolve.
Node native module
Watch a file. If the file changes, the handler will be invoked.
You can change the polling interval by using process.env.polling_watch
.
Use process.env.watch_persistent = 'off'
to disable the persistent.
For samba server, we have to choose watchFile
than watch
.
variable.
-
param:
path
{ String }The file path
-
param:
handler
{ Function }Event listener. The handler has these params:
- file path
- current
fs.Stats
- previous
fs.Stats
- if its a deletion
-
param:
auto_unwatch
{ Boolean }Auto unwatch the file while file deletion. Default is true.
-
return: { Function }
The wrapped watch listeners.
-
example:
process.env.watch_persistent = 'off' kit.watch_file 'a.js', (path, curr, prev, is_deletion) -> if curr.mtime != prev.mtime kit.log path
Watch files, when file changes, the handler will be invoked.
It takes the advantage of kit.watch_file
.
-
param:
patterns
{ Array }String array with minimatch syntax. Such as
['*/**.css', 'lib/**/*.js']
. -
param:
handler
{ Function } -
return: { Promise }
It contains the wrapped watch listeners.
-
example:
kit.watch_files '*.js', (path, curr, prev, is_deletion) -> kit.log path
Watch directory and all the files in it. It supports three types of change: create, modify, move, delete.
-
param:
opts
{ Object }Defaults:
{ dir: '.' pattern: '**' # minimatch, string or array # Whether to watch POSIX hidden file. dot: false # If the "path" ends with '/' it's a directory, else a file. handler: (type, path, old_path) -> }
-
return: { Promise }
-
example:
# Only current folder, and only watch js and css file. kit.watch_dir { dir: 'lib' pattern: '*.+(js|css)' handler: (type, path) -> kit.log type kit.log path watched_list: {} # If you use watch_dir recursively, you need a global watched_list }
See the doc/changelog.md file.
npm test
Memory cache is faster than direct file streaming even on SSD machine. It's hard to test the real condition, because most of the file system will cache a file into memory if it being read lot of times.
Type | Performance |
---|---|
memory | 1,225 ops/sec ±3.42% (74 runs sampled) |
stream | 933 ops/sec ±3.23% (71 runs sampled) |
Type | Performance |
---|---|
crc buffer | 5,903 ops/sec ±0.52% (100 runs sampled) |
crc str | 54,045 ops/sec ±6.67% (83 runs sampled) |
jhash buffer | 9,756 ops/sec ±0.67% (101 runs sampled) |
jhash str | 72,056 ops/sec ±0.36% (94 runs sampled) |
Type | Time | Collision |
---|---|---|
jhash | 10.002s | 0.004007480630510286% (15 / 374300) |
crc32 | 10.001s | 0.004445855827246745% (14 / 314900) |
Decouple libs.
Better test coverage.
May 2014, Yad Smood