Skip to content

o2team/athena

Repository files navigation

athena-html

node version npm npm GitHub license GitHub stars

O2Team构建项目流程工具,可以生成相应目录和代码,同时对项目进行编译

一次安装,到处运行

功能一览

创建项目

  • 生成项目、模块、页面、组件文件结构

编译预览

  • 轻量组件化功能
  • 根据组件加载情况生成资源依赖表
  • 页面、组件html编译
  • Sass/less 编译
  • CSS合并压缩
  • CSS prefix,px转rem
  • JS合并压缩
  • 自动生成雪碧图,自动多倍图
  • 文件内联,自定义图片转base64
  • 图片压缩
  • 字体压缩
  • 文件MD5戳
  • 本地预览

项目部署

  • 资源定位(图片等资源路径替换)
  • 生成CSS页面片
  • 部署到预览机和开发机

ChangeLog

请见ChangeLog

加入开发

请见开发指引

安装

基于node,请确保已具备较新的node环境(>=4.0.0),推荐使用node版本管理工具nvm,这样不仅可以很方便地切换node版本,而且全局安装时候也不用加sudo了。

安装本项目 athena-html

$ [sudo] npm install -g athena-html

由于国外源实在太慢,建议使用国内源来安装

$ [sudo] npm i -g athena-html --registry=http://registry.npm.taobao.org --disturl=http://npm.taobao.org/mirrors/node

目前已支持sass/less文件的编译,使用sass需要使用ruby安装compass

$ [sudo] gem install compass

由于墙的缘故(你懂的),原始的gem源https://rubygems.org/ 几乎无法使用,建议将gem源替换成 ruby-china 的源

$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$ gem sources -l
*** CURRENT SOURCES ***

https://gems.ruby-china.org
# 请确保只有 gems.ruby-china.org
$ gem install compass

项目结构

一个项目对应一个目录,项目中可以包含多个 模块 ,项目将由以下结构组成

├── module1                 - 模块1
├── module2                 - 模块2
├── module3                 - 模块3
└── app-conf.js             - 项目的配置信息

项目中模块将由以下结构组成

├── dist                    - 通过编译生成的目录
│   ├── output              - 真正用来上线的目录
│       ├── combofile       - publish时用来存放生成页面和页面片文件的目录
│       ├── css             - 通过编译生成的css文件
│       ├── js              - 通过编译生成的js文件
│       ├── images          - 通过编译压缩后的images文件
│       ├── page1.html      - 通过编译生成的页面html
│   ├── map.json            - 通过编译后生成页面/widget依赖关系已经页面引用资源、资源md5对应表
|
├── page                    - 所有页面目录
│   ├── page                - 某一页面目录
│       ├── images          - 页面的图片目录
|       ├── page.json       - 页面的说明文件
│       ├── page.css        - 页面级css
│       ├── page.js         - 页面级js
│       ├── page.html       - 页面html
│
├── static                  - static目录一般用来存放需要引用的第三方的资源文件,需要配合``static-conf.js``来使用
│   ├── css                 - 额外的css文件
│   ├── js                  - 额外的js文件
│   ├── images              - 额外的image文件
│  
├── widget                  - 所有widget目录
│   ├── widget              - 某一widget目录
│       ├── images          - widget的图片目录
|       ├── widget.json     - widget的说明文件
│       ├── widget.css      - widget的css
│       ├── widget.js       - widget的js
│       ├── widget.html     - widget的html
│
├── static-conf.js          - 需要额外引用的静态资源的配置
│
└── module-conf.js          - 模块的配置信息

在这种项目组织方式中,将页面拆分成各个widget组件,在页面中通过加载各个widget的方式来拼装页面,再经过编译,生成正常页面。

公共模块gb

在创建项目时,每个项目都会默认拥有一个公共模块 gb

普通模块只允许调用公共模块 gb 的公共的组件、css或js,而不允许调用其他普通模块的资源。

快速开始

基于命令 athena,同时提供了简写ath

初始化

首先需要初始化Athena,在这一步会有初始化工作目录、输入用户名等操作

$ ath init [工作目录]

生成新项目

生成一个新的项目目录

$ ath app [项目名称]

或者使用简写 ath a [项目名称],ath app -h可以看到该命令的使用方式

同时提供了通过携带参数快速创建项目的命令

$ ath a --name lo --description 测试 --sass --template 默认模板

参数 --name 指定项目名称

参数 --description 指定项目描述

参数 --sass 指定项目使用 sass

参数 --less 指定项目使用 less

参数 --template 指定项目使用的模板,输入模板名称,默认模板是 默认模板

每个参数都是可缺省的。

然后根据提示一步一步来,将会自动生成项目的结构和所需文件代码

新增模块

在某一项目中新增一个模块,比如在项目 wd 中新增一个 open 模块,需要在项目根目录下执行

$ ath module [模块名]

或者使用简写 ath m [模块名],ath module -h可以看到该命令的使用方式

[模块名]参数指定模块,可以包含多个模块,多模块间使用 , 进行分隔

举个栗子

