Meteor - Advance

meteor

https://meteorhacks.com/fibers-eventloop-and-meteor/ - done reading
https://github.com/laverdet/node-Fibers
https://www.eventedmind.com/feed/nodejs-introducing-fibers
https://www.eventedmind.com/feed/nodejs-using-futures
https://www.eventedmind.com/feed/meteor-meteor-wrapasync
https://www.youtube.com/watch?v=AWJ8LIzQMHY

How does Meteor use Event Loop?

Meteor is built on top of Node.js, so we can’t forget the Event Loop. Node.js runs on a single thread, and thanks to the Event Loop and event-driven programming, program execution isn’t blocked by I/O activities (network and disk, mainly). Instead, we provide a callback function that is run after the I/O completes, and the rest of the program continues to run.

What is Fiber?

Callbacks make Node.js code difficult to reason about (some describe it as callback soup). Error handling and nested callbacks are uncomfortable to write, and their existence makes code difficult to maintain and scale. That’s why some say Node.js is hard to learn (and use). Luckily, several techniques exist to overcome this issue. Fibers, Promises, and Generator-based coroutines are some of them.

Meteor uses Fibers, and implements APIs on top of it. Fibers provides an abstraction layer for the Event Loop that allows us to execute functions (tasks) in sequence. It allows us to write asynchronous code without callbacks. We get the best of both worlds–asynchronous efficiency with synchronous-style coding. Behind the scenes, Fibers takes care of dealing with the Event Loop.

Fibers is really good if you use it correctly (Meteor does it well). Also, the overhead caused by Fibers is negligible.

How does Meteor use Fiber?

Meteor abstracts Fibers with its APIs, allowing you to write your app without callbacks. The best part is that you can write your code this way and be completely oblivious to Fibers. It just works.

Meteor creates a new Fiber for each and every request (DDP Request) made from the client. By default, Meteor executes one request at a time for each client, meaning one Fiber for each client at a time. But you can change that. Fibers is the one of the best reasons Meteor is so popular. Since it allows us to write Node.js apps without callbacks, it has attracted many developers who hated Node.js for that reason.

How can we use Async Functions with Meteor?

We can’t satisfy 100% of our needs with Meteor’s API–sometimes we need to use NPM modules to get things done. But how can we do this if we don’t know how to use callbacks with Meteor?

For example, say you need to use the Github NPM module to get your user’s public profile. It needs to be done inside a Meteor method, and we need to return the profile from the method. Okay, let’s try to implement this.

var GithubAPI = Meteor.require('github');
var ghapi = new GithubAPI({version: "3.0.0"});

Meteor.methods({
  getProfile: function(username) {
    ghapi.user.getFrom({user: username}, function(err, profile) {
      // How to return?
    });

    // We need to return the profile from here.
  }
});

We can’t use callbacks like above. We can’t return the profile to the client from the callback, because the Meteor method won’t wait for the callback before returning. Now we need to learn how to deal with Fibers. Or do we?

Meteor foresaw this problem and provided us with a very simple API to get around it. It’s not documented yet, but here’s how you can use it. meteor-npm also comes with a set of async-utilities to work with npm modules.

function getUserProfile(req, callback) {
  ghapi.user.getFrom(req, callback);
}
var wrappedGetProfile = Meteor._wrapAsync(getUserProfile);

Meteor.methods({
  getProfile: function(username) {
    return wrappedGetProfile({user: username});
  }
});

The code above is simple to understand. We wrapped the ghapi.user.get method in a function, and called that function with Meteor._wrapAsync to make it Fibers aware. Now we can use it inside Meteor methods and other Meteor APIs. If you know how bind works, you can do the wrapping in a single line as shown below.

var wrappedGetProfile = Meteor._wrapAsync(ghapi.user.getFrom.bind(ghapi.user));

What is this 'splitting into multiple apps' stuff?

If you are writing a sufficiently complex system, there can come a time where it makes sense to split your code up into multiple applications. For example you may want to create a separate application for the administration UI (rather than checking permissions all through the admin part of your site, you can check once), or separate the code for the mobile and desktop versions of your app.

Another very common use case is splitting a worker process away from your main application so that expensive jobs do not impact the user experience of your visitors by locking up a single web server.

There are some advantages of splitting your application in this way:

  1. Your client JavaScript bundle can be significantly smaller if you separate out code that a specific type of user will never use.
  2. You can deploy the different applications with different scaling setups and secure them differently (for instance you might restrict access to your admin application to users behind a firewall).
  3. You can allow different teams at your organization to work on the different applications independently.

