Создаем пакет Meteor

Отступление 9.5

На данный момент переведено

В этой главе вы:

  • Создадите локальный пакет в приложении.
  • Напишите тесты для пакета.
  • Опубликуете пакет в репозитории Atmosphere.
  • Мы создали неплохой механизм для обработок ошибок. Теперь настало время поделиться им с сообществом Meteor.

    Для начала, нам нужно удостовериться, что у нас есть Meteor Developer account. Вы можете зарегистрировать такой на сайте meteor.com. Вам нужно определить имя вашей учетной записи, так как в этой главе оно будет сильно задействовано.

    Мы будем использовать имя tmeasday для примеров, вы можете заменить его на свое.

    Во-первых нам нужно создать структуру пакета где он будет находиться. Для этого мы можем использовать команду meteor create --package tmeasday:errors. Заметьте, что Meteor создал папку packages/tmeasday:errors с файлами внутри. Мы начнем редактировать файл package.js, этот файл уведомляет Meteor о том, как пакет должен быть использован и какие объекты и функции он экспортирует.

    Package.describe({
      summary: "Механизм отображения ошибок приложения пользователю",
      version: "1.0.0"
    });
    
    Package.onUse(function (api, where) {
    api.versionsFrom('METEOR@0.9.0');
    
      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');
    });
    
    packages/tmeasday:errors/package.js

    Разрабатывая пакет для реального использования, будет неплохо добавить Git URL репозитория вашего пакета поле git в Package.describe (если вы публикуете свои пакеты на git сервере). Таким образом пользователи могут изучать исходный код, и если вы используете GitHub, README файл репозитория будет использован в описании на Atmosphere.

    Добавим еще три файла в наш пакет (сгенерированный Meteor'ом код можно убрать). Мы можем скопировать их из кода Microscope практически без изменений, за исключением правильного названия переменных и слегка почищенного API:

    Errors = {
      // Локальная (только для клиента) коллекция
      collection: new Meteor.Collection(null),
    
      throw: function(message) {
        Errors.collection.insert({message: message, seen: false})
      },
      clearSeen: function() {
        Errors.collection.remove({seen: true});
      }
    };
    
    
    packages/tmeasday:errors/errors.js
    <template name="meteorErrors">
      {{#each errors}}
        {{> meteorError}}
      {{/each}}
    </template>
    
    <template name="meteorError">
      <div class="alert alert-error">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        {{message}}
      </div>
    </template>
    
    packages/tmeasday:errors/errors_list.html
    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}});
      });
    };
    
    packages/tmeasday:errors/errors_list.js

    Тестируем пакет с помощью Microscope

    Протестируем изменения локально с помощью Microscope, чтобы убедиться что приложение все еще корректно работает. Для добавления пакета в наш проект мы запустим команду meteor add tmeasday:errors. Затем нам нужно удалить существующие файлы, которые больше не нужны:

    $ rm client/helpers/errors.js
    $ rm client/views/includes/errors.html
    $ rm client/views/includes/errors.js
    
    удаляем старые файлы с помощью консоли bash

    Еще нам нужно внести незначительные изменения в код чтобы он использовал правильный API:

    Router.before(function() { Errors.clearSeen(); });
    
    lib/router.js
      {{> header}}
      {{> meteorErrors}}
    
    client/views/application/layout.html
    Meteor.call('post', post, function(error, id) {
      if (error) {
        // display the error to the user
        Errors.throw(error.reason);
    
    
    client/views/posts/post_submit.js
    Posts.update(currentPostId, {$set: postProperties}, function(error) {
      if (error) {
        // display the error to the user
        Errors.throw(error.reason);
    
    client/views/posts/post_edit.js

    Коммит 9-5-1

    Пакет для обработки ошибок создан и добавлен в приложение.

    После всех упомянутых изменений наше приложение должно начать работать точно так же, как и до них.

    Пишем тесты

    Первым шагом в разработке пакета было его тестирование вместе с приложением. Следующим шагом будет написание тестов, которые как следует протестируют поведение пакета. Meteor упакован встроенным тестером под названием Tinytest, позволяющим легко запускать серии тестов, и дающим спокойствие душе и разуму после того, как вы опубликовали ваш пакет для всех.

    Создадим файл с тестами, использующими Tinytest. Они будут тестировать уже существующий код обработки ошибок:

    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);
    });
    
    packages/tmeasday:errors/errors_tests.js

    В этих тестах мы проверяем работоспособность функций из Meteor.Errors, а также делаем двойную проверку что отрисованный (rendered) код в шаблоне все еще работает.

    Мы не будем углубляться в детали написания тестов для пакетов Meteor (так как API все еще не заморожен и сильно меняется), но мы надеемся что все довольно просто и понятно.

    Чтобы сообщить Meteor, как запускать тесты в package.js, используйте следующий код:

    Package.onTest(function(api) {
      api.use('tmeasday:errors', 'client');
      api.use(['tinytest', 'test-helpers'], 'client');
    
      api.add_files('errors_tests.js', 'client');
    });
    
    packages/errors/package.js

    Коммит 9-5-2

    Добавлены тесты в пакет.

    Теперь мы можем запустить серию тестов следующей командой:

    $ meteor test-packages tmeasday:errors
    
    Terminal
    Все тесты пройдены успешно
    Все тесты пройдены успешно

    Публикуем пакет

    Мы хотим опубликовать наш пакет и сделать его доступным для всех. Для этого отправим пакет на пакетный сервер Meteor'а и таким образом опубликуем его на Atmosphere.

    Сделать это очень легко. Нам нужно перейти в папку с пакетом и отправить пакет командой meteor publish --create:

    $ cd packages/tmeasday:errors
    $ meteor publish --create
    
    Терминал

    Теперь, когда пакет опубликован, мы можем смело удалить его из проекта и добавить в приложение:

    $ rm -r packages/tmeasday:errors
    $ meteor add tmeasday:errors
    
    Терминал (запускаем из корневой папки нашего приложения)

    Коммит 9-5-4

    Пакет удален из приложения.

    Теперь мы можем увидеть как Meteor впервые загружает наш пакет из репозитория. Отличная работа!