// 以下命令将创建my和hello两个模块
ath m my,hello

同时提供了通过携带参数快速创建模块的命令

$ ath m --name hhh --description 测试 --sass

参数 --name 指定模块名称

参数 --description 指定模块描述

参数 --sass 指定模块使用 sass

参数 --less 指定模块使用 less

每个参数都是可缺省的。

然后根据提示一步一步来,将会自动生成项目的结构和所需文件代码

新增页面

在某一模块下新增一个页面,进入到该模块 下,执行

$ ath page [页面名]

或者使用简写 ath pa [页面名],ath page -h可以看到该命令的使用方式

同时提供了通过携带参数快速创建页面的命令

$ ath pa --name hello --description 测试 --sass --remote jd

参数 --name 指定页面名称

参数 --description 指定页面描述

参数 --sass 指定页面使用 sass

参数 --less 指定页面使用 less

参数 --remote 指定页面属于域,目前分别有 tencentjd

每个参数都是可缺省的。

然后根据提示一步一步来,将会自动生成athena的页面目录和模板

新增widget

在某一模块下新增一个widget组件,进入到该模块 下,执行

$ ath widget [组件名]

或者使用简写 ath w [组件名],ath widget -h可以看到该命令的使用方式

同时提供了通过携带参数快速创建组件的命令

$ ath w --name topbar --sass --description 测试

参数 --name 指定组件名称

参数 --description 指定组件描述

参数 --sass 指定组件使用 sass

参数 --less 指定组件使用 less

参数 --cms 指定这是供CMS使用的楼层组件

每个参数都是可缺省的。

然后根据提示一步一步来,将会自动生成athena的widget目录和模板

删除命令

通过命令 athena delete 可以进行 项目模块页面组件 的删除,请遵循以下场景使用

命令简写 ath del

场景一

在项目目录外,可以使用如下命令来进行删除

// 删除当前目录下项目
$ ath del -a [项目名]

// 删除当前目录下项目的某一模块
$ ath del -a [项目名] -m [模块名]

// 删除当前目录下项目的某一模块中的某一页面
$ ath del -a [项目名] -m [模块名] -p [页面名称]

// 删除当前目录下项目的某一模块中的某一组件
$ ath del -a [项目名] -m [模块名] -w [组件名称]

场景二

在项目目录下,可以使用如下命令来进行删除

// 删除当前项目的某一模块
$ ath del -m [模块名]

// 删除当前项目的某一模块中的某一页面
$ ath del -m [模块名] -p [页面名称]

// 删除当前项目的某一模块中的某一组件
$ ath del -m [模块名] -w [组件名称]

场景三

在模块目录下,可以使用如下命令来进行删除

// 删除当前模块的某一页面
$ ath del -p [页面名称]

// 删除当前模块的某一组件
$ ath del -m [模块名] -w [组件名称]

使用及编译

编译模式

过一段时间的探索演进,目前Athena有2种编译模式,分别是

  • 在客户端进行代码合并的客户端完全处理client模式
  • 在静态服务器进行代码合并的server模式

而这两种模式下又要区分是编译出上线前代码的build,还是进行开发时的实时预览serve,build和serve需要执行的编译任务是不一样的,所以其实认为有4种模式也并无不可。

两种模式下大家开发时的代码写法完全一样,唯一的区分是在项目的app-conf.js中进行配置,配置项为comboConf如下

module.exports = {
  app: 'nima',
  appId: '7024e980-8cd8-11e5-89fe-370bd1e969e9',
  description: '尼玛',
  common: 'gb',
  moduleList: ['gb', 'hh', 'lp'],
  platform: 'mobile',
  versionControl: 'git',
  comboConf: {
    mode: 'server', // server/client
    server: {
      flag: '??', // server端合并时的分割标识,如某Url //static.360buyimg.com/nima??/gb/common_d6e4c134.css,/hh/jj_5e52390b.css,/hh/topbar_17c154d1.css,/hh/banner_2dc311a1.css,/hh/hello_1ed059f2.css
      onlineDomain: '//static.360buyimg.com/', // 服务端合并的线上域名
      shortPath: 'nima' // 次级目录
    }
  }
...
}

comboConf.modeserver则是server模式,client即是client模式。

模块化

通过阅读设计稿,我们可以将页面拆分成不同widget,而一些可以通用的widget我们可以放到一个公共模块中去统一管理,通过这样的页面组件化方式,我们可以很好地避开复制代码的问题,同时让我们的代码更好管理。

在执行athena page [pageName]命令生成页面后,可以发现在模块的page目录下多了一个以刚刚输入的页面名称pageName作为名字的目录,这个目录下面包含 html/js/css 三个文件。在html文件中一般通过加载各个widget的方式来进行开发,具体代码如下:

<%= widget.load('user') %>
<%=
	widget.load('user', {
		param: 'test'
	})
%>
<%= widget.load('user', null, 'gb') %>

widget.load可以方法接收三个参数,第一个参数是widget的名称,后面两个参数是可选参数,第二个是向widget传递的一些参数,第三个是widget所属的模块,如果是本模块,可以不传。

