-
Notifications
You must be signed in to change notification settings - Fork 12
/
09s-creating-a-meteorite-package.md.erb
246 lines (186 loc) · 8.6 KB
/
09s-creating-a-meteorite-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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
---
title: Creating a Meteorite Package
slug: creating-a-meteorite-package
date: 0009/01/02
number: 9.5
sidebar: true
contents: Ein lokales in-App Package schreiben.| Tests für dein Package schreiben.|Das Package auf Atmosphere publizieren.
paragraphs: 22
---
Wir haben ein wiederverwendbares Pattern in unserer Error-Anzeige, deshalb wollen wir das in ein Smartpackage verpacken und mit der Meteor Community teilen.
Zuerst müssen wir eine Struktur für unser Package kreieren. Wir legen das Package in ein Ordner namens `packages/errors/`. Dies kreiert ein custom Package das automatisch von der App benutzt wird. (Vielleicht ist dir aufgefallen dass Meteorite Packages via Symlinks in den `packages/` Ordner hineinspeichert).
Dann speichern wir eine `package.js` in diesen Ordner ab. Dieses File gibt Meteor Auskunft darüber, wie das Package benutzt werden soll.
~~~js
Package.describe({
summary: "A pattern to display application errors to the user"
});
Package.on_use(function (api, where) {
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/errors/package.js" %>
Nun fügen wir drei Files dem Package hinzu. Wir können diese Files ohne grosse Änderungen aus der bestehenden Microscope App hinausziehen, lediglich den Namespace und die API müssen wir leicht anpassen:
~~~js
Errors = {
// Local (client-only) collection
collection: new Meteor.Collection(null),
throw: function(message) {
Errors.collection.insert({message: message, seen: false})
},
clearSeen: function() {
Errors.collection.remove({seen: true});
}
};
~~~
<%= caption "packages/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/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/errors/errors_list.js" %>
### Das Package in Microscope ausprobieren
Wir werden nun das Ganze lokal mit Microscope ausprobieren, um sicherzustellen, dass unser geänderter Code auch funktioniert. Um das Package in das Projekt zu linken müssen wir `meteor add errors` ausführen. Dann müssen wir die existierenden Files die in der Zwischenzeit redundant geworden sind entfernen:
~~~bash
$ rm client/helpers/errors.js
$ rm client/views/includes/errors.html
$ rm client/views/includes/errors.js
~~~
<%= caption "removing old files on the bash console" %>
Was wir auch noch machen müssen, ist unsere API leicht anpassen:
~~~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", "Created basic errors package and linked it in." %>
Sobald diese Änderungen vorgenommen sind, sollten wir unsere ursprüngliche Funktionalität wieder haben.
### Tests schreiben
Der erste Schritt beim Development ist das Package in eine App zu integrieren. Der nächste Schritt ist dann, einen Test zu Schreiben, um das Package und sein Verhalten zu testen. Meteor hat eine built-in Testing Suite (Tynitest), die es einfach macht, solche Tests auszuführen und uns mit gutem Gewissen unseren Code mit anderen teilen lässt.
Lass uns einen Test mit Tinytest schreiben, der die "Errors"-Codebase testet.
~~~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);
// render the template
OnscreenDiv(Spark.render(function() {
return Template.meteorErrors();
}));
// wait a few milliseconds
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/errors/errors_tests.js" %>
In diesen Tests überprüfen wir die grundsätzlichen `Meteor.Errors` Funktionen und als Doppelcheck, dass der Code im Template immer noch funktioniert.
Wir beschäftigen uns hier nicht mit den Spezifikationen wie man Meteor Packages testet (die API ist noch nicht ganz fertiggestellt und ändert zur Zeit täglich), aber hoffentlich ist das Arbeitsprinzip zu weiten Graden selbsterklärend.
Um Meteor mitzuteilen wie es die Tests in `package.js` ausführen soll, benützen wir folgenden Code:
~~~js
Package.on_test(function(api) {
api.use('errors', 'client');
api.use(['tinytest', 'test-helpers'], 'client');
api.add_files('errors_tests.js', 'client');
});
~~~
<%= caption "packages/errors/package.js" %>
<%= scommit "9-5-2", "Added tests to the package." %>
Dann können wir die eigentlichen Tests wie folgt laufen lassen:
~~~bash
$ meteor test-packages errors
~~~
<%= caption "Terminal" %>
<%= screenshot "s7-1", "Passing all tests" %>
### Das Package publizieren
Jetzt wollen wir das Package publizieren, um es mit der Meteor Welt zu teilen. Dies machen wir über die Meteor Package Plattform Atmosphere.
Zuerst müssen wir ein `smart.json` hinzufügen, damit Atmosphere die wichtigen Details unseres Packages kennt.
~~~json
{
"name": "errors",
"description": "A pattern to display application errors to the user",
"homepage": "https://github.com/tmeasday/meteor-errors",
"author": "Tom Coleman <[email protected]>",
"version": "0.1.0",
"git": "https://github.com/tmeasday/meteor-errors.git",
"packages": {
}
}
~~~
<%= caption "packages/errors/smart.json" %>
<%= scommit "9-5-3", "Added a smart.json" %>
Wir schreiben einige grundsätzliche Metadaten, um Informationen über das Package zur Verfügung zu stellen. Dies wären: Informationen über was es tut, die git location wo wir es hosten und eine initiale Verisonsnummer. Wenn unser Package Abhängigkeiten zu anderen Atmosphere Packages hat, könnten wir auch die "packages" section benützen, um diese Abhängigkeiten festzulegen.
Wenn das alles an Ort und Stelle ist, ist das Publizieren einfach. Wir müssen ein Git Repository erstellen, zu einem Remote Git pushen und auf diese location in der smart.json verlinken.
Der Prozess dafür auf [GitHub](http://github.com) ist: Zuerst das neue Repository erstellen und dann dem Standard Workflow zum Zurverfügungstellen des Codes im Repository folgen. Dann können wir den `mrt release` Befehl brauchen um es zu Publizieren.
~~~bash
$ git init
$ git add -A
$ git commit -m "Created Errors Package"
$ git remote add origin https://github.com/tmeasday/meteor-errors.git
$ git push origin master
$ mrt release .
Done!
~~~
<%= caption "Terminal (run from within `packages/errors`)" %>
Bemerkung: Package Namen müssen einzigartig sein. Wenn du bisher Wort-für-Wort gefolgt bist und denselben Package Namen benutzt, wird es einen Konflikt geben. In Zukunft wird Atmosphere allerdings einen Autoren-Namespace haben. Du kannst also damit rechnen, dass es da noch Änderungen gibt.
Zweite Bemerkung: Du musst auf http://atmosphere.meteor.com/accounts einloggen und einen Usernamen und Password erstellen. Diese brauchst du wenn du auf der Command Line `mrt release` aufrufst.
Jetzt wenn das Package publiziert ist, können wir es aus dem Projekt löschen und wieder über Meteorite als offizielles Package einfügen:
~~~bash
$ rm -r packages/errors
$ mrt add errors
~~~
<%= caption "Terminal (run from the top level of the app)" %>
<%= scommit "9-5-4", "Removed package from development tree." %>
Jetzt sollte Meteorite unser Package zum ersten mal herunterladen. Herzliche Gratulation!