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.
Panto supports almost any building process
You can select rest files that not selected by selectors
Read a file only once, even more than one transforming on a file
Avoid duplicated processing
Avoid duplicated transforming
More efficient watching
Grunt | Gulp | Panto | |
---|---|---|---|
Stream task | ✘ | ✔ | ✔ |
Topological process | ✘ | ✘ | ✔ |
Read once | ✘ | ✘ | ✔ |
Accurate cache | ✘ | ✘ | ✔ |
Accurate increment | ✘ | ✘ | ✔ |
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.
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.
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:
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();
}
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();
});
process.cwd()
Some official transformers:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。