bee

xml build tool write in Node

npm install bee
2 downloads in the last day
2 downloads in the last week
28 downloads in the last month

bee

一个前端build工具

Unit Test (the service down?)

travis build status

Usage

npm install bee -g

Summary

一个bee工程可以包含多个task,一个task可以依赖多个其它task,当执行某个task,其依赖的task会现执行,其设计模式跟ant类似。

build.xml所在文件夹下执行:

bee

或者执行某个文件中的某个特殊的任务:

bee publish -f ./build/publish.xml

build.xml文件:

<?xml version='1.0' encoding='utf-8'?>
<project name='using bee to build a project example'  basedir='.'>
  <description>clean, create, combo</description>
  <!-- 可以包含properties文件 -->
  <property file="version.properties"/>
  <property name="src" value="../src"/>
  <property name='build' value='../dist'/>
  <!--clean-->
  <target name='clean'>
    <delete dir='${build}'/>
  </target>
  <!--create-->
  <target name="create">
    <mkdir dir='${build}'/>
  </target>
  <!--combo-->
  <target name='combo'>
    <concat dir='${src}/css' file='dialog.css,photoswipe.css,slider.css,app.css'
         destfile='${build}/css/combo.css'/>
  <target>
  <!--default-->
  <target name='build' depends='clean,create,combo'/>
</project>

Why XML?

  • XML是国际标准格式,具有严谨的格式规范,编写起来简单明了,学习门槛低。
  • 作为通用的数据格式,便于程序动态生成和建模,为可视化编辑提供支持。
  • 支持注释。

Config

bee project有name, description, level等属性

  • name 项目名次
  • description 项目描述
  • level 日志level,可以是log, info, debug, warn, error。默认是debug,即项目运行过程中不会输出loginfo信息到控制台。

npm

在build过程中,可能需要自定义脚本,这些脚本或许依赖某个npm包。基于这个需求场景,bee支持在build启动时根据配置来自动下载npm包。

<npm>node-uploader,node-uuid</npm>

安装到全局:

<npm>coffee-script</npm>

taskdef

在build过程中,很有可能依赖第三方npm插件,所以使用taskdef能很方便的加载使用到的插件,插件的下载和装配过程是bee自动完成的。

<taskdef npm="bee-less,bee-min@0.3.0"/>

当然也可以使用taskdef自定义插件

<taskdef>path/custom.js</taskdef>

详细的使用方法,可以参考后面的自定义插件这一段。

Tasks

bee内置了一些常用的命令,很多都是从ant工具上获得灵感。除此之外,我们可以很方便地定义自己的命令来扩充功能。

available

判断某个文件或文件夹是否存在

<available target='file-or-dir' property='target-exist'/>

basename

获得某个文件的basename

<basename file='${input}' property='file-basename'/>

dirname

获取某个文件的目录名

<dirname file='${input}' property='file-dirname'/>

extname

获取文件的扩展名

<extname file='${input}' property='file-extname'/>

touch

创建一个文件

<touch file='readme.md'/>
<touch file='readme.txt' permission='755'>text content</touch>

copy

复制某个文件或文件夹

<copy file='src/myfile.js' tofile='build/myfile.js'/>
<copy dir='src/lib' todir='dest'/>

<copy todir='dest'>
  <fileset src='src'>
    <exclude value='.svn'/>
  </fileset>
</copy>

delete

删除文件

<delete file='myfile'/>

<delete>
  <fileset dir="src">
    <exclude value='.svn'/>
  </fileset>
</delete>
<delete>
  <fileset dir='.'>
    <include glob='.svn'/>
  </fileset>
</delete>

mkdir

创建文件夹

<mkdir dir='~/Documents/app/bee-test/example'/>
<mkdir dir='${src}/lib'/>

move

复制某个文件或文件夹

<move file='tmp/myfile.js' tofile='build/myfile.js'/>
<move dir='tmp/lib' todir='dest'/>

<move todir='dest'>
  <fileset src='tmp'>
    <exclude value='.svn'/>
  </fileset>
</move>

rename

重命名某个文件或文件夹

<rename file='myfile.js' destfile='my-file.js'/>

echo

打印字符串控制台

<echo>the server is running on port ${port}.</echo>

exec

执行一段shell脚本

<exec>node myNodeApp.js</exec>

concat

合并文件

<concat files='a.js,b.js,c.js' destfile='combo.js'/>

更多的合并选项。

<concat>
  <!-- 自定义header,并删除每行的行前空白字符 -->
  <header trimleading="yes">
  ========
  header
  ========
  </header>

  <!-- 文件列表 -->
  <file>a.js</file>
  <file dir="optional-dir" name="b.js"/>
  <filelist dir="some-dir">
    <file>m.js</file>
    <file name="n.js"/>
  </filelist>

  <!-- 自定义footer -->
  <footer>
=========
  footer
=========
  </footer>
</concat>

condition

条件处理

<condition property="result">
  <os platform='win32'/>
  <equals arg1='${arg1}' arg2='${arg2}'/>
  <or>
    <available file='myfile'/>
  </or>
</condition>

<condition property='result' if='target-if' unless='target-unless'>
  <os platform='win32'/>
  <equals arg1='${arg1}' arg2='${arg2}'/>
  <or>
    <available file='myfile'/>
  </or>
</condition>

get

通过URL下载某个文件

<get url="https://raw.github.com/colorhook/bee/master/README.md" dest="README.md"/>

input

