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 | - mosaics
|
81 | - wangwang
|
82 | - 0.1.0
|
83 | - index.js
|
84 | - ...
|
85 |
|
86 | ### 开发 Brix 核心组件
|
87 |
|
88 | Brix 核心组件的命名空间为 mosaics,所有代码都在 <https://github.com/mosaics>,相应的,
|
89 | 我们要求核心组件开发者在本机也将组件目录组织为:
|
90 |
|
91 | - mosaics
|
92 | - dropdown
|
93 | - README.md
|
94 | - index.js
|
95 | - index.css
|
96 | - ...
|
97 | - breadcrumbs
|
98 | - README.md
|
99 | - index.js
|
100 | - index.css
|
101 | - ...
|
102 |
|
103 | 然后,在 mosaics 目录下执行:
|
104 |
|
105 | ```
|
106 | mo server
|
107 | ```
|
108 |
|
109 | 接着,访问 <http://127.0.0.1:5000/dropdown> 即可预览自己所要开发的组件了。预览的内容根据
|
110 | README.md 的内容自动产生,具体写法可以参考
|
111 | [mosaics/wangwang](https://github.com/mosaics/wangwang) 示例。
|
112 |
|
113 | ### 开发基于乐高平台的页面
|
114 |
|
115 | 使用如下命令启动服务:
|
116 |
|
117 | ```
|
118 | mo lego
|
119 | ```
|
120 |
|
121 | 要求目录组织如下:
|
122 |
|
123 | - public
|
124 | - mux.lego
|
125 | - ceiling
|
126 | - template.vm
|
127 | - index.js
|
128 | - views
|
129 | - index.vm
|
130 | - server.js
|
131 |
|
132 | ## 实现
|
133 |
|
134 | [isaacs](http://github.com/isaacs) 大牛对 Node 社区影响深远,要做包管理工具,
|
135 | 完全跟他做的 NPM 不沾边是不实际的。在本项目中,依赖的与 NPM 相关的包有:
|
136 |
|
137 | - tar
|
138 | - semver
|
139 | - fstream
|
140 | - fstream-npm
|
141 |
|
142 | ### tar
|
143 |
|
144 | [tar](https://github.com/isaacs/node-tar) 是 NPM 中使用的打包库,作用很简单,就是
|
145 | `tar foo.tar foo`,封装了各个平台的兼容性,提供了统一的接口:
|
146 |
|
147 | ```js
|
148 | fstream
|
149 | .Reader('path/to/package')
|
150 | .pipe(tar.Pack())
|
151 | .pipe(fstream.Writer('package.tar'))
|
152 | .on('close', function() {
|
153 | fs.existsSync('package.tar')
|
154 | // ==> true
|
155 | })
|
156 | ```
|
157 |
|
158 | 要打包(tar)一个组件目录,只需将其作为输入流,输送(pipe)到 `tar.Pack()`,再输送到输出流即可。
|
159 | 还可以中间加一个压缩步骤:
|
160 |
|
161 | ```js
|
162 | fstream
|
163 | .Reader('path/to/package')
|
164 | .pipe(tar.Pack())
|
165 | .pipe(zlib.Gunzip()) // Node 自带
|
166 | .pipe(fstream.Writer('package.tgz'))
|
167 | ```
|
168 |
|
169 | ### fstream
|
170 |
|
171 | fstream 自然不得不提,不清楚 Node 里是什么时候开始有这种流的设计,我还搞不太懂,
|
172 | 只能参考例子凑合着用,在 Node 里,我们可以如此打包、压缩单个文件:
|
173 |
|
174 | ```js
|
175 | fs.createReadStream('db-backup.sql')
|
176 | .pipe(tar.pack())
|
177 | .pipe(zlib.Gunzip())
|
178 | .pipe(fs.createWriteStream('db-backup.tgz'))
|
179 | ```
|
180 |
|
181 | 但是 `fs.createReadStream` 不支持从目录读取,因此大神 isaacs 封装了 fstream,方便操作。
|
182 |
|
183 | 在 fstream 的基础上,他又搞了 fstream-ignore 和 fstream-npm
|
184 |
|
185 | ### fstream-npm
|
186 |
|
187 | 简单说,这个库的作用就是以一个目录为输入流,根据其中的三个文件内容,忽略掉此目录中的一些文件。
|
188 | 这个忽略的功能,自然是依靠 fstream-ignore 实现的。这三个文件是:
|
189 |
|
190 | - [.npmignore](https://npmjs.org/doc/developers.html#Keeping-files-out-of-your-package)
|
191 | - [.gitignore](https://help.github.com/articles/ignoring-files)
|
192 | - [package.json](https://npmjs.org/doc/json.html)
|
193 |
|
194 | 前两个不言自明,在 fstream-ignore 中已实现,fstream-npm 扩展了第三个,即允许用户在
|
195 | package.json 中使用 `files` 属性显示指明所包含的文件,类似:
|
196 |
|
197 | ```json
|
198 | {
|
199 | "files": ["index.js", "mosaic.js"]
|
200 | }
|
201 | ```
|
202 |
|
203 | ### semver
|
204 |
|
205 | 语义化版本,去年就广而告之了,从[官网](http://semver.org)做了摘要,翻译如下:
|
206 |
|
207 | 首先,你要声明一个公共 API。可以由文档和代码本身的约束组成。无论如何,首要的是这个 API 要清晰并且准确。
|
208 | 一旦确认了你的公共 API,你就要通过版本号中的特定上升来说明 API 的改变。设想一种版本格式为 X.Y.Z ,
|
209 | 主版本号.次版本号.补丁版本号。不影响 API 的修复版本,上升补丁版本号;向后兼容的 API 增加、修改,
|
210 | 上升次版本号;向后不兼容的 API 修改,则增加主版本号。
|
211 |
|
212 | 详细的规则,和两个版本号的比较,semver.org 都有,isaacs 在 Node 中实现了这一逻辑,
|
213 | 并在 [node-semver](https://github.com/isaacs/node-semver) 的 README 中描述了其 API,
|
214 | 和版本号比较的逻辑。
|
215 |
|
216 |
|