-
Notifications
You must be signed in to change notification settings - Fork 39
/
09s-creating-a-meteor-package.md.erb
223 lines (166 loc) · 10.1 KB
/
09s-creating-a-meteor-package.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
---
title: Создаем пакет Meteor
slug: creating-a-meteor-package
date: 0009/01/02
number: 9.5
sidebar: true
contents: Создадите локальный пакет в приложении.|Напишите тесты для пакета.|Опубликуете пакет в репозитории Atmosphere.
paragraphs: 22
---
Мы создали неплохой механизм для обработок ошибок. Теперь настало время поделиться им с сообществом Meteor.
Для начала, нам нужно удостовериться, что у нас есть Meteor Developer account. Вы можете зарегистрировать такой на сайте meteor.com. Вам нужно определить имя вашей учетной записи, так как в этой главе оно будет сильно задействовано.
Мы будем использовать имя `tmeasday` для примеров, вы можете заменить его на свое.
Во-первых нам нужно создать структуру пакета где он будет находиться. Для этого мы можем использовать команду `meteor create --package tmeasday:errors`. Заметьте, что Meteor создал папку `packages/tmeasday:errors` с файлами внутри. Мы начнем редактировать файл `package.js`, этот файл уведомляет Meteor о том, как пакет должен быть использован и какие объекты и функции он экспортирует.
~~~js
Package.describe({
summary: "Механизм отображения ошибок приложения пользователю",
version: "1.0.0"
});
Package.onUse(function (api, where) {
api.versionsFrom('[email protected]');
api.use(['minimongo', 'mongo-livedata', 'templating'], 'client');
api.add_files(['errors.js', 'errors_list.html', 'errors_list.js'], 'client');
if (api.export)
api.export('Errors');
});
~~~
<%= caption "packages/tmeasday:errors/package.js" %>
Разрабатывая пакет для реального использования, будет неплохо добавить Git URL репозитория вашего пакета поле `git` в `Package.describe` (если вы публикуете свои пакеты на git сервере). Таким образом пользователи могут изучать исходный код, и если вы используете GitHub, README файл репозитория будет использован в описании на Atmosphere.
Добавим еще три файла в наш пакет (сгенерированный Meteor'ом код можно убрать). Мы можем скопировать их из кода Microscope практически без изменений, за исключением правильного названия переменных и слегка почищенного API:
~~~js
Errors = {
// Локальная (только для клиента) коллекция
collection: new Meteor.Collection(null),
throw: function(message) {
Errors.collection.insert({message: message, seen: false})
},
clearSeen: function() {
Errors.collection.remove({seen: true});
}
};
~~~
<%= caption "packages/tmeasday:errors/errors.js" %>
~~~html
<template name="meteorErrors">
{{#each errors}}
{{> meteorError}}
{{/each}}
</template>
<template name="meteorError">
<div class="alert alert-error">
<button type="button" class="close" data-dismiss="alert">×</button>
{{message}}
</div>
</template>
~~~
<%= caption "packages/tmeasday:errors/errors_list.html" %>
~~~js
Template.meteorErrors.helpers({
errors: function() {
return Errors.collection.find();
}
});
Template.meteorError.rendered = function() {
var error = this.data;
Meteor.defer(function() {
Errors.collection.update(error._id, {$set: {seen: true}});
});
};
~~~
<%= caption "packages/tmeasday:errors/errors_list.js" %>
### Тестируем пакет с помощью Microscope
Протестируем изменения локально с помощью Microscope, чтобы убедиться что приложение все еще корректно работает. Для добавления пакета в наш проект мы запустим команду `meteor add tmeasday:errors`. Затем нам нужно удалить существующие файлы, которые больше не нужны:
~~~bash
$ rm client/helpers/errors.js
$ rm client/views/includes/errors.html
$ rm client/views/includes/errors.js
~~~
<%= caption "удаляем старые файлы с помощью консоли bash" %>
Еще нам нужно внести незначительные изменения в код чтобы он использовал правильный API:
~~~js
Router.before(function() { Errors.clearSeen(); });
~~~
<%= caption "lib/router.js" %>
~~~html
{{> header}}
{{> meteorErrors}}
~~~
<%= caption "client/views/application/layout.html" %>
~~~js
Meteor.call('post', post, function(error, id) {
if (error) {
// display the error to the user
Errors.throw(error.reason);
~~~
<%= caption "client/views/posts/post_submit.js" %>
~~~js
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// display the error to the user
Errors.throw(error.reason);
~~~
<%= caption "client/views/posts/post_edit.js" %>
<%= scommit "9-5-1", "Пакет для обработки ошибок создан и добавлен в приложение." %>
После всех упомянутых изменений наше приложение должно начать работать точно так же, как и до них.
### Пишем тесты
Первым шагом в разработке пакета было его тестирование вместе с приложением. Следующим шагом будет написание тестов, которые как следует протестируют поведение пакета. Meteor упакован встроенным тестером под названием Tinytest, позволяющим легко запускать серии тестов, и дающим спокойствие душе и разуму после того, как вы опубликовали ваш пакет для всех.
Создадим файл с тестами, использующими Tinytest. Они будут тестировать уже существующий код обработки ошибок:
~~~js
Tinytest.add("Errors collection works", function(test) {
test.equal(Errors.collection.find({}).count(), 0);
Errors.throw('A new error!');
test.equal(Errors.collection.find({}).count(), 1);
Errors.collection.remove({});
});
Tinytest.addAsync("Errors template works", function(test, done) {
Errors.throw('A new error!');
test.equal(Errors.collection.find({seen: false}).count(), 1);
// отрисовываем шаблон
OnscreenDiv(Spark.render(function() {
return Template.meteorErrors();
}));
// ждем несколько миллисекунд
Meteor.setTimeout(function() {
test.equal(Errors.collection.find({seen: false}).count(), 0);
test.equal(Errors.collection.find({}).count(), 1);
Errors.clearSeen();
test.equal(Errors.collection.find({seen: true}).count(), 0);
done();
}, 500);
});
~~~
<%= caption "packages/tmeasday:errors/errors_tests.js" %>
В этих тестах мы проверяем работоспособность функций из `Meteor.Errors`, а также делаем двойную проверку что отрисованный (`rendered`) код в шаблоне все еще работает.
Мы не будем углубляться в детали написания тестов для пакетов Meteor (так как API все еще не заморожен и сильно меняется), но мы надеемся что все довольно просто и понятно.
Чтобы сообщить Meteor, как запускать тесты в `package.js`, используйте следующий код:
~~~js
Package.onTest(function(api) {
api.use('tmeasday:errors', 'client');
api.use(['tinytest', 'test-helpers'], 'client');
api.add_files('errors_tests.js', 'client');
});
~~~
<%= caption "packages/errors/package.js" %>
<%= scommit "9-5-2", "Добавлены тесты в пакет." %>
Теперь мы можем запустить серию тестов следующей командой:
~~~bash
$ meteor test-packages tmeasday:errors
~~~
<%= caption "Terminal" %>
<%= screenshot "s7-1", "Все тесты пройдены успешно" %>
### Публикуем пакет
Мы хотим опубликовать наш пакет и сделать его доступным для всех. Для этого отправим пакет на пакетный сервер Meteor'а и таким образом опубликуем его на Atmosphere.
Сделать это очень легко. Нам нужно перейти в папку с пакетом и отправить пакет командой `meteor publish --create`:
~~~bash
$ cd packages/tmeasday:errors
$ meteor publish --create
~~~
<%= caption "Терминал" %>
Теперь, когда пакет опубликован, мы можем смело удалить его из проекта и добавить в приложение:
~~~bash
$ rm -r packages/tmeasday:errors
$ meteor add tmeasday:errors
~~~
<%= caption "Терминал (запускаем из корневой папки нашего приложения)" %>
<%= scommit "9-5-4", "Пакет удален из приложения." %>
Теперь мы можем увидеть как Meteor впервые загружает наш пакет из репозитория. Отличная работа!