与用户交互在控制台中输入

<input property='username' message='please type your username?' defaultvalue='default-user'/>
<input property='password' password='true' message='please type your password?'/>
<echo>username: ${username} password: ${password}</echo>

loadfile

载入一个文件

<loadfile file='src/lib/myfile.js' encoding='utf-8' property="content"/>
<echo>${content}</echo>
<!--write to file-->
<touch file="build/lib/myfile.js'>${content}</touch>

replace

替换文件中的某个标识

<!--替换combo.js中的@version@字符串-->
<tstamp property='timestamp'/>
<replace token='@time@' value='${timestamp}' file='combo.js'/>

多值替换。需要注意的是,对于替换?这类正则语义字符需要在token定义中加入\进行转义:

<replace file="replace/hello.txt">
    <replacefilter token="@1@" value="#1#"/>
    <replacefilter token="#1#" value="?1?"/>
    <replacefilter token="\?1\?" value="!1!"/>
    <replacefilter token="!1!" value="z1z"/>
</replace>

sleep

让程序sleep一段时间

<sleep value='1000'/>
<sleep>1000</sleep>

tstamp

获取时间戳

<tstamp property='tstamp' pattern='yyyy-MM-dd HH:mm:ss'/>

node

用node环境执行脚本,在该环境下,存在一个名为bee的全局变量。

<node>
<![CDATA[
console.log(require('os').platform);
//当前运行的project
console.log(bee.project);
]]>
</node>

自定义插件

除了有内置的task插件可以用之外,还可以用第三方插件或者自己定义插件。

使用第三方插件:

less

将less文件编译成css文件

<?xml version='1.0' encoding='utf-8'?>
<project name='using bee-less to build a project example'  basedir='.'>
  <description>less</description>
  <deskdef npm='bee-less'/>
  <target name="build">
    <less src='reset.less' dest='reset.css' encoding='utf-8'/>
  </target>
</project>

datauri

datauri某个css或图片

<?xml version='1.0' encoding='utf-8'?>
<project name='using bee-min to build a project example'  basedir='.'>
  <description>datauri</description>
  <deskdef npm='bee-min'/>
  <target name="build">
    <datauri src='a.css' dest='my-new-dir/a.css'/>
  </target>
</project>

min

压缩优化js、css、图片文件

<?xml version='1.0' encoding='utf-8'?>
<project name='using bee-min to build a project example'  basedir='.'>
  <description>min</description>
  <deskdef npm='bee-min'/>
  <target name="build">
    <min src='reset.css' dest='reset.min.css'/>
    <min file='myfie' destfile='myfile.min.js' type='js'/>
    <min file='logo.png' destfile='logo.png'/>
  </target>
</project>

mail

发送邮件

<?xml version="1.0" encoding="utf-8"?>
<project name="bee mail project" description="bee mail test">

  <property name="user" value="colorhook@gmail.com"/>
  <property name="from" value="colorhook@gmail.com"/>
  <property name="to" value="colorhook@gmail.com"/>

  <target name="default">
    <input setproperty='gmail.password' message='your gmail password? ' password='true'/>
    <echo>${gmail.password}</echo>
    <mail service='Gmail'>
      <auth user='${user}' pass='${gmail.password}'/>
      <message from="${from}" to="${to}">
        <html>
            <![CDATA[
            <b>Hello</b>, <span style='color:red'>bee-mail</span>
            ]]>
        </html>
      </message>
    </mail>
  </target>

</project>

自定义内置插件。

新建一个文件greeting.js,并写入如下代码:

module.exports = function(bee){
  bee.register('greeting', function(options){
    console.log('greeting: ' + options.value);
  });
}

greeting.js相同目录新建一个文件build.xml,并写入如下内容:

<?xml version="1.0" encoding="utf-8"?>
<project name="custom plugin" description="bee example">

  <taskdef file="greeting.js"/>

  <property name='argv' value='Write a custom task without publish to npm'/>

  <target name="build">
    <greeting>${argv}</greeting>
  </target>
</project>

childNodes

如上greeting.js所示,xml定义的task定义会变成object形式的js对象:

<taskName prop1='a'>
  <subprop prop2='b'>
    <key1 prop3='c'>value1</key1>
  </subprop>
</taskName>

经过./XMLParser.js解析之后

module.exports = function(bee){
  bee.register('taskName', function(options){
    /**
    {
      prop1: 'a',
            value: '',
      childNodes: [
        {
                    name: 'subprop',
                    value: {
                        prop2: 'b',
                        value: '',
                        childNodes: [
                            {
                                name: 'key1',
                                value: {
                                    prop3: 'c',
                                    value: 'value1'
                                }
                            }
                        ]
                    }
                }
      ]
    }
    **/
        console.log(options);
  });
}

xml2json的内部实现:

xml2json: function(xml) {
    var obj = {
        childNodes: []
    };
    xml.attributes("*").each(function(attr) {
        obj[attr.localName()] = attr.toString();
    });
    if (xml.hasComplexContent()) {
        xml.children().each(function(child) {
            obj.childNodes.push({
                name: child.localName(),
                value: xu.xml2json(child)
            })
        });
    } else {
        if (!obj.value) {
            obj.value = this.text(xml);
        }
    }
    return obj;
}

Bugs & Feedback

Please feel free to report bugs or feature requests. You can send me private message on [github], or send me an email to: [colorhook@gmail.com]

License

bee is free to use under MIT license.

npm loves you