Files
meteor/docs/client/concepts.html
David Glasser 5e622215ba Change all publicly documented APIs to use camelCase.
For now, the old names still work as well.

This includes:
  - Meteor.isServer/isClient
  - this.isSimulation in methods
  - Context.onInvalidate
  - Meteor.status().retryCount/retryTime

Remove old backwards-compatibility "Sky" alias for "Meteor".

Update all examples in the docs to use camelCase.

Delete unused docs/client/projects.html file.
2012-09-17 14:26:45 -07:00

560 lines
22 KiB
HTML

<template name="concepts">
<h1 id="concepts">Concepts</h1>
We've written our fair share of single-page JavaScript applications by hand.
Writing an entire application in one language (JavaScript) with one
data format (JSON) is a real joy. Meteor is everything we wanted
when writing those apps.
{{> structure }}
{{> data }}
{{> reactivity }}
{{> livehtml }}
{{> templates }}
{{> packages_concept }}
{{> deploying }}
</template>
<template name="structure">
{{#better_markdown}}
<h2 id="structuringyourapp">Structuring your application</h2>
A Meteor application is a mix of JavaScript that runs inside a
client web browser, JavaScript that runs on the Meteor server inside
a Node.js container, and all the supporting HTML fragments, CSS rules,
and static assets. Meteor automates the packaging and transmission
of these different components. And, it is quite flexible about how
you choose to structure those components in your file tree.
The only server asset is JavaScript. Meteor gathers all your JavaScript
files, excluding anything under the `client`
and `public` subdirectories, and loads them into a Node.js
server instance inside a fiber. In Meteor, your server code runs in
a single thread per request, not in the asynchronous callback style
typical of Node. We find the linear execution model a better fit for
the typical server code in a Meteor application.
There are more assets to consider on the client side. Meteor
gathers all JavaScript files in your tree with the exception of
the `server` and `public` subdirectories for the
client. It minifies this bundle and serves it to each new client.
You're free to use a single JavaScript file for your entire application, or
create a nested tree of separate files, or anything in between.
Files outside the `client` and `server`
subdirectories are loaded on both the client and the server! That's
the place for model definitions and other functions. Meteor provides
the variables [`isClient` and `isServer`](#meteor_isclient) so that
your code can alter its behavior depending on whether it's running
on the client or the server.
Any sensitive code that you don't want served to the client, such as code
containing passwords or authentication mechanisms, should be
kept in the `server` directory.
CSS files are gathered together as well: the client will get a bundle with all
the CSS in your tree (excluding the `server`
and `public` subdirectories).
In development mode, JavaScript and CSS files are sent individually to make
debugging easier.
HTML files in a Meteor application are treated quite a bit differently
from a server-side framework. Meteor scans all the HTML files in your
directory for three top-level elements: `<head>`, `<body>`, and
`<template>`. The head and body sections are separately concatenated
into a single head and body, which are transmitted to the client on
initial page load.
Template sections, on the other hand, are converted into JavaScript
functions, available under the `Template` namespace. It's
a really convenient way to ship HTML templates to the client.
See the [templates](#templates) section for more.
Lastly, the Meteor server will serve any files under the `public`
directory, just like in a Rails or Django project. This is the place
for images, `favicon.ico`, `robots.txt`, and anything else.
{{/better_markdown}}
</template>
<template name="data">
{{#better_markdown}}
<h2 id="data">Data</h2>
Meteor makes writing distributed client code as simple as talking to a
local database. It's a clean and simple approach, much easier than
building individual RPC endpoints, slow roundtrips to the server, and
orchestrating invalidation messages.
Every Meteor client includes an in-memory database cache. Each client's
cache holds valid copies of some set of documents that are stored in a
server's master database. When a matching document in that database
changes, Meteor automatically synchronizes that change to every
subscribed client.
To manage the client caches, your server code <b>publishes</b> sets of
documents, and your client code <b>subscribes</b> to those sets. For
example, if you are building a chat system, the server might publish two
sets: the set of all rooms, and the set of all messages in a given room.
Each client would subscribe to the master set of available rooms and the
set of messages in the currently-selected room. Once subscribed, the
client uses its cache as a fast local database, dramatically simplifying
your client model code.
Meteor's protocol for distributing document updates is database
agnostic. By default, Meteor applications use the
familiar <a target="_blank"
href="http://www.mongodb.org/display/DOCS/Manual">MongoDB API</a>:
servers store documents in MongoDB collections, and clients cache those
documents in a client-side cache that implements the same Mongo API for
queries and updates.
// server: publish all room documents, and per-room messages
Meteor.publish("chatrooms");
Meteor.publish("messages", function (roomId) {
return Messages.find({room: roomId});
});
// client: subscribe to all rooms, and messages in the first room
Meteor.subscribe("chatrooms");
Meteor.subscribe("messages", Chatrooms.find()[0]._id);
Document modifications also propagate automatically. Modification
instructions like `insert`, `remove`, and `update` are executed
immediately on the client's cached data. <i>At the same time</i>, the
client sends that instruction up to the server, which executes the same
change against the master database. Usually the client and server
agree, but should they differ (permissions checking or overlapping with
another client, for example), the server's result will publish back down
to the client. And of course, all other clients with a matching
subscription automatically receive an updated document.
// create new message, executes on both client and server.
Messages.insert({room: 2413, text: "hello!"});
Putting it all together, these techniques accomplish <i>latency
compensation</i>. Clients hold a fresh copy of the data they need, and
never need to wait for a roundtrip to the server. And when clients
modify data, those modifications can run locally without waiting for the
confirmation from the server, while still giving the server final say
over the requested change.
You can substitute another database for MongoDB by providing a
server-side database driver and/or a client-side cache that implements
an alternative API. The `mongo-livedata` is a good starting point for
such a project.
{{#note}}
A pre-release version of Meteor includes a user login system and a set of tools
for securing read and write access to data based on the logged-in user. For more
information, see the
<a target="_blank"
href="https://github.com/meteor/meteor/wiki/Getting-Started-with-Auth">Getting
Started with Auth</a> wiki page.
{{/note}}
{{/better_markdown}}
</template>
<template name="reactivity">
{{#better_markdown}}
<h2 id="reactivity">Reactivity</h2>
Meteor embraces the concept of
<a target="_blank" href="http://en.wikipedia.org/wiki/Reactive_programming">
reactive programming</a>. This means that you can write your code in a
simple imperative style, and the result will be automatically
recalculated whenever data changes that your code depends on.
Meteor.autosubscribe(function () {
Meteor.subscribe("messages", Session.get("currentRoomId"));
});
This example (taken from a chat room client) sets up a data
subscription based on the session variable `currentRoomId`.
If the value of `Session.get("currentRoomId")` changes for any reason, the
function will be automatically re-run, setting up a new subscription that
replaces the old one.
This automatic recomputation is achieved by a cooperation
between `Session` and `Meteor.autosubscribe`.
Methods like `Meteor.autosubscribe` establish a "reactive
context" inside of which data dependencies are tracked, and they are
prepared to re-run their function argument as necessary. Data
providers like `Session`, on the other hand, make note of
the context they are called from and what data was requested, and they
are prepared to send an invalidation signal when the data changes.
This simple pattern has wide applicability. Above, the programmer is
saved from writing unsubscribe/resubscribe calls and making sure they
are called at the right time. In general, Meteor can eliminate whole
classes of data propagation code which would otherwise clog up your
application with error-prone logic.
These Meteor functions run your code in a reactive context:
* [`Meteor.render`](#meteor_render) and [`Meteor.renderList`](#meteor_renderlist)
* [`Meteor.autosubscribe`](#meteor_autosubscribe)
* [Templates](#templates)
And the reactive data sources that can trigger changes are:
* <a href="#session">Session</a> variables
* Database queries on <a href="#find">Collections</a>
* <a href="#meteor_status">`Meteor.status`</a>
Meteor's <a href="https://github.com/meteor/meteor/blob/master/packages/deps/deps.js" target="_blank">implementation</a>
of reactivity is short and sweet, about 50 lines of code. You can
hook into it yourself to add new reactive contexts or data sources,
using the <a href="#meteor_deps">Meteor.deps</a> module.
{{/better_markdown}}
</template>
<template name="livehtml">
{{#better_markdown}}
<h2 id="livehtml">Live HTML</h2>
HTML templating is central to web applications. With Meteor's live
page update technology, you can render your HTML _reactively_, meaning
that it will update automatically to track changes in the data used to
generate it.
This optional feature works with any HTML templating library, or even
with HTML you generate manually from Javascript. Here's an example:
var fragment = Meteor.render(
function () {
var name = Session.get("name") || "Anonymous";
return "<div>Hello, " + name + "</div>";
});
document.body.appendChild(fragment);
Session.set("name", "Bob"); // page updates automatically!
[`Meteor.render`](#meteor_render) takes a rendering function, that is, a
function that returns some HTML as a string. It returns an auto-updating
`DocumentFragment`. When there is a change to data used by the rendering
function, it is re-run. The DOM nodes in the `DocumentFragment` then
update themselves in-place, no matter where they were inserted on the
page. It's completely automatic. [`Meteor.render`](#meteor_render) uses
[reactive contexts](#reactivity) to discover what data is used by the
rendering function.
Most of the time, though, you won't call these functions directly
&mdash; you'll just use your favorite templating package, such as
Handlebars or Jade. The `render` and `renderList` functions are intended
for people that are implementing new templating systems.
Meteor normally batches up any needed updates and executes them only
when your code isn't running. That way, you can be sure that the DOM
won't change out from underneath you. Sometimes you want the opposite
behavior. For example, if you've just inserted a record in the
database, you might want to force the DOM to update so you can find
the new elements using a library like jQuery. In that case, call
[`Meteor.flush`](#meteor_flush) to bring the DOM up to date
immediately.
When live-updating DOM elements are taken off the screen, they are
automatically cleaned up &mdash; their callbacks are torn down, any
associated database queries are stopped, and they stop updating. For
this reason, you never have to worry about
the <a href="http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/"
target="_blank">zombie templates</a> that plague hand-written update
logic. To protect your elements from cleanup, just make sure that they
on-screen before your code returns to the event loop, or before any
call you make to [`Meteor.flush`](#meteor_flush).
Another thorny problem in hand-written applications is element
preservation. Suppose the user is typing text into an `<input>`
element, and then the area of the page that includes that element is
redrawn. The user could be in for a bumpy ride, as the focus, the
cursor position, the partially entered text, and the accented
character input state will be lost when the `<input>` is recreated.
This is another problem that Meteor solves for you. You can specify
elements to preserve when templates are re-rendered with the
[`preserve`](#template_preserve) directive on the template. Meteor will
preserve these elements even when their enclosing template is
rerendered, but will still update their children and copy over any
attribute changes.
{{/better_markdown}}
</template>
<template name="templates">
{{#better_markdown}}
<h2 id="templates">Templates</h2>
Meteor makes it easy to use your favorite HTML templating language,
such as Handlebars or Jade, along with Meteor's live page update
technology. Just write your template as you normally would, and Meteor
will take care of making it update in realtime.
To use this feature, create a file in your project with the `.html`
extension. In the file, make a `<template>` tag and give it a
`name` attribute. Put the template contents inside the tag. Meteor
will precompile the template, ship it down to the client, and make it
available as a function on the global `Template` object.
{{#note}}
Today, the only templating system that has been packaged for Meteor is
Handlebars. Let us know what templating systems you'd like to use with
Meteor. Meanwhile, see
the <a href="http://www.handlebarsjs.com/">Handlebars documentation</a>
and <a href="https://github.com/meteor/meteor/wiki/Handlebars">Meteor
Handlebars extensions</a>.
{{/note}}
A template with a `name` of `hello` is rendered by calling the
function `Template.hello`, passing any data for the template:
<!-- in myapp.html -->
<template name="hello">
<div class="greeting">Hello there, {{dstache}}first}} {{dstache}}last}}!</div>
</{{! }}template>
// in the JavaScript console
> Template.hello({first: "Alyssa", last: "Hacker"});
=> "<div class="greeting">Hello there, Alyssa Hacker!</div>"
This returns a string. To use the template along with the [`Live
HTML`](#livehtml) system, and get DOM elements that update
automatically in place, use [`Meteor.render`](#meteor_render):
Meteor.render(function () {
return Template.hello({first: "Alyssa", last: "Hacker"});
})
=> automatically updating DOM elements
The easiest way to get data into templates is by defining helper
functions in JavaScript. Just add the helper functions directly on the
`Template.[template name]` object. For example, in this template:
<template name="players">
{{dstache}}#each topScorers}}
<div>{{dstache}}name}}</div>
{{dstache}}/each}}
</{{! }}template>
instead of passing in `topScorers` as data when we call the
template function, we could define a function on `Template.players`:
Template.players.topScorers = function () {
return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};
In this case, the data is coming from a database query. When the
database cursor is passed to `#each`, it will wire up all of the
machinery to efficiently add and move DOM nodes as new results enter
the query.
Helpers can take arguments, and they receive the current template data
in `this`:
// in a JavaScript file
Template.players.leagueIs = function (league) {
return this.league === league;
};
<!-- in a HTML file -->
<template name="players">
{{dstache}}#each topScorers}}
{{dstache}}#if leagueIs "junior"}}
<div>Junior: {{dstache}}name}}</div>
{{dstache}}/if}}
{{dstache}}#if leagueIs "senior"}}
<div>Senior: {{dstache}}name}}</div>
{{dstache}}/if}}
{{dstache}}/each}}
</{{! }}template>
{{#note}}
Handlebars note: `{{dstache}}#if leagueIs "junior"}}` is
allowed because of a Meteor extension that allows nesting a helper
in a block helper. (Both `if` and `leagueIs` are
technically helpers, and stock Handlebars would not invoke
`leagueIs` here.)
{{/note}}
Helpers can also be used to pass in constant data.
// Works fine with {{dstache}}#each sections}}
Template.report.sections = ["Situation", "Complication", "Resolution"];
Finally, you can use an `events` declaration on a template function to set up a
table of event handlers. The format is documented at [Event
Maps](#eventmaps). The `this` argument to the event handler will be
the data context of the element that triggered the event.
<!-- myapp.html -->
<template name="scores">
{{dstache}}#each player}}
{{dstache}}> playerScore}}
{{dstache}}/each}}
</{{! }}template>
<template name="playerScore">
<div>{{dstache}}name}}: {{dstache}}score}}
<span class="givePoints">Give points</span>
</div>
</{{! }}template>
<!-- myapp.js -->
Template.playerScore.events({
'click .givePoints': function () {
Users.update({_id: this._id}, {$inc: {score: 2}});
}
});
Putting it all together, here's an example of how you can inject
arbitrary data into your templates, and have them update automatically
whenever that data changes. See [Live HTML](#livehtml) for further
discussion.
<!-- in myapp.html -->
<template name="forecast">
<div>It'll be {{dstache}}prediction}} tonight</div>
</{{! }}template>
<!-- in myapp.js -->
// JavaScript: reactive helper function
Template.forecast.prediction = function () {
return Session.get("weather");
};
<!-- in the console -->
> Session.set("weather", "cloudy");
> document.body.appendChild(Meteor.render(Template.forecast));
In DOM: <div>It'll be cloudy tonight</div>
> Session.set("weather", "cool and dry");
In DOM: <div>It'll be cool and dry tonight</div>
{{/better_markdown}}
</template>
<template name="packages_concept">
{{#better_markdown}}
<h2 id="smartpackages">Smart Packages</h2>
Meteor has an unusually powerful package system. All of the
functionality you've read about so far is implemented as standard
Meteor packages.
Meteor packages are intelligent: the packages are themselves
JavaScript programs. They can inject code into the client or the
server, or hook new functions into the bundler, so they can extend the
Meteor environment in arbitrary ways. Some examples of packages are:
* The <a href="#coffeescript">coffeescript</a> package extends the
bundler, automatically compiling any <code>.coffee</code> files in
your tree. Once added, you can write your application in CoffeeScript
instead of JavaScript.
* The <a href="#jquery">jQuery</a>
and <a href="#backbone">Backbone</a> packages are examples of using
Meteor to prepackage client JavaScript libraries. You could get
the same result by copying the JavaScript files into your tree, but
it's faster to add a package.
* The <a href="#underscore">underscore</a> package extends both the
client and server environments. Many of the core Meteor features,
including Minimongo, the Session object, and reactive Handlebars
templates, are implemented as internal packages automatically
included with every Meteor application.
You can see a list of available packages
with <a href="#meteorlist">meteor list</a>,
add packages to your project
with <a href="#meteoradd">meteor add</a>, and remove them
with <a href="#meteorremove">meteor remove</a>.
See the <a href="#packages">Package List</a> section for a description
of the existing packages.
{{#warning}}
The package API is rapidly changing and isn't documented, so you can't
make your own packages just yet. Coming soon.
{{/warning}}
{{/better_markdown}}
</template>
<template name="deploying">
{{#better_markdown}}
<h2 id="deploying">Deploying</h2>
Meteor is a full application server. We include everything you need
to deploy your application on the internet: you just provide the JavaScript,
HTML, and CSS.
<h3 class="nosection">Running on Meteor's infrastructure</h3>
The easiest way to deploy your application is to use <b>meteor
deploy</b>. We provide it because it's what, personally, we've always
wanted: an easy way to take an app idea, flesh it out over a weekend,
and put it out there for the world to use, with nothing getting in the
way of creativity.
$ meteor deploy myapp.meteor.com
Your application is now available at myapp.meteor.com. If
this is the first time deploying to this hostname, Meteor creates a
fresh empty database for your application. If you want to deploy an
update, Meteor will preserve the existing data and just refresh the
code.
You can also deploy to your own domain. Just set up the hostname you
want to use as a CNAME to <code>origin.meteor.com</code>,
then deploy to that name.
$ meteor deploy www.myapp.com
We provide this as a free service so you can try Meteor. It is also
helpful for quickly putting up internal betas, demos, and so on.
<h3 class="nosection">Running on your own infrastructure</h3>
You can run also your application on your own infrastructure, or any
other hosting provider like Heroku.
To get started, run
$ meteor bundle myapp.tgz
This command will generate a fully-contained Node.js application in
the form of a tarball. To run this application, you need to provide
Node.js 0.6 and a MongoDB server. You can then run the application by
invoking node, specifying the HTTP port for the application to listen
on, and the MongoDB endpoint. If you don't already have a MongoDB
server, we can recommend our friends at [MongoHQ](http://mongohq.com).
$ PORT=3000 MONGO_URL=mongodb://localhost:27017/myapp node bundle/main.js
Other packages may require other environment variables (for example, the `email`
package requires a `MAIL_URL` environment variable).
{{#warning}}
For now, bundles will only run on the platform that the bundle was
created on. To run on a different platform, you'll need to rebuild
the native packages included in the bundle. To do that, make sure you
have <code>npm</code> available, and run the following:
$ cd bundle/server/node_modules
$ rm -r fibers
$ npm install fibers@0.6.5
{{/warning}}
{{/better_markdown}}
</template>