Skip to content

pantojs/panto

Repository files navigation

panto

NPM version Downloads Build Status Build status Coverage Status Dependency status Dev Dependency status bitHound Overall Score

NPM

See http://www.infoq.com/cn/articles/constructe-tool-optimize-for-complex-web-front-end-projects.

PantoJS is an extremely flexible file transforming engine. It is usually used for building projects, especially web front-end projects.

It works like Grunt or Gulp, but more efficient, powerful and flexible.

Core Features

  • Any building process topology

Panto supports almost any building process

  • Collecting rest files

You can select rest files that not selected by selectors

  • Read a file once at most

Read a file only once, even more than one transforming on a file

  • Transform a file once at most

Avoid duplicated processing

  • Cache at file

Avoid duplicated transforming

  • Incremental file transforming

More efficient watching

Panto vs Grunt/Gulp

Grunt Gulp Panto
Stream task
Topological process
Read once
Accurate cache
Accurate increment

Quick Start

Like Grunt or Gulp, Panto needs a process configurable file pantofile.js in root directory of your project, coffeescript syntax is not supported. A simplest pantofile.js contains:

module.exports = panto => {};

Notice that Panto requires Node.js 6.0.0 or higher, so feel relieved to write ES2015 codes.

Like loading Grunt/Gulp plugins, transformers should be loaded first. A transformer defines how to transform file contents.

module.exports = panto => {
    panto.loadTransformer('read');
    panto.loadTransformer('less');
    panto.loadTransformer('copy');
    panto.loadTransformer('write');
};

The above needs to install some npm packages:

npm install panto panto-transformer-read panto-transformer-less panto-transformer-copy panto-transformer-write --save-dev

Next, we need to define some parameters: cwd/src/output. src and output are relative to cwd:

panto.setOptions({
    cwd: __dirname,
    src: 'src',
    output: 'output'
});

Now we start to define building process. Here we transform .less files as an example:

panto.pick('*.less').read().less().write();

The above codes search .less files in src directory, read them, transform to css format, and write to output. E.g., src/style/foo.less transformed to output/style/foo.less.

Then we copy files other than .less files to output:

panto.rest().copy();

i.e. src/config/c.yml copied to output/config/c.yml.

The total pantofile.js is:

module.exports = panto => {
    panto.loadTransformer('read');
    panto.loadTransformer('less');
    panto.loadTransformer('copy');
    panto.loadTransformer('write');

    panto.setOptions({
        cwd: __dirname,
        src: 'src',
        output: 'output'
    });

    panto.pick('*.less').read().less().write();
    panto.rest().copy();
};

You can use load-panto-transformers to avoid writing many panto.loadTransformer('xxx') statements. time-panto is used for monitor, the simpler pantofile.js is:

module.exports = panto => {
    require('load-panto-transformers')(panto);
    require('time-panto')(panto);

    panto.setOptions({
        cwd: __dirname,
        src: 'src',
        output: 'output'
    });

    panto.pick('*.less').read().less().write();
    panto.rest().copy();
};

At last, for starting tasks in terminal, you need to install panto-cli first:

npm install panto-cli -g

Run:

panto -f pantofile.js

All above are in https://github.com/pantojs/simple-panto-usage.

Transformer

Transformers define logic of how to transform files. Extend panto-transformer to implement a transformer:

const Transformer = require('panto-transformer');

class FooTransformer extends Transformer {
    _transform(file) {
        file.content += 'A';
        return Promise.resolve(file);
    }
    isTorrential() {
      return false;
    }
    isCacheable() {
      return true;
    }
}

module.exports = FooTransformer;

If the files are transformed independently, just implement _transform() function, or else transformAll(), they both return Promise object, distinguished by isTorrential() function. Please see panto-transformer-browserify and panto-transformer-uglify.

If a transformer is idempotent strictly, it's cacheable, isCacheable() returns true. Any factors beyond file content that affect transforming results between two transformings will lead to uncacheable. E.g., for calculating md5 of content, same content result in same md5 value, affected by no factors. As another example, appending current date time to file content result in uncacheable, of course.

Input and output of transformers are files or file arrays. A file is a plain JavaScript object, contains filename and content these two properties at least. You can append other properties too.

Stream

Panto uses stream to define transforming tasks. As a node, streams consist of a directed acyclic graph.

const Stream = require('panto').Stream;
const s1 = new Stream();
const s2 = new Stream();
const s3 = new Stream();
const s4 = new Stream();

s1.connect(s2).connect(s4);
s1.connect(s3);

Above codes construct a topology graph:

A stream needs a transformer as a constructing parameter, or nothing is acceptable too.

new Stream(new Transformer())

By defining topological streams and transformers, you can describe how to build a project easily and clearly. The following is a complicated building process topology:

panto topology

A more typical configurable case:

module.exports = panto => {
	panto.setOptions({
    	cwd: __dirname,
	    src: 'src',
    	output: 'output' // not as same as src
	});

	require('load-panto-transformers')(panto);

	const srcJs = panto.pick('**/*.{js,jsx}').tag('js(x)').read();

	srcJs.babel(clientBabelOptions).write();

	srcJs.babel(serverBabelOptions).write();

	panto.pick('**/*.less').tag('less').read().less().write();

	// node_modules should be processed only once
	panto.pick('node_modules/**/*', true).tag('node_modules').copy();

	panto.rest().tag('others').ignore().copy();
}

API

Panto is available through API:

const panto = require('panto');

panto.setOptions({
    
});

panto.on('start', buildId => {})
    .on('flowstart', ({tag}, flowId) => {})
    .on('flowend', ({tag}, flowId) => {})
    .on('error', (err, buildId) => {})
    .on('complete', (files, buildId) => {})

panto.build().then(() => {
    panto.watch();
});

Options

  • cwd: string, current working directory, default process.cwd()
  • src: string, source directory, default '.'
  • output: output string, file directory, default 'output'
  • binary_resource: string, binary file extensions, e.g. 'zip,tar,jpg', default is same as binary-extensions
  • watch_ignore: array, ignored files when watching, e.g. '["/*.pyc", "/*.class"]', default is []

Boilerplate

Transformers

Some official transformers:

About

PantoJS is an extremely flexible file transforming engine

Resources

License

Stars

Watchers

Forks

Packages

No packages published