Дмитрий Манжасов, Мера
Дмитрий Манжасов, Мера
meteor create simple-todos
И весь код разместить в 3-х файлах
simple-todos.js # JavaScript loaded on both client & server
simple-todos.html # HTML file that defines view templates
simple-todos.css # CSS file to define your app's styles
client/ # everything for client-side only
compatibility/ # dinosaurs
css/ # some styles
lib/ # client libraries
view/ # template HTML & JavaScript
layout/ # page layouts
template/ # page templates
page1/ # page1 HTML template and JavaScript
public/ # static resources:
assets/ # local fonts and images
common/ # for the both client and server
controller/ # Iron Router controllers
lib/ # common libraries
collections.js # some collections
routes.js # Iron Router routes
server/ # server-side code
methods.js # remote functions
publish.js # collection publishing rules
private/ # top secret files
Плюсы
Минусы
meteor create --package username:packagename
packagename/
package.js
packagename.js
packagename-tests.js
README.md
// All properties are optional
Package.describe({
// Default is package directory name.
name: "bundle:namespace",
version: "0.0.1",
summary: "What this does",
// Github URL to your source repository.
git: "https://github.com/something/something.git",
// Package documentation
documentation: 'README.md'
});
// This defines your actual package
Package.onUse(function(api) {
// Use core Meteor packages from the release specified
api.versionsFrom('1.2.1');
// Dependencies
api.use('ecmascript');
api.use(['bundle:namespace', 'bundle:imports']);
api.use('tap:i18n@1.3.0');
api.use('underscore', 'client');
// to be continued
// Imply = use for including package or app
api.imply('iron:router@1.0.12');
// Package files
api.addFiles('route.js');
api.addFiles(['fruits.html', 'fruits.js'], 'client');
// Package assets
api.addAssets(['fonts/bundle.eot', ...
'img/default-avatar.jpg'], 'client');
// Export
api.export('Bundle');
});
/code/bundle/layout/icons.css
src:url("fonts/bundle.eot");
src:url("fonts/bundle.eot?#iefix") format("embedded-opentype"),
url("fonts/bundle.woff") format("woff"),
url("fonts/bundle.ttf") format("truetype"),
url("fonts/bundle.svg#bundle") format("svg");
/code/bundle/layout/layout.html
<img src="/packages/bundle_layout/img/default-avatar.jpg">
meteor publish
Ограничения
meteor add <package> [package..]
Где Meteor ищет пакеты:
packages/
приложенияPACKAGE_DIRS
Linux
PACKAGE_DIRS=../bundle:../i18n
Windows
set PACKAGE_DIRS=../bundle:../i18n
meteor create myapp
cd myapp
del myapp.*
meteor remove autopublish
mkdir packages
cd packages
meteor create --package myapp
cd ..
meteor add myapp
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.use('coffeescript');
api.use(['bundle:imports',
'bundle:namespace',
'bundle:layout',
'bundle:fruits',
'bundle:sweets']);
api.addFiles('myapp.coffee');
});
/code/myapp/packages/myapp/myapp.coffee
# Default route
Router.route '/', -> Router.go 'fruits'
if Meteor.isClient
# Navigation menu
Bundle.Navigation.set [
{template: 'NavFruits'}
{template: 'NavSweets'}
]
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.imply([
'iron:router@1.0.12',
'zimme:active-route@2.0.1'
]);
});
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.addFiles('namespace.js');
api.export('Bundle');
});
/code/bundle/namespace/namespace.js
Bundle = {};
/code/bundle/layout/
api.use('bundle:namespace'); // package.js
Bundle.Navigation = new ReactiveVar([]); // layout.js
/code/myapp/packages/myapp/
api.use(['bundle:namespace', 'bundle:layout']); // package.js
Bundle.Navigation.set [template: 'NavFruits'] # myapp.coffee
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.use(['ecmascript', 'bundle:namespace']);
api.addFiles('collections.js');
api.addFiles('publish.js', 'server');
});
/code/bundle/collections/collections.js
Bundle.Collection = {
Fruits: new Meteor.Collection('fruits'),
Sweets: new Meteor.Collection('sweets')
};
for(let name in Bundle.Collection) {
Bundle.Collection[name].allow({
// set insert, update and remove rules
});
}
/code/bundle/collections/publish.js
Meteor.publish('fruits', function() {
// TODO apply filter and check user access rights
return Bundle.Collection.Fruits.find();
});
Meteor.publish('sweets', function() {
// TODO apply filter and check user access rights
return Bundle.Collection.Sweets.find();
});
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.use(['ecmascript', 'templating', 'reactive-var']);
api.use(['bundle:namespace', 'bundle:imports']);
api.addFiles('route-controller.js');
api.addFiles(['icons.css', 'layout.css',
'layout.html', 'layout.js'], 'client');
api.addAssets(['fonts/bundle.eot', 'fonts/bundle.svg',
'fonts/bundle.ttf', 'fonts/bundle.woff',
'img/default-avatar.jpg'], 'client');
});
/code/bundle/layout/layout.html
<template name="Layout">
<div>
<aside>{{> yield region="navigation"}}</aside>
<div>
<header>{{> yield region="header"}}</header>
<main>{{> yield}}</main>
</div>
</div>
<footer></footer>
</template>
/code/bundle/layout/route-controller.js
Bundle.RouteController = RouteController.extend({
layoutTemplate: 'Layout',
title: '', // default title
context: undefined, // default context
action: function() {
// implementation
}
});
/code/bundle/layout/route-controller.js
this.render('Navigation', { to: 'navigation',
data: function() { return Bundle.Navigation.get(); }
});
this.render('Header', { to: 'header',
data: this.title
});
this.render(this.lookupTemplate(), {
data: this.context
});
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.use(['ecmascript', 'templating']);
api.use(['bundle:imports', 'bundle:namespace',
'bundle:collections']);
api.addFiles('route.js');
api.addFiles(['fruits.html', 'fruits.js'], 'client');
});
/code/bundle/fruits/route.js
Router.route('/fruits', {
controller: Bundle.RouteController.extend({
title: 'Свежие Фрукты',
subscriptions: function() {
return Meteor.subscribe('fruits');
},
context: function() {
return Bundle.Collection.Fruits.find();
}})
});
set PACKAGE_DIRS=../bundle
meteor
set PACKAGE_DIRS=../bundle
meteor build ..\ --architecture os.linux.x86_64
/* This defines the tests for the package */
Package.onTest(function(api) {
api.use('ecmascript');
// Allows you to use the 'tinytest' framework
api.use('tinytest');
// Sets up a dependency on this package
api.use('username:packagename');
// Specify the source code for the package tests
api.addFiles('packagename-tests.js');
});
https://github.com/meteor/meteor/tree/devel/packages/tinytest
/code/bundle/namespace/namespace-tests.js
Tinytest.add('namespace', function (test) {
test.instanceOf(Bundle, Object);
});
/code/bundle/collections/collections-tests.js
Tinytest.addAsync('collections - fruits', (test, next) => {
Meteor.subscribe('fruits', {
onError: (e) => {
test.fail(e);
next();
}, onReady: () => {
test.ok();
next();
}});
});
meteor test-packages