Mantra

An Application Architecture for Meteor

Sung Won Cho / @mikeswcho

Presented March 30 at Meteor Sydney

Structure

  1. What Is Mantra
  2. Spec Overview
  3. Case Study
  4. Tools

What Is Mantra

A specification for structuring for Meteor apps

Not

  • Framework
  • Platform
  • Code generator

Why?

  • Less choice
  • Future proof
  • Sanity

Building Blocks

  • ES 2015 Modules
  • React
  • Meteor

Spec Overview

Pillars

  • Dependency injection
  • No isomorphism
  • Modular

Directory structure

App context

Shared variables

context.js
import * as Collections from '/lib/collections';
import {Meteor} from 'meteor/meteor';
import {FlowRouter} from 'meteor/kadira:flow-router';
import {ReactiveDict} from 'meteor/reactive-dict';
import {Tracker} from 'meteor/tracker';

export default function () {
	return {
		Meteor,
		FlowRouter,
		Collections,
		LocalState: new ReactiveDict(),
		Tracker
	};
}

Action

Business logic

posts.js
export default {
  create({Meteor, LocalState, FlowRouter}, title, content) {
    if (!title || !content) {
      return LocalState.set('SAVING_ERROR',
				'Title & Content are required!');
    }

    Meteor.call('posts.create', id, title, content);
    FlowRouter.go(`/post/${id}`);
  }
};

Components

React components

post_list.jsx
import React from 'react';

const PostList = ({posts}) => (
  
); export default PostList;

Containers

Pass actions & props to components

post_list.jsx
import PostList from '../components/postlist.jsx';
import {useDeps, composeWithTracker, composeAll} from 'mantra-core';

export const composer = ({context}, onData) => {
  const {Meteor, Collections} = context();
  if (Meteor.subscribe('posts.list').ready()) {
    const posts = Collections.Posts.find().fetch();
    onData(null, {posts});
  }
};

export default composeAll(
  composeWithTracker(composer),
  useDeps()
)(PostList);

index.js

Entry point for a module

main.js
import methodStubs from './configs/method_stubs';
import actions from './actions';
import routes from './routes.jsx';

export default {
  routes,
  actions,
  load(context) {
    methodStubs(context);
  }
};

main.js

Entry point for client side code

main.js
import {createApp} from 'mantra-core';
import initContext from './configs/context';

// modules
import coreModule from './modules/core';
import commentsModule from './modules/comments';

// init context
const context = initContext();

// create app
const app = createApp(context);
app.loadModule(coreModule);
app.loadModule(commentsModule);
app.init();

Case Study

Vym

Make real time presentation from GitHub PRs
vym.io

demo

Tools

Made in Sydney

Mantra CLI

Rails flavoured Command line interface


mantra create my_app
mantra generate component core:posts
mantra generate method comments
mantra desetroy method comments

Mantra Atom Package

End

Sung Won Cho