widget 的目录下包含了一个该组件的json格式的说明文件,文件中的 data 字段可以用来定义组件所需接收的默认参数,在执行 widget.load 方法时 data 字段会作为参数的一部分,方法调用时传入的参数若和 data 有重叠,则会对 data 进行覆盖。

页面中API

widget.load

如前一小节所显示,用来加载组件

widget.loadFloor

widget.load 的变种,用来加载CMS解决方案中的楼层,参数与widget.load方法一致,默认加载 widget 目录中的 data.json 文件,但需要注意的是,目前这个方法只有在开启server模式才有效。

widget.loadFloorSmarty

widget.load 的变种,用来加载使用Smarty语法编写的楼层或元件,参数与widget.load方法一致,默认加载 widget 目录中的 custom_data.json 文件,但需要注意的是,目前这个方法只有在开启server模式才有效。

getCSS

使用方式 <%= getCSS() %>

用来输出页面所需引用的CSS Link,可传入3个参数,第一个参数是CSS 样式表的名称,第二个参数是模块名,第三个参数是是否加入页面片中(client模式)。如果什么都不传则默认输出与当前页面同名的样式表。例如:

当前模块hello中有一页面为mine.html,在页面<head>标签中调用<%= getCSS() %>将输出

<link rel="stylesheet" type="text/css" href="css/mine.css" combo-use="/hello/css/mine.min.css">

若第三个参数为 inline ,则该样式文件会以内联的形式写入页面片中(client模式)。

getJS

与上述getCSS相似,将输出页面所需引用的脚本文件,参数与getCSS保持一致。

当前模块hello中有一页面为mine.html,在页面<body>标签最后调用<%= getJS() %>将输出

<script src="js/mine.js" combo-use="/hello/css/mine.min.js"></script>

若第三个参数为 inline ,则该样式文件会以内联的形式写入页面片中(client模式)。

注意

  • 这些API调用语句末尾不要加分号

app-conf.js

项目的根目录下生成的文件中,app-conf.js 文件是一个通过传入配置项生成的关于本项目的配置文件,我们可以看到它包含如下配置:

'use strict';

module.exports = {
  app: 'qwd', // 项目名称
  appId: 'd562b930-be56-11e5-8027-b52041f428b5', // 项目ID
  description: 'demo',
  platform: 'pc', // 平台 pc or mobile
  common: 'gb', // 公共模块
  moduleList: ['gb', 'frs', 'test'], // 项目下模块列表,通过athena module命令生成模块时会自动往此处添加新模块名
  tmpId: 'default', // 选用模板
  versionControl: 'git', // 标记当前项目使用的版本控制工具,目前只有git,若设置了,则在发布时将经过代码是否已提交远程仓库的检测
  shtml: {  //页面片配置
    use: true, //是否使用,总控制,若要开启使用页面片,这里必须为true
    needCombo: true, // 页面片中链接是否合并
    needTimestamp: true //增加时间戳
  },
  useInclude: { // 启用生成html页面片功能
    folder: 'include', // 生成页面片目录名字
    pathPrefix: 'include', //页面片路径前缀 include/header.html
    files: { // 需要生成的页面片文件
      'header.html': { // 文件名,文件对应的widget组件信息
        module: 'gb',
        widget: 'mod_hd'
      }
    }
  },
  comboConf: {  // 文件合并模式,server模式为文件在服务器端合并,client即文件通过工具本地合并
    mode: 'server', // server/client
    server: {
      flag: '??', // server端合并时的分割标识,如某Url //static.360buyimg.com/nima??/gb/common_d6e4c134.css,/hh/jj_5e52390b.css,/hh/topbar_17c154d1.css,/hh/banner_2dc311a1.css,/hh/hello_1ed059f2.css
      onlineDomain: '//static.360buyimg.com/', // 服务端合并的线上域名
      shortPath: 'nima' // 次级目录
    }
  },
  deploy: {  // 需要发布时的配置
    local: { // 不涉及到部署至哪台机器
      fdPath: '/' // 需要放置的目录
    },
    preview: { // 预览机的配置,名字不能修改,配置内容可以随自己需求修改
      host: 'labs.qiang.it', // 机器host
      user: '', // 用户名
      pass: '', // 密码
      port: 21, // 端口
      fdPath: '/h5/', // 需要放置的目录
      domain: 'labs.qiang.it', // 机器域名
      remotePath: '/labs.qiang.it/h5/qwd' // 上传到的目录
    },
    jdcfinder: { // jdcfinder
      mode: 'http',
      host: 'jdcfinder',
      user: '',
      pass: '',
      fdPath: '/fd/h5/',
      domain: 'jdc.jd.com',
      remotePath: '/fd/h5/nima', // 上传代码的目录
      cssi: '/sinclude/cssi/fd/h5/qwd', // 上传页面片的目录
      assestPrefix: '/fd/h5/qwd', // 发布完静态资源后,静态资源路径
      shtmlPrefix: '/sinclude/cssi/fd/h5/qwd', // 发布完页面片后,静态资源路径
      shtmlCommentPrefix: '/sinclude/cssi/fd/h5/qwd', // 生成页面片注释中的路径
      shtml: {  //针对服务器的页面片配置
        needCombo: true, // 页面片中链接是否合并
        needTimestamp: true //增加时间戳
      }
    },
    jdTest: {
      host: '192.168.193.32',
      user: '',
      pass: '',
      port: 22,
      fdPath: '/fd/h5/',
      domain: 's.paipaiimg.com',
      remotePath: '/export/paipai/resource/static/fd/h5/hellokity', // 上传代码的目录
      cssi: '/export/paipai/resource/sinclude/cssi/fd/h5/hellokity', // 上传页面片的目录
      assestPrefix: '/static/fd/h5/hellokity', // 发布完静态资源后,静态资源路径
      shtmlPrefix: '/sinclude/cssi/fd/h5/hellokity', // 发布完页面片后,静态资源路径
      shtmlCommentPrefix: '/sinclude/cssi/fd/h5/hellokity', // 生成页面片注释中的路径
      shtml: {  //针对服务器的页面片配置
        needCombo: true, // 页面片中链接是否合并
        needTimestamp: true //增加时间戳
      }
    }
  }
};

