1 | # Mosaic
|
2 |
|
3 | 马赛克(Mosaic)是所有以 Brix 组件形式编写的组件的管理工具,将业务中的各个区块以组件形式管理起来。
|
4 | 马赛克希望可以成为 BPM 工具的替代,后者依赖 NPM,不易扩展。
|
5 |
|
6 | 在你使用本工具之前,请先阅读 [Brix 相关文档](http://thx.github.io/brix)。
|
7 |
|
8 | ## 安装
|
9 |
|
10 | 马赛克采用 Node.js 开发,通过 NPM 方式发布。所以使用马赛克,你需要安装:
|
11 |
|
12 | - Node.js
|
13 | - NPM
|
14 |
|
15 | 然后在终端执行:
|
16 |
|
17 | ```
|
18 | npm install mosaic -g
|
19 | ```
|
20 |
|
21 | 装好之后,就可以使用 mosaic 命令了,还可以使用 mo 简写喔
|
22 |
|
23 | ```
|
24 | mosaic help
|
25 | mo help
|
26 | ```
|
27 |
|
28 | ## 用法
|
29 |
|
30 | 马赛克工具包含如下功能:
|
31 |
|
32 | - 发布组件
|
33 | - 下载组件
|
34 | - 开发核心组件
|
35 | - 开发乐高项目
|
36 |
|
37 | 所有功能都以子命令的形式提供,类似 git、brew 等工具:
|
38 |
|
39 | - mo publish
|
40 | - mo install
|
41 | - mo server
|
42 | - mo lego
|
43 |
|
44 | ### 发布组件
|
45 |
|
46 | 在组件目录执行:
|
47 |
|
48 | ```
|
49 | mo publish
|
50 | ```
|
51 |
|
52 | 即可。如果不想 cd 来 cd 去,也可以指定一下组件相对当前目录的路径:
|
53 |
|
54 | ```
|
55 | mo publish mux.tanx/dropdown
|
56 | ```
|
57 |
|
58 | 发布后,将可在 <http://brix.alibaba-inc.com> 看到所有发布的组件,自然也包括你刚发布的这个。
|
59 | 同时也可以在那找到你的组件在 CDN 的地址,通常为:
|
60 |
|
61 | http://g.tbcdn.cn/mo/:namespace/:name/:version/:file
|
62 |
|
63 | 如果是 Brix 核心组件,则命名空间为 mosaics ,路径为:
|
64 |
|
65 | http://g.tbcdn.cn/mo/mosaics/:name/:version/:file
|
66 |
|
67 | 如何在自己项目中使用这些外部组件(核心组件、或者其他业务组件),请看 <http://thx.github.io/brix>。
|
68 |
|
69 | ### 下载组件
|
70 |
|
71 | 可以下载仓库中的组件到本地,通常这是不必要的,除非你需要将某些组件改头换面到自己业务的命名空间下。
|
72 |
|
73 | ```
|
74 | mo install mosaics/wangwang/0.1.0
|
75 | mo install mosaics/wangwang
|
76 | ```
|
77 |
|
78 | 均可。不指定版本的话,则默认下载最新的。将会下载组件包,并解压至当前目录,结构为:
|
79 |
|
80 | ```
|
81 | mosaics
|
82 | └── wangwang
|
83 | ├── README.md
|
84 | ├── index.js
|
85 | └── package.json
|
86 | ```
|
87 |
|
88 | ### 开发 Brix 核心组件
|
89 |
|
90 | Brix 核心组件的命名空间为 mosaics,所有代码都在 <https://github.com/mosaics>,相应的,
|
91 | 我们要求核心组件开发者在本机也将组件目录组织为:
|
92 |
|
93 | ```
|
94 | mosaics
|
95 | ├── dropdown
|
96 | │ ├── README.md
|
97 | │ ├── demo
|
98 | │ │ └── wangwang.inc
|
99 | │ ├── index.css
|
100 | │ └── index.js
|
101 | ├── toc
|
102 | │ ├── README.md
|
103 | │ ├── index.js
|
104 | │ └── package.json
|
105 | └── wangwang
|
106 | ├── README.md
|
107 | ├── index.js
|
108 | └── package.json
|
109 | ```
|
110 |
|
111 | 然后,在 mosaics 目录下执行:
|
112 |
|
113 | ```
|
114 | mo server
|
115 | ```
|
116 |
|
117 | 接着,访问 <http://127.0.0.1:5000/dropdown> 即可预览自己所要开发的组件了。预览的内容根据
|
118 | README.md 的内容自动产生,具体写法可以参考
|
119 | [mosaics/wangwang](https://github.com/mosaics/wangwang) 示例。
|
120 |
|
121 | ### 开发基于乐高平台的页面
|
122 |
|
123 | 使用如下命令启动服务:
|
124 |
|
125 | ```
|
126 | mo lego
|
127 | ```
|
128 |
|
129 | 要求目录组织如下:
|
130 |
|
131 | ```
|
132 | .
|
133 | ├── public
|
134 | │ └── mux.lego
|
135 | │ └── ceiling
|
136 | │ ├── index.js
|
137 | │ └── package.json
|
138 | ├── views
|
139 | │ └── index.vm
|
140 | └── server.js
|
141 | ```
|
142 |
|
143 | ## 实现
|
144 |
|
145 | [isaacs](http://github.com/isaacs) 大牛对 Node 社区影响深远,要做包管理工具,
|
146 | 完全跟他做的 NPM 不沾边是不实际的。在本项目中,依赖的与 NPM 相关的包有:
|
147 |
|
148 | - tar
|
149 | - semver
|
150 | - fstream
|
151 | - fstream-npm
|
152 |
|
153 | ### tar
|
154 |
|
155 | [tar](https://github.com/isaacs/node-tar) 是 NPM 中使用的打包库,作用很简单,就是
|
156 | `tar foo.tar foo`,封装了各个平台的兼容性,提供了统一的接口:
|
157 |
|
158 | ```js
|
159 | fstream
|
160 | .Reader('path/to/package')
|
161 | .pipe(tar.Pack())
|
162 | .pipe(fstream.Writer('package.tar'))
|
163 | .on('close', function() {
|
164 | fs.existsSync('package.tar')
|
165 | // ==> true
|
166 | })
|
167 | ```
|
168 |
|
169 | 要打包(tar)一个组件目录,只需将其作为输入流,输送(pipe)到 `tar.Pack()`,再输送到输出流即可。
|
170 | 还可以中间加一个压缩步骤:
|
171 |
|
172 | ```js
|
173 | fstream
|
174 | .Reader('path/to/package')
|
175 | .pipe(tar.Pack())
|
176 | .pipe(zlib.Gunzip()) // Node 自带
|
177 | .pipe(fstream.Writer('package.tgz'))
|
178 | ```
|
179 |
|
180 | ### fstream
|
181 |
|
182 | fstream 自然不得不提,不清楚 Node 里是什么时候开始有这种流的设计,我还搞不太懂,
|
183 | 只能参考例子凑合着用,在 Node 里,我们可以如此打包、压缩单个文件:
|
184 |
|
185 | ```js
|
186 | fs.createReadStream('db-backup.sql')
|
187 | .pipe(tar.pack())
|
188 | .pipe(zlib.Gunzip())
|
189 | .pipe(fs.createWriteStream('db-backup.tgz'))
|
190 | ```
|
191 |
|
192 | 但是 `fs.createReadStream` 不支持从目录读取,因此大神 isaacs 封装了 fstream,方便操作。
|
193 |
|
194 | 在 fstream 的基础上,他又搞了 fstream-ignore 和 fstream-npm
|
195 |
|
196 | ### fstream-npm
|
197 |
|
198 | 简单说,这个库的作用就是以一个目录为输入流,根据其中的三个文件内容,忽略掉此目录中的一些文件。
|
199 | 这个忽略的功能,自然是依靠 fstream-ignore 实现的。这三个文件是:
|
200 |
|
201 | - [.npmignore](https://npmjs.org/doc/developers.html#Keeping-files-out-of-your-package)
|
202 | - [.gitignore](https://help.github.com/articles/ignoring-files)
|
203 | - [package.json](https://npmjs.org/doc/json.html)
|
204 |
|
205 | 前两个不言自明,在 fstream-ignore 中已实现,fstream-npm 扩展了第三个,即允许用户在
|
206 | package.json 中使用 `files` 属性显示指明所包含的文件,类似:
|
207 |
|
208 | ```json
|
209 | {
|
210 | "files": ["index.js", "mosaic.js"]
|
211 | }
|
212 | ```
|
213 |
|
214 | ### semver
|
215 |
|
216 | 语义化版本,去年就广而告之了,从[官网](http://semver.org)做了摘要,翻译如下:
|
217 |
|
218 | 首先,你要声明一个公共 API。可以由文档和代码本身的约束组成。无论如何,首要的是这个 API 要清晰并且准确。
|
219 | 一旦确认了你的公共 API,你就要通过版本号中的特定上升来说明 API 的改变。设想一种版本格式为 X.Y.Z ,
|
220 | 主版本号.次版本号.补丁版本号。不影响 API 的修复版本,上升补丁版本号;向后兼容的 API 增加、修改,
|
221 | 上升次版本号;向后不兼容的 API 修改,则增加主版本号。
|
222 |
|
223 | 详细的规则,和两个版本号的比较,semver.org 都有,isaacs 在 Node 中实现了这一逻辑,
|
224 | 并在 [node-semver](https://github.com/isaacs/node-semver) 的 README 中描述了其 API,
|
225 | 和版本号比较的逻辑。
|
226 |
|
227 |
|