However there are some challenges to splitting your code in this way that should be considered before jumping in.

What is this 'sharing code' stuff?

The primary challenge is properly sharing code between the different applications you are building. The simplest approach to deal with this issue is to simply deploy the same application on different web servers, controlling the behavior via different settings. This approach allows you to easily deploy different versions with different scaling behavior but doesn’t enjoy most of the other advantages stated above.

If you want to create Meteor applications with separate code, you’ll have some modules that you’d like to share between them. If those modules are something the wider world could use, you should consider publishing them to a package system, either npm or Atmosphere, depending on whether the code is Meteor-specific or otherwise.

If the code is private, or of no interest to others, it typically makes sense to simply include the same module in both applications (you can do this with private npm modules). There are several ways to do this:

  1. a straightforward approach is simply to include the common code as a git submodule of both applications.
  2. alternatively, if you include both applications in a single repository, you can use symbolic links to include the common module inside both apps.

What is this 'sharing data' stuff?

Another important consideration is how you’ll share the data between your different applications. The simplest approach is to point both applications at the same MONGO_URL and allow both applications to read and write from the database directly. This works well thanks to Meteor’s support for reactivity through the database. When one app changes some data in MongoDB, users of any other app connected to the database will see the changes immediately thanks to Meteor’s livequery.

However, in some cases it’s better to allow one application to be the master and control access to the data for other applications via an API. This can help if you want to deploy the different applications on different schedules and need to be conservative about how the data changes.

The simplest way to provide a server-server API is to use Meteor’s built-in DDP protocol directly. This is the same way your Meteor client gets data from your server, but you can also use it to communicate between different applications. You can use DDP.connect() to connect from a “client” server to the master server, and then use the connection object returned to make method calls and read from publications.

What is this 'sharing accounts' stuff?

If you have two servers that access the same database and you want authenticated users to make DDP calls across the both of them, you can use the resume token set on one connection to login on the other. If your user has connected to server A, then you can use DDP.connect() to open a connection to server B, and pass in server A’s resume token to authenticate on server B. As both servers are using the same DB, the same server token will work in both cases. The code to authenticate looks like this:

// This is server A's token as the default `Accounts` points at our server
const token = Accounts._storedLoginToken();

// We create a *second* accounts client pointing at server B
const app2 = DDP.connect('url://of.server.b');
const accounts2 = new AccountsClient({ connection: app2 });

// Now we can login with the token. Further calls to `accounts2` will be authenticated
accounts2.loginWithToken(token);

You can see a proof of concept of this architecture in an example repository.

How can we use CSS preprocessor with Meteor?

There are three CSS pre-processors that are particularly popular right now: Sass, Less.js, Stylus. They all have their pros and cons, and different people have different preferences, just like with JavaScript transpiled languages. The most popular one at the time of writing seems to be Sass with the SCSS syntax. Popular CSS frameworks like Bootstrap 4 and more are switching to Sass, and the C++ LibSass implementation appears to be faster than some of the other compilers available.

CSS framework compatibility should be a primary concern when picking a pre-processor, because a framework written with Less won’t be compatible with one written in Sass.

An important feature shared by all of the available CSS pre-processors is the ability to import files. This lets you split your CSS into smaller pieces, and provides a lot of the same benefits that you get from JavaScript modules:

  1. You can control the load order of files by encoding dependencies through imports, since the load order of CSS matters.
  2. You can create reusable CSS “modules” that just have variables and mixins and don’t actually generate any CSS.

In Meteor, each of your .scss, .less, or .styl source files will be one of two types: “source” or “import”. A “source” file is evaluated eagerly and adds its compiled form to the CSS of the app immediately. An “import” file is evaluated only if imported from some other file and can be used to share common mixins and variables between different CSS files in your app. Read the documentation for each package listed below to see how to indicate which files are source files vs. imports.

See more at https://guide.meteor.com/build-tool.html#css-which-preprocessor

How can we build our own build plugin?

The most powerful feature of Meteor’s build system is the ability to define custom build plugins. If you find yourself writing scripts that mangle one type of file into another, merge multiple files, or something else, it’s likely that these scripts would be better implemented as a build plugin. The ecmascript, templating, and coffeescript packages are all implemented as build plugins, so you can replace them with your own versions if you want to!

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License