其中 appcommon 配置项 不要 修改,我们需要重点关注 deploy 这个配置项,这是发布到一些机器上的配置,可以注意到用户名和密码是空的,我们需要自己去完善它,同时上传的目录可以根据自己的需要进行修改。

需要注意的是 localpreview 是特殊配置项,其中 preview 代表需要发布到的预览机器,这两者的名字 不可修改 ,目前配置中有配置了两台开发机,分别是 tencnetjdTest,若需要发布到其他开发机请自行仿照增加配置。

module-conf.js

包含模块的一些配置信息

'use strict';

module.exports = {
  creator: 'luckyadam',  // 模块创建者
  app: 'hw',  // 项目名称
  common: 'gb',  // 公共模块名称
  module: 'mm',  // 当前模块名
  description: 'test',  // 模块简要信息
  support : {  
    useHash: {
      enable: true // 是否启用文件hash
    },
    imagemin: { // 图片压缩的配置
      exclude: ['banner.png'] // 图片压缩排除的图片
    },
    autoprefixer: { // 自动前缀的配置
      pc: [
      	'last 3 versions',
      	'Explorer >= 8',
      	'Chrome >= 21',
        'Firefox >= 1',
        'Edge 13'
      ],
      mobile: [
      	'Android >= 4',
      	'iOS >= 6'
      ]
    },
    px2rem: {  // px转rem配置
      enable: false,  // 是否开启
      root_value: 40,
      unit_precision: 5,
      prop_white_list: [],
      selector_black_list: [],
      replace: true,
      media_query: false
    },
    fontcompress : {
      enable: false
    },
    csssprite: { //css雪碧图合并配置
      enable: true, // 是否开启
      rootValue: 40, // px转rem,若不想转rem,此处应为0
      padding: 10, // 图与图之间的距离
      spriteFolder: 'sprites' // 雪碧图放置目录,若不想将雪碧图单独放置目录,此处为空或不传
    },
    base64: {
      enable: false, // 表示是否开启统一转换
      exclude: [], // 排除图片,例如 images/icon.png
      size: 5000 // 小于5000b的图片就会转
    }
  }
};

static-conf.js

需要引用static目录下资源的配置,由使用者自定义,一般可以用来自定义配置一些需要额外引用的第三方库文件,例如:

static/css目录下存在t1.csst2.css两个资源,需要将这两个资源引用到页面中,那么可以在该文件中增加如下配置

'use strict';

module.exports = {
  staticPath: {
    'test.css': [
      'static/css/t1.css',
      'static/css/t2.css'
    ]
  }
};

test.css 是自定义的合并后css名称,若要在页面中引用,只需调用 <%= getCSS('test.css') %> 即可。引用js文件同理

需要注意的是:

  • test.css 需带上后缀以示区分
  • 引用的资源路径,从static目录开始写全,如 static/css/t1.css

map.json

map.json 文件是通过执行编译任务后生成一个标识依赖关系的文件,文件中包含了当前模块所有页面所依赖的 widget 组件的信息,同时还有页面引用静态资源的信息,资源md5后资源名称的对应关系,它的文件结构如下

