Skip to content

Latest commit

 

History

History
306 lines (215 loc) · 10.6 KB

README_CN.md

File metadata and controls

306 lines (215 loc) · 10.6 KB

panto

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

NPM

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

PantoJS 是一个极其灵活的文件转换引擎,通常用于项目的构建和编译,特别是 Web 前端项目。

它比较类似于 GruntGulp,但更高效强大灵活

核心特性

  • 支持任意定义的拓扑构建流程

只要是你能定义出来的构建流程,无论如何复杂,只要是合理的,Panto 都可以支持

  • 支持遗留文件的收集

在选择特定的文件类型后,可以一次性访问到未被选择的其它文件

  • 保证对每个源文件最多读取一次

对于同一个文件存在一个以上不同的处理流程,读取也最只有一次

  • 保证对于每个文件的同样处理流程只有一次

尽最大努力避免重复工作

  • 支持文件级别的精确缓存,最大程度上避免不必要的计算

不必重新构建的文件,尽最大努力利用缓存

  • 支持文件级别的精确增量构建

高效重复构建

与Grunt/Gulp相比

Grunt Gulp Panto
流式任务
拓扑流程
一次读取
精确缓存
精确增量

快速入门

GruntGulp 一样,Panto 也需要在项目根目录下定义流程配置文件 pantofile.js,但不支持 coffeescript 语法。一个最简单的 pantofile.js 内容如下:

module.exports = panto => {};

注意 PantoNode.js 的最低版本要求是 6.0.0,因此可以放心使用 ES2015 的语法。

接着,就像加载 Grunt/Gulp 的插件一样,需要先加载_转换器(Transformer)_。转换器定义了如何变换文件内容的逻辑。

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

以上需要使用npm加载相应的package:

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

下面先要定义几个参数:cwdsrcoutput。其中 srcoutput 相对于 cwd

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

现在开始定义构建流程,这里以转换less文件为例:

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

这个流程的意义是在 src 目录内搜索以 .less 为扩展名的文件,并读取其内容,转换为CSS格式,并写入 output 的对应目录内。比如 src/style/foo.less,转换后写入 output/style/foo.less

现在,我们把除了less文件以外的其它文件拷贝到 output 中:

panto.rest().copy();

那么 src/config/c.yml 拷贝至 output/config/c.yml

现在,完整的构建配置文件的内容是:

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();
};

你可以使用 load-panto-transformers 来避免书写大量 panto.loadTransformer('xxx') 语句,同时你也可以使用 time-panto 来监控构建信息,这样,简化并完整的 pantofile.js 是:

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();
};

最后,为了在命令行环境下调用构建任务,你需要先安装 panto-cli

npm install panto-cli -g

在命令行中执行:

panto -f pantofile.js

以上示例请参考 https://github.com/pantojs/simple-panto-usage

转换器

转换器(Transformer) 定义了如何转换文件的逻辑。实现一个 Transformer 可以继承自 panto-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;

如果文件的转换是相互独立的,那么实现 _transform 方法即可,否则需要实现 transformAll 方法,它们都返回 Promise 对象,两种转换器使用 isTorrential() 方法来区分。具体请参见 panto-transformer-browserifypanto-transformer-uglify 的不同实现。

如果转换器是严格幂等的,则是可缓存的,这通过 isCacheable() 方法来区分。任何可能通过文件内容之外其它因素导致两次转换结果不一致的情景,都不能是可缓存的。例如,计算内容md5值的逻辑,只要内容相同,md5值即是一样的,不涉及任何其它因素,这就是可缓存的。再例如,为文件增加当前时间的时间戳内容,则一定是不可缓存的。

转换器的输入和输出都是文件对象或者是集合。文件对象是一个纯JavaScript对象(PlainObject),至少包含 filenamecontent 两个属性,你也可以增加其它属性。

Panto 使用流(Stream)来定义转换任务。作为节点,流可以构建为任意的有向无环图。

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);

以上代码构建的拓扑图如下:

流以一个转换器为构造参数,但也可以不传入任何参数。

new Stream(new Transformer())

通过定义拓扑流和转换器,可以简洁和清晰地描述如何构建一个项目。下面是一个复杂的构建流程示例:

panto topology

一个更典型的配置案例:

module.exports = panto => {
	panto.setOptions({
    	cwd: __dirname,
	    src: 'src',
    	output: 'output' // 不可以与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 的文件只需处理一次
	panto.pick('node_modules/**/*', true).tag('node_modules').copy();

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

API

Panto 也可以使用 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();
});

选项

  • cwd: 字符串,当前工作目录,默认同 process.cwd()
  • src: 字符串,源码目录,默认 '.'
  • output: 文件输出目录,默认 'output'
  • binary_resource: 字符串,二进制文件扩展名,如 'zip,tar,jpg',默认同 binary-extensions
  • watch_ignore: 数组,忽略的文件监视类型,如 '["/*.pyc", "/*.class"]',默认 []

模板

转换器

一些官方的转换器: