"Meteor is a full-stack JavaScript App Platform that assemble all the pieces you need to build modern web and mobile apps, with a single JavaScript codebase."
A library of packages: pre-written, self-contained modules that you might need in your app.
Meteor doesn't send HTML over the network. The server sends data and lets the client render it.
(you can, with a little bit of effort, have server side rendering though.)
Isomorphic
You can use the same methods to access your database from the client or server, thanks to minimongo.
Client-side, Meteor prefetches data and simulates models to make it look like a server method call returns instantly.
We call this optomistic UI.
Everything gets updates automatically, in real-time, and only when necessary.
Meteor is open source and it should be able to integrate with other open source platforms.
Like React.
Clean, easy to use APIs.
MongoDB
built with Meteor and React and Giphy and parachute pants.
// /lib/router.jsx
FlowRouter.route('/', {
action: function(){
ReactLayout.render(MainLayout, {
content: <HammerPage/>
})
}
})
// client/components/Layout/mainLayout.jsx
MainLayout = React.createClass({
render(){
return (
<div className="application">
<Header className="app-header">
<div className="title-container">
<p className="title"></p>
</div>
</Header>
<main>
{this.props.content}
</main>
</div>
)
}
});
// /client/components/Page/_hammerPage.jsx
HammerPage = React.createClass({
mixins: [ReactMeteorData],
getMeteorData(){
let subscription = Meteor.subscribe('hammerList');
return {
loading: !subscription.ready(),
hammers: Hammers.find({}, {sort: {createdOn: -1}}).fetch()
};
},
render(){
if (this.data.loading){
return <p>...loading</p>
} else{
return (
<Page>
<HammerButton />
<HammerList hammers={this.data.hammers}/>
</Page>
)
}
}
});
// /server/publications.js
Meteor.publish('hammerList', function(){
return Hammers.find();
})
// /client/components/Page/page.jsx
Page = React.createClass({
componentDidMount(){
//animate Page on load
let item = $(this.getDOMNode());
TweenMax.fromTo(page, .5, {
opacity: 0
}, {
opacity: 1,
ease: Power4.easeOut
} )
},
render(){
let styles = {
backgroundImage: "url('" + this.props.backgroundImage + "')",
}
let children = this.props.children;
return(
<div className={"page " + this.props.className} style={styles}>
{children}
</div>
)
}
});
// /client/components/Button/_hammerButton.jsx
HammerButton = new React.createClass({
render(){
return(
<div className="hammer-button">
<input type="text" className="hammer-name-field" placeholder="Name Your Hammer"/>
<Button action={this.action} className="primary-btn">Add Hammer</Button>
</div>
)
},
action(){
// use the meteor HTTP package to get a random MC Hammer GIF!
HTTP.get('http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=mc+hammer', function(error,result){
let hammerImage = result ? result.data.data.image_url : '/images/hammertime.gif';
let hammerName = $('.hammer-name-field').val();
//call a Meteor Methods to create a new Hammer. This methods is available on both the client and the server! Latency Compensation FTW!
Meteor.call('addHammer', hammerImage, hammerName, function(err, res){
if (err){
alert(err.reason)
}
});
});
}
})
// lib/collections/hammers.js
//this is our Hammers collection
Hammers = new Mongo.Collection('hammers');
Meteor.methods({
addHammer: function(hammerImage, hammerName){
//we should see this logged to both the client and the server logs!
console.log(hammerName);
if (!hammerName){
throw new Meteor.Error(422, 'Please name your Hammmmmmer.')
}
//uses Meteor's Check package to check that arguments are Strings, not Objects. Objects can be bad!
check(hammerName, String);
check(hammerImage, String);
//create a new Hammer by inserting it into a Mongo DB collection. This returns the Mongo ID of the new document
return Hammers.insert({image: hammerImage, name: hammerName, createdOn: new Date()});
}
})
// client/components/List/_hammerList.jsx
HammerList = new React.createClass({
render(){
// this is passed in from HammerPage - we only get data from top level components and let it flow down.
let hammers = this.props.hammers;
//loop through each object in hammers and render the HammerItem component
return (
<List className="hammer-list">
{hammers.map( hammer => {
return(
<HammerItem key={hammer._id} hammer={hammer} />
)
})}
</List>
)
}
})
HammerItem = new React.createClass({
componentDidMount(){
//lets animate these when the get rendered!
let count = Session.get('itemCount') || 0;
Session.set('itemCount', count + 1);
let item = $(React.findDOMNode(this.refs.item));
let delay = (count % 6) / 20;
TweenMax.fromTo(item, 1, {
opacity: 0,
y: 20
}, {
opacity: 1,
y: 0,
ease: Power4.easeInOut,
delay: delay
})
},
render(){
let style = {
backgroundImage: "url('" + this.props.hammer.image + "')"
}
return(
<li ref="item" style={style} className="hammer-item">
<h2 className="hammer-name">{this.props.hammer.name}</h2>
</li>
)
}
})