{
  "dependency": {
  	"find.html": [],
 	  "index.html": [],
 	  "open.html": [],
 	  "open1.html": [],
  	"open3.html": [],
  	"shop.html": [
   	 {
      	"widgetName": "topbar",
      	"param": {
        	"topbar": "微信"
      	},
      	"module": "test",
      	"exists": true
     }
   ],

   "include": {
    "test.html": {
      "css": [
        {
          "name": "gb.css",
          "module": "gb"
        },
        {
          "name": "test.css",
          "module": "mm"
        },
        {
          "name": "t.css",
          "module": "mm"
        }
      ],
      "js": [
        {
          "name": "test.js",
          "module": "mm"
        }
      ]
    }
  }
}

athena build

在编写完页面后可以通过athena build命令来执行对整个项目的编译,编译后的结果生成在各个模块的dist目录下。

build 可简写成 b

同时你可以通过传入参数来决定你需要编译的模块,[模块名]参数指定模块,可以包含多个模块,多模块间使用 , 进行分隔

$ athena build --module [模块名]

命令简写

$ ath b -m [模块名]

携带参数--verbose可以看到编译过程中的一些详细信息

携带参数--pack将进入打包模式,只输出静态稿压缩包到项目目录下,如果只是制作静态稿,可以使用这种模式

携带参数--compress页面将引用压缩后md5重命名的资源

携带参数--remote将根据输入的机器名来生成对应机器所需要的可上线文件,包括页面片,执行后所有可上线文件均在模块 dist/output 目录下,机器名和 app-conf.js 中配置的机器名一致

注意--pack--remote不要同时使用

携带参数--release将编译出可上线文件

携带参数 --allin 在使用server模式编译时会同时产生出合并后的资源文件

使用ath b -h 查看帮助。

每次对公共模块gb编辑完后,都需要重新编译gb模块,第一次获取项目后也需要编译一次公共模块gb

athena serve

通过athena serve命令可以实时预览正在编辑的页面。你可以在根目录执行这个命令,也可以进入到具体模块目录下去执行这个命令。

serve 可简写成 s

如果在项目根目录下,可以通过携带参数来决定要浏览的页面:

$ athena serve --module [模块名] --page [页面名]

如果在模块目录下,可以通过携带参数来决定要浏览的页面:

$ athena serve --page [页面名]

命令简写

$ ath s -m [模块名] --page [页面名]

同时你可以通过传入参数来决定你需要编译的模块,[模块名]参数指定模块,可以包含多个模块,多模块间使用 , 进行分隔

$ ath s -m gb,home

携带参数--dist将可以预览经过完整编译流程后生成的文件

建议只serve当前正在修改的模块,因为只serve模块的话会快很多

执行预览页面后会自动打开浏览器,届时将能看到整个项目的站点地图

站点地图

athena publish

athena publish 会将模块重新编译后发布到 app-conf.js 中配置的机器(包括预览机和开发机)上,同时会将压缩并重命名后的css文件和动态生成的页面片文件发布到机器的对应目录下(预览机器除外)。而在每次执行 athena publish 后页面片中的时间戳将会自动更新。目前配置了发布到腾讯和京东域的开发机,机器代号分别是 tencent jdTest,同时可发布到预览机 labs.qiang.it 上。在 athena publish 的过程中,你可以自行选择需要发布到开发机上的页面和对应静态资源。

publish 可简写成 pu

在模块目录下执行这个命令将会只发布本模块的页面。

在项目根目录下执行,可以通过传参来决定将发布哪些模块。[模块名]参数指定模块,可以包含多个模块,多模块间使用 , 进行分隔

$ athena publish --module [模块名]

命令简写

$ ath pu -m [模块名]

携带参数 --remote 指定要发布的机器,机器名和 app-conf.js 中配置的机器名一致

携带参数 --all 指定上传所有页面,无需再单独选择页面 携带参数 --allres 上传当前模块所有资源

使用ath pu -h 查看帮助。

若发现上传文件一直错误,请使用 $ ath clear --publish 命令来清除文件发布的缓存以解决问题(请详见ath clear 命令的使用),并提出issue描述问题。

athena clone

进入到某一模块下,通过athena clone 命令可以复制另一个模块的widget到当前模块。

$ athena clone [组件名字] --from [来源模块] --to [目标模块,若是当前模块可省略]

使用ath clone -h 查看帮助。

athena widget-publish

发布某一组件到公共组件库

使用方式

$ athena widget-publish [组件名字]
$ athena widget-publish --widget [组件名字]

简写

$ ath wp [组件名字]
$ ath wp -w [组件名字]

覆盖式发布

$ ath wp [组件名字]  -i [组件库ID]

注意:使用组件发布功能时,若组件需要接收参数,则必须在组件的说文件 组件名.json 文件的 data 参数中填写组件所需接收的默认参数,否则组件编译将会报错,如下

// widget.json
{
  ...
  "data": {
    "param1": "test1",
    "param2": "test2"
  }
}

athena widget-load

从组件库下载某一组件

使用方式

$ athena widget-load [组件id] --alias [组件重命名]
$ athena widget-load --id [组件id] --alias [组件重命名]

简写

$ ath wl [组件id] -a [组件重命名]
$ ath wl -i [组件id] -a [组件重命名]

athena map

用于列出某些依赖关系。

列出组件被页面引用的依赖关系

$ athena map [--module gb] --widget tab

若在项目目录下,则 --module 参数不可缺省,而在模块目录下则可缺省之,命令可简写为

$ ath map [-m gb] -w tab

示例:

示例

使用ath map -h 查看帮助。

athena clear

清除缓存,目前缓存包含 模板文件发布时的缓存文件

若出现模板拉取获取项目发布存在问题,可尝试清除缓存来解决。

使用方式

$ athena clear

清除模板文件缓存

$ athena clear --template
// 简写
$ ath clear -t

清除发布时的缓存文件,请在项目或模块目录下执行,否则将清除所有的发布缓存文件!

// 若要删除当前项目的发布缓存
$ athena clear --publish
// 简写
$ ath clear -p
// 若要删除当前项目某一模块的发布缓存
$ athena clear --module xxx --publish
// 简写
$ ath clear -m xxx -p

清除sass编译的缓存文件,请在项目或模块目录下执行,否则将清除所有的sass缓存文件!

// 请在项目或模块目录下执行
// 若要删除当前项目的sass编译缓存
$ athena clear --sass
// 简写
$ ath clear -s
// 若要删除当前项目某一模块的sass编译缓存
$ athena clear --module xxx --sass
// 简写
$ ath clear -m xxx -s

清除图片压缩的缓存文件,请在项目或模块目录下执行,否则将清除所有的图片缓存文件!

// 请在项目或模块目录下执行
// 若要删除当前项目的图片压缩缓存
$ athena clear --image
// 简写
$ ath clear -i
// 若要删除当前项目某一模块的图片压缩缓存
$ athena clear --module xxx --image
// 简写
$ ath clear -m xxx -i

athena update

$ athena update

将检测当前Athena版本是否最新,若是旧版本将自动安装最新版本Athena

简写

$ ath up

athena list-config

可以列出Athena配置

$ athena list-config

简写

$ ath lc

将会得到如下输出

配置地址:/Users/luckyadam/project/jdc/athena-html/.config.json
user_name=luckyadam
work_space=/Users/luckyadam/project/temp

athena list-setting

可以列出Athena设置

$ athena list-setting

简写

$ ath ls

将会得到如下输出

设置地址:/Users/luckyadam/project/jdc/athena-html/.setting.json
report_url=http://aotu.jd.com/athena

部分功能使用方法

文件压缩

文件压缩的配置位于每个模块module-conf.js文件中,在support下使用compress进行相关配置

// moudle-conf.js
support: {
  compress: {
    css: {
      mergeRules: false,
      mergeIdents: false,
      reduceIdents: false,
      discardUnused: false,
      minifySelectors: false
    },
    js: {
      mangle: {
        except: ['require', 'exports', 'module', 'e'],
        screw_ie8: false
      }
    },
    img: {
      extensions: ['png', 'jpg', 'jpeg', 'gif'],
      png: {
        quantity: '80-100'
      },
      jpg: {
        quantity: '90'
      }
    }
  }
}

CSS文件压缩

CSS文件采用 cssnano 工具进行压缩,可以在 support -> compress -> css 下进行相关配置,配置项可以参考 cssnano

JS文件压缩

JS文件采用 uglify-js 工具进行压缩,可以在 support -> compress -> js 下进行相关配置,配置项可以参考 uglify-js

图片压缩

目前可以对png/jpg/gif格式的图片进行压缩,可以在 support -> compress -> img 下进行相关配置

目前有如下配置项

extensions 配置需要进行压缩的图片后缀名,如 ['png', 'jpg'] 表示需要对 png/jpg/ 格式的图片进行压缩,目前支持的后缀有 ['png', 'jpg', 'jpeg', 'gif'],如不设置 extensions 则将压缩所有支持格式的图片

png 针对png格式图片压缩配置,目前支持配置压缩质量,如 {quality: '60-80'}quality 默认为 60-80,取值应为一个范围,此配置请参考 imagemin-pngquant 中的 quality 配置项进行配置

jpg 针对jpg格式的图片压缩配置,目前支持配置压缩质量,如 {quality: '80'}quality 默认为 80,此配置请参考 imagemin-mozjpeg 中的 quality 配置项进行配置

gif图片不支持设置图片压缩质量配置

完整的压缩配置见上述示例代码。

同时我们可以选择排除掉不需要压缩的图片,配置module-conf.js里面的 support 中的 imagemin 属性如下即可:

support : {  
  imagemin: {
    exclude: ['banner.png']
  }
}

babel转换

支持对 后缀为js的文件进行babel转换,使用的预设有 babel-preset-es2015babel-preset-stage-0,同时支持对jsx 语法进行转换,以便使用类React的框架进行开发

需要开启的话,在 module-conf.js 中进行配置

support : {  
  useBabel: {
    enable: true,
    jsxPragma: 'Nerv.createElement', // jsx转换支持,默认为 React.createElement
    exclude: [ // 排除掉不需要转义的文件
      'static/js/o2.js'
    ]
  }
}

文件md5重命名

通过配置 module-conf.js 里面的 support 中的 useHash 属性可以控制是否开启对文件做md5重命名

Sass的使用

全局的 sass 库文件放置在 公共模块gbstatic/sass 目录下,目前会自动生成一个 _common.scss 库,包含一些常用的mixins、变量和方法,若需引入其他库文件,请以下划线 _ 作为文件名的开始,直接放入 static/sass 目录下即可,随后在代码中这样引用:

需要在 banner.scss 中引用 _common.scss 中的 mixin flexbox

@import "common"; // 可以不带下划线

.banner {
  background: red;
  @include flexbox;
}

若要在一个模块中引入模块私有的sass库,可以将文件放入该模块的 static/sass 下,调用方式和上述一致。

一个模块中的sass文件只能引用本模块和公共模块中的sass库文件,为了区分公共模块和本模块的sass库,可以在 static/sass 目录下再建立一级目录,例如和所在模块同名的目录,这样引用时就可以就可可以区分了。例如,在 _common.scss 文件放在 static/sass/gb 目录下,这样引用的写法就是:

@import "gb/common"; // 可以不带下划线

若发现sass文件编译一直错误,请使用 $ ath clear --sass 命令来清除sass编译的缓存以解决问题(请详见ath clear 命令的使用),并提出issue描述问题。

注:之前工具自动生成项目没有自动生成 static/sass 目录,如需使用sass库,请自动创建该目录。

资源定位

资源定位是为了可以自动化将资源引用链接替换成配置好的目标地址,同时记录资源引用关系。

HTML 模板中定位使用API <%= uri() %>

定位CSS文件

<%= uri('css/demo.css') %>

定位JS文件

<%= uri('js/demo.js') %>

定位图片等放在images目录下的资源,必须带上images目录作为标记

<%= uri('images/bg.png') %>

js 中定位使用API __uri

__uri('css/demo.css')
__uri('images/bg.png')

同时在JS代码中提供了 __hash API来获取资源经过处理后(如MD5重命名)的名称:

__hash('images/lv.jpg') // => 'images/lv_bd11a0db.jpg'

需要注意的是,如果你想定位到 json 文件,建议将 json 文件放到 images 目录下来引用。

最佳实践:

如果有资源在JS代码中引用,则可以通过 __uri API来进行引用:

var bg = __uri('images/bg.png');
var lv = __uri('images/lv.jpg');

loadImage(bg);

文件内联

工具提供了将文件内容直接打印到页面中的功能,例如可以将一个 CSS 文件以内联的方式在 HTML 中引用。使用方式如下

HTML 模板中内联样式或脚本文件

// 第一个参数是文件名,第二个参数是模块名,如果是当前模块,可省略
<%= inline('demo.css', 'module') %>

API的第一个参数文件名是需要在模块 static-conf.js 文件中进行配置的,配置方式见上述文档中关于 static-conf.js 的使用说明。

而且需要注意的是,如果需要直接内嵌组件或页面的资源,即使只引用了一个组件的资源,也需要在 static-conf.js 中配置,而且如果配置中包含了组件或页面的资源,则最后打包的时候 <%= getCSS() %><%= getJS() %> 输出的资源中将不会再包含这个组件或页面的资源,以避免重复,例如

// demo.css

module.exports = {
  staticPath: {
    't.js': [
      'static/js/t1.js',
      'static/js/t2.js'
    ],
    'demo.css': [
      'widget/heheda/heheda.css',
      'widget/topbar/topbar.css'
    ]
  }
};

__inline('demo.css') 将直接输出组件 hehedatopbar 的合并样式,并且 <%= getCSS() %> 输出的样式表中将不会包含这两个组件样式。

js 中内联资源使用API __inline

// 第一个参数是文件名,第二个参数是模块名,如果是当前模块,可省略
__inline('demo.css', 'module')

同时,inline API是支持内联网络资源的,例如想要在模板中内联引入一段脚本,可以直接这样写

<%= inline('http://static.360buyimg.com/mtd/pc/cms/js/o2_ua.min.js') %>

若只想在预览时加载网络资源,发布时删去,则可以传入第二个参数 debug 来进行控制

// 以下写法,在页面发布时,会将这一句删掉,主要用于开发时调试之用
<%= inline('http://static.360buyimg.com/mtd/pc/cms/js/o2_ua.min.js', 'debug') %>

图片转base64

提供了两种方式来进行使用

第一种,在URL后面加上 ?__inline 标识,这样会直接转base64;

第二种,通过在 module-conf.js 中增加配置,定义规则,来进行统一转换处理

// module-conf.js
support : {  
  base64: {
    enable: false, // 表示是否开启统一转换
    exclude: [], // 排除图片
    size: 5000 // 小于5000b的图片就会转
  }
}

autoprefixer

我们提供了为CSS属性自动添加前缀的功能,同时区分了 移动端pc 端,在module-conf.js中配置如下:

support : {  
  autoprefixer: {
    pc: [
      'last 3 versions',
      'Explorer >= 8',
      'Chrome >= 21',
      'Firefox >= 1',
      'Edge 13'
    ],
    mobile: [
      'Android >= 4',
      'iOS >= 6'
    ]
  }
}

在编译的时候会自动读取 项目配置 app-conf.js 中的配置 platform 来决定是 pc 还是 mobile,例如如下代码

.banner {
  transform: rotate(45deg);
  font-size: 50px;
}

在不同 platform 下将输出如下:

pc

.banner {
  -webkit-transform: rotate(45deg);
     -moz-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
          transform: rotate(45deg);
  font-size: 50px;
}

mobile

.banner {
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
  font-size: 50px;
}

px转rem

自动将px转成rem,需要配置module-conf.js里面的 support 中的 px2rem 属性如下即可:

support : {  
  px2rem: {
    enable: false,  // 是否开启
    root_value: 40,  // 1rem = 40px
    unit_precision: 5,
    prop_white_list: ['prop1','prop2'],  // prop1,prop2为需要转换的属性
    selector_black_list: ['prop3','prop4'],  // prop3,prop4为不需要转换的属性
    replace: true,  //替换原来的属性
    media_query: false
  }
}

假设上面的白名单属性设为width,height,下面举例转换过程:

source.css

.demo {
  width: 80px;
  height: 100px;
  padding: 40px;
}

output.css

.demo {
  width: 2rem;
  height: 2.5rem;
  padding: 40px;
}

CSS雪碧图合并

将所有文件中background或者background-image引用到的带有?__sprite后缀的图片进行雪碧图合并,需要在配置文件module-conf.jssupport增加下面属性:

support : {  
    csssprite: {
      enable: true, // 是否开启
      rootValue: 40, // px转rem
      padding: 10, // 图与图之间的距离
      spriteFolder: 'sprites' // 雪碧图放置目录
    }
  }

上面的属性rootValue若设置为0表示不开启px转rem,若设置为非0正数,则表示1rem=40px,40为rootValue的值。 同时,若需要支持高清图样式适配,那么图片请自行修改为@2x,@3x后缀名,如:help@2x.png

以上面的配置为例,下面为转换过程,更多参考

source.css

body {
  background: url('images/ball.png?__sprite') no-repeat 0 0;
}

h1 {
 background-image: url('images/help.png?__sprite');
 background-repeat: no-repeat;
 background-position: 20px 30px;
}

.arrow {
  background: url('images/help@2x.png?__sprite') no-repeat 0 100px;width:40px;height:50px;
}

.logo {
  background: url('images/ball@2x.png?__sprite') no-repeat 100px 0;
}

output.css

body { background-image:url(../images/sprite.png); background-position:-2.7rem 0; }

h1 { background-image:url(../images/sprite.png); background-position:0 0;}

.arrow { background-image:url(../images/sprite.@2x.png); background-position:0 0; background-size:2.75rem 3.25rem;width:1rem;height:1.25rem;}

.logo { background-image:url(../images/sprite.@2x.png); background-position:-1.35rem 0; background-size:2.75rem 3.25rem;}

同时,提供了自定义生成多张雪碧图的功能,例如引用图片A/B/C/D,想要让A/B生成雪碧图sprite_1,C/D生成雪碧图sprite_2,则可以通过分别携带后缀?__sprite=sprite_1?__sprite=sprite_2来生成两张雪碧图。

source.css

.a {
  background-image: url('images/A.png?__sprite=sprite_1');
}

.b {
  background-image: url('images/B.png?__sprite=sprite_1');
}
.c {
  background-image: url('images/C.png?__sprite=sprite_2');
}

.d {
  background-image: url('images/D.png?__sprite=sprite_2');
}

output.css

.a {
  background-image: url('images/sprite_sprite_1.png');
}

.b {
  background-image: url('images/sprite_sprite_1.png');
}
.c {
  background-image: url('images/sprite_sprite_2.png');
}

.d {
  background-image: url('images/sprite_sprite_2.png');
}

配置中 rootValue 是控制当前模块全局的 rem 开关,如果想要指定某一处图片相关样式使用 pxrem 单位,可以在引用图片的地方通过参数指定,例如

// 指定使用 `px` 单位
.a {
  background-image: url('images/A.png?__sprite=sprite_1&__px');
}

// 指定使用 `rem` 单位
.a {
  background-image: url('images/A.png?__sprite=sprite_1&__rem');
}

// 使用 `rem` 单位时同时指定自己的 `rootValue`
.a {
  background-image: url('images/A.png?__sprite=sprite_1&__rem=20');
}

配置中 __widthHeight 是控制关闭强制替换背景图width和height,例如

// 强制使用 `__widthHeight` 来关闭width和height替换
.a {
  background-image: url('images/A.png?__sprite=sprite_1&__widthHeight');
  width:10px;
  height:10px;
}

增加 __widthHeight__rem=20同时配置使用

.a {
  background-image: url('images/A.png?__sprite=sprite_1&__widthHeight&__rem=20');
  width: 22px;
  height: 30px;
}

output.css

.a {
    background-image: url('images/sprite_sprite_1.png');
    background-position: -81.6rem -24.05rem;
    background-repeat: no-repeat;
    width: 1.1rem;
    height: 1.5rem;
}

CONTRIBUTORS

luckyadam Simba Chen adamchuan Sky Cai Manjiz panxinwu Littly
luckyadam Simba Chen adamchuan Sky Cai Manjiz panxinwu Littly

LICENCE

The MIT License (MIT)

Copyright (c) 2015

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.