Skip to content

NVerban/runjs

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

runjs node version Build Status npm version Gitter

Minimalistic building tool

Get started

Install globally (for a command line script):

npm install runjs -g

Install in your project (to use runjs api inside your runfile.js):

npm install runjs --save-dev

If you want to use Babel, install it. RunJS will pickup your babel-register automatically.

npm install babel-core babel-preset-es2015 babel-register --save-dev

Configure Babel in your package.json:

"babel": {
  "presets": ["es2015"]
}

Create runfile.js:

import {run} from 'runjs';

export const build = {
  js () {
    run('webpack -p --config config/webpack/prod.js --progress');
  },
  
  css () {
    
  },
  
  all () {
    build.js()
    build.css()
  }
}

export function createcomponent (name) {
  
}

export function lint (path = '.', options = {}) {
  options.fix ? run(`eslint ${path} --fix`) : run(`eslint ${path}`) 
}

Run:

run createcomponent AppContainer
run build:js
run build:all
run lint --fix components/Button.js

Mechanism of RunJS is very simple. Tasks are run by just importing runfile.js as a normal node.js module. Then based on command line arguments a proper exported function from runfile.js is run.

Why runjs ?

We have Grunt, Gulp, npm scripts, Makefile. Why another building tool ?

Gulp or Grunt files seem overly complex for what they do and the plugin ecosystem adds a layer of complexity towards the simple command line tools underneath. The documentation is not always up to date and the plugin does not always use the latest version of the tool. After a while customizing the process even with simple things, reconfiguring it becomes time consuming.

Npm scripts are simple but they get out of hand pretty quickly if we need more complex process which make them quite hard to read.

Makefiles are simple, better for more complex processes but they depend on bash scripting. Within runfile you can use command line calls as well as JavaScript code and npm libraries which makes that approach much more flexible. Additionally each task and command call is reported in the console.

Handling arguments

Provided arguments in the command line are passed to the function:

export function sayHello (who) {
  console.log(`Hello ${who}!`)
}
$ run sayHello world
Hello world!

You can also provide dash arguments like -a or --test. Order of them doesn't matter after task name but they will be always passed as a last argument in a form of JSON object.

export function sayHello (who, options) {
  console.log(`Hello ${who}!`)
  console.log('Given options:', options)
}
$ run sayHello -a --test=something world
Hello world!
Given options: { a: true, test: 'something' }

API

For inside runfile.js usage

import {run, generate} from 'runjs';

run(cmd, options)

run given command as a child process and log the call in the output. ./node_modules/.bin/ is included into PATH so you can call installed scripts directly.

Options:

{
    cwd: ..., // current working directory (String)
    async: ... // run command asynchronously (true/false), false by default
    stdio: ... // 'inherit' (default), 'pipe' or 'ignore'
    env: ... // environment key-value pairs (Object)
    timeout: ...
}

Examples:

To get an output from run function we need to set stdio option to pipe otherwise output will be null:

const output = run('ls -la', {stdio: 'pipe'})
run('http-server .', {async: true, stdio: 'pipe'}).then((output) => {
  log(output) 
}).catch((error) => {
  throw error
})

For stdio: 'pipe' outputs are returned but not forwarded to the parent process thus not printed out to the terminal. For stdio: 'inherit' (default) outputs are passed to the terminal, but run function will resolve (async) / return (sync) null.

generate(src, dst, context)

generate a file specified by dst path by given template file src and context object

file1.tmp.js:

{
    author: '<%= AUTHOR %>'
}
generate('file1.tmp.js', 'file1.js', {AUTHOR: 'Pawel'});

will generate file1.js:

{
    author: 'Pawel'
}

ask(question)

Gather information from the user.

import { ask } from 'runjs'

export function prompt () {
  ask('Who are you?').then((name) => {
    console.log(`Hello ${name}!`) 
  })
}
$ run prompt
Who are you? Pawel
Hello Pawel!

Using Babel

If you have Babel and babel-register already installed, RunJS will pick up it automatically and use it for you runfile.js. If RunJS not finds babel-register it will fallback to pure node.

RunJS performs better with npm>=3.0 when using with Babel. It is because new version of npm handles modules loading much more effective.

If you have very specific location for your babel-register, you can define a path to it through config in your package.json (default path is ./node_modules/babel-register):

"runjs": {
    "babel-register": "./node_modules/some_package/node_modules/babel-register"
}

Scaling

When runfile.js gets large it is a good idea to extract some logic to external modules and import them back to runfile.js:

./tasks/css:

export function compile () {
  ...
}

./tasks/lint:

export function fix () {
  ...
}

./tasks/common:

export function serve () {
  ...
}

runfile.js:

import { run } from 'runjs'
import lint from './tasks/lint'
import css from './tasks/css'
import common from './tasks/common'

export default {
  css, // equals to css: css
  lint, // equals to lint: lint
  ...common,
  clean: () => {
    run('rm -rf node_modules') 
  },
  deploy: {
    'production': () => {
      
    },
    'staging': () => {
      
    }
  }
}
run css:compile
run lint:fix
run serve
run clean
run deploy:production
run staging:staging

You can notice a couple of approaches here but in general RunJS will treat object key as a namespace. It is also possible to bump tasks directly without the namespace by using ES7 object spread operator as with common tasks in the example above.

Documenting tasks

To display all available tasks from your runfile.js type run in your command line without any arguments:

$ run
Requiring babel-register...
Processing runfile...

Available tasks:
echo
testapi

Add doc property to your task to get additional description:

import { run } from 'runjs'

export function buildjs () {
  
}

buildjs.doc = 'Compile JavaScript files'
$ run
Requiring babel-register...
Processing runfile...

Available tasks:
buildjs - Compile JavaScript files

About

Minimalistic building tool

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 97.0%
  • Shell 3.0%