Radosław Miernik
Open source? Embrace, understand, develop.
a.k.a. The Disclaimer
demystify
/diːˈmɪstɪfʌɪ/
(verb) Make (a difficult subject) clearer and easier to understand.
In other words: how Meteor does its magic.
And that it's not magic at all.
All files in a client
directory or with a client
part in their name will be accessible only on the client.
(Of course the same works for server.)
import { Meteor } from 'meteor/meteor';
// This code runs everywhere.
if (Meteor.isClient) {
// This code runs only on client.
}
if (Meteor.isServer) {
// This code runs only on server.
}
Meteor will include all the code in the client bundle. It may change though: meteor/meteor#11164.
Tracker is essentially a simple convention, or interface, that lets reactive data sources (like your database) talk to reactive data consumers (such as a live-updating HTML templating library) without the application code in between having to be involved.
Tracker gives you much of the power of a full-blown Functional Reactive Programming (FRP) system without requiring you to rewrite your program as a FRP data flow graph.
Meteor Tracker is an incredibly tiny (~1k) but incredibly powerful library for transparent reactive programming in JavaScript.
import { Thermometer } from 'best-thermometer-library';
import { Tracker } from 'meteor/tracker';
const temperatureDependency = new Tracker.Dependency();
export function currentTemperature() {
temperatureDependency.depend();
return Thermometer.read();
}
Thermometer.onChange(() => {
temperatureDependency.changed();
});
import { Tracker } from 'meteor/tracker';
import { currentTemperature } from './thermometer';
Tracker.autorun(() => {
console.log(`Temperature: ${currentTemperature()}°C`);
});
Distributed Data Protocol (or DDP) is a client-server protocol for querying and updating a server-side database and for synchronizing such updates among clients. It uses the publish-subscribe messaging pattern. It was created for use by the Meteor JavaScript framework. The DDP Specification is located on GitHub.
DDP supports only two operations*
Remote Procedure Calls (RPC)
Subscriptions (Pub-Sub)
(*) establishing connection and "heartbeats"
are technically operations as well
DDP may use either SockJS or WebSockets as a lower-level message transport.
At any time [...] the server can send data messages to the client. [...] These messages model a local set of data the client should keep track of.
Source: Optimistic UI with Meteor
import { Meteor } from 'meteor/meteor';
// Call a method.
Meteor.call('createTask', 'Buy more tea.');
import { Tasks } from '../collections/tasks';
Tracker.autorun(() => {
const tasks = Tasks.find().fetch();
console.table(tasks);
});
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
// Define a collection.
export const Tasks = new Mongo.Collection('Tasks');
// Define a method.
Meteor.methods({
createTask(taskName) {
// TODO: Validate your inputs!
Tasks.insert({ name: taskName });
}
});
Optimistic UI will work only if the method definition (Meteor.methods
) is both on the client and server side. Server-only methods will not be simulated.
It is 100% correct to have a different client- and server-side definition to achieve optimistic UI and keep the code hidden.
import { Meteor } from 'meteor/meteor';
import { Tasks } from '../collections/tasks';
// Define a publication.
Meteor.publish('tasks', (...args) => {
// TODO: Limit published documents!
return Tasks.find();
});
import { Meteor } from 'meteor/meteor';
// Subscribe.
Meteor.subscribe('tasks', ...args);
import { SomePubSubLibrary } from 'some-pub-sub-lib';
import { Meteor } from 'meteor/meteor';
// Define a low-level publication.
Meteor.publish('external-data', function (topic) {
// TODO: Validate inputs!
const handler = SomePubSubLibrary.subscribe(topic);
handler.on('data', data => {
this.added('external-pub-sub', topic, data);
});
this.ready();
this.onStop(() => {
this.removed('external-pub-sub', topic);
});
});
It's completely transparent for the client.
See vlasky:mysql
for an example.
import { Meteor } from 'meteor/meteor';
// Documents are sent only once.
Meteor.subscribe('tasks');
Meteor.subscribe('tasks');
Meteor.subscribe('tasks');
Fibers, sometimes called coroutines, are a powerful tool which expose an API to jump between multiple call stacks from within a single thread. This can be useful to make code written for a synchronous library play nicely in an asynchronous environment.
~
node-fibers
docs
What...?
import Fiber from 'fibers';
function sleep(ms) {
const fiber = Fiber.current;
setTimeout(() => fiber.run(), ms);
Fiber.yield();
}
const fiber = new Fiber(() => () {
console.log(new Date());
sleep(42 * 1000);
console.log(new Date());
});
fiber.run();
console.log('Done.');
// $ node sleep.js
// Fri Oct 11 2019 10:30:00 GMT+0100 (CET)
// Done.
// Fri Oct 11 2019 10:30:42 GMT+0100 (CET)
import Fiber from 'fibers';
function sleep(ms) {
const fiber = Fiber.current;
setTimeout(() => fiber.run(), ms);
Fiber.yield();
}
const fiber = new Fiber(() => () {
console.log(new Date());
sleep(42 * 1000);
console.log(new Date());
});
fiber.run();
console.log('Done.');
// $ node sleep.js
// Fri Oct 11 2019 10:30:00 GMT+0100 (CET)
// Done.
// Fri Oct 11 2019 10:30:42 GMT+0100 (CET)
async function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async run() {
console.log(new Date());
await sleep(42 * 1000);
console.log(new Date());
}
run();
console.log('Done.');
// $ node sleep.js
// Fri Oct 11 2019 10:30:00 GMT+0100 (CET)
// Done.
// Fri Oct 11 2019 10:30:42 GMT+0100 (CET)
NOTE OF OBSOLESCENCE -- The author of this project recommends you avoid its use if possible. The original version of this module targeted nodejs v0.1.x in early 2011 when JavaScript on the server looked a lot different. Since then async/await, Promises, and Generators were standardized and the ecosystem as a whole has moved in that direction.
~
node-fibers
docs
async function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async run() {
console.log(new Date());
await sleep(42 * 1000);
console.log(new Date());
}
// Meteor only!
run().await();
// ...or...
Promise.await(run());
console.log('Done.');
// Fri Oct 11 2019 10:30:00 GMT+0100 (CET)
// Fri Oct 11 2019 10:30:42 GMT+0100 (CET)
// Done.
METEOR_PROFILE=0
ROOT_URL=http://192.168.21.37
--extra-packages bundle-visualizer --production
--inspect & --inspect-brk
Can I disable Merge Box?
Not yet. See meteor/meteor-feature-requests#79 and meteor/meteor#11151.
Where can I read more?
By Radosław Miernik