Quantcast
Channel: Meteor Blog - Medium
Viewing all 160 articles
Browse latest View live

Modulus is shutting down to become Xervo.


An Interview with Rohit Bakhshi, Galaxy Product Manager, Meteor Development Group

Meteor in 2017

Using Promises and async/await in Meteor

Protect your database: Galaxy supports IP whitelisting!

How to stop Ubuntu Xenial from randomly killing your big processes

Building a CMS-powered blog in Meteor with a headless CMS

Using Promises on the Client in Meteor


Announcing Meteor 1.4.3

Logging infrastructure changes in Galaxy

Dynamic imports in Meteor 1.5

Meteor 1.5 ❤ React Loadable

$
0
0

Spoiler: it just works

If you keep up with the latest JavaScript news, you might have seen this article by james kyle about his React Loadable project, which establishes a new pattern for using dynamic import(...) to fetch React components and display loading indicators while they load.

I especially love this graphic illustrating the difference between a)using dynamic import(...) at the routing level and b) using it at the component level:

dynamic components vs. dynamic routing
Route-based (left/red) vs. component-based (right/green) dynamic module loading

Testing react-loadable with Meteor 1.5

I was naturally curious if react-loadable would work in Meteor 1.5-beta.10, since Meteor should be able to take full advantage of these finer-grained module groupings. So, this morning I started with the react-loadable-example repository and attempted to turn it into a typical Meteor app.

I’m happy to say that the conversion was a success, as you can see from the changes that I made. These changes were pretty predictable:

  1. Borrowing the .meteor directory from a fresh Meteor 1.5 app: meteor/react-loadable-example@2ea8ad5
  2. Reorganizing the example code to have a typical Meteor application structure (client and imports directories, static-html-style HTML, etc.): meteor/react-loadable-example@707028d
  3. Getting rid of unnecessary Babel/Webpack dependencies and configuration files (my favorite commit): meteor/react-loadable-example@1d5a12d

Now, these changes were only necessary because I was starting from an existing Webpack/Babel-based app. If you already have a Meteor app, or you’re starting one from scratch, you would just meteor npm install --save react-loadable, and start writing code using the Loadable component, in which case none of these changes would be necessary.

The react-loadable-example app uses yarn instead of npm, which works perfectly well with Meteor, though we recommend using meteor yarn to guarantee the correct version of Node. If you're not already using meteor yarn, just meteor npm install --global yarn to make it work.

Try it out yourself!

If you want to try out the example app yourself, just follow these steps from the README.md file:

git clone git@github.com:meteor/react-loadable-example.git
cd react-loadable-example
meteor npm install --global yarn # if necessary
meteor yarn
meteor run

Open up localhost:3000 in your browser, and behold the “Loaded!” text. If you watch very carefully, you’ll see “Loading…” appear briefly before “Loaded!” replaces it. The delay is pretty short, but it’s also artificial. You wouldn’t be able to see the “Loading…” indicator at all, if this 400ms delay was not included for demonstration purposes.

As excited as I am that react-loadable works in Meteor 1.5, your experience may differ from mine, so I encourage everyone to play with this example app, or try out react-loadable in your own React-based apps. If you're confused by anything along the way, your feedback (on GitHub) will directly improve Meteor 1.5.


Meteor 1.5 ❤ React Loadable was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Leverage the power of Meteor with any client-side framework

$
0
0

Introduction to Meteor-Client-Bundler

Meteor Javascript Client bundle can run on any frontend app

Meteor was first released back in 2011, and since then it’s been one of the most powerful platforms for web developers. It brought many new concepts to the table — one of the more powerful ones is where the client, server and the database can share code, almost the same API and code snippets, which really accelerated the development process.

This has been a very big advantage that’s proven itself to be worthy, but has also created a misconception that Meteor is a monolith that can’t be broken down to smaller parts. But in fact, when you build a Meteor app for deployment to Galaxy or any other hosting platform, Meteor essentially generates a stand-alone Node application that you can run anywhere Node is installed. This built application can be easily consumed by a wide variety other tools that work with Node and Javascript apps.

In this post, I will show how you can use your existing React, Angular, or WebPack front-end app (or break up your existing Meteor front-end app away from the Meteor CLI) while still using Meteor’s benefits like Meteor Collections, Minimongo, real time updates and DDP, accounts packages and more…

Introducing Meteor Client Bundler

Two example scenarios could be: a) We want to use React Native’s CLI to build our client, since it provides us with native mobile components, and a configurable bundler; or b) We want to use WebPack and the great create-react-app.

Because we’re using Meteor, you might think we’re obligated to use the Meteor CLI, leaving WebPack’s great tools impractical to use. We can therefore ask the following question: “Is there a way to use WebPack, or any other similar tool, to create our client, and Meteor as our backend?” Well folks, the answer is — YES!

I present you — Meteor Client Bundler (it’s a long name, so we’re gonna refer it as MCB).

MCB, as we can infer, is a module-bundler which will take a bunch of Meteor packages and bundle them into a single script, based on a specified configuration. This means we can load Meteor’s core client-script, along with other desired packages, like mys:accounts-phone, jalik:ufs, matb33:collection-hooks etc into any front-end app!

This will give us the ability to create two separate projects: one is made with WebPack CLI (the client) and other is made with Meteor’s CLI (the server). Furthermore, with a little help from bundling tools like Webpack, we can even achieve the effect of shared code snippets between the two apps, which will be shown further in this article.

Some of the advantages of such a strategy are:

  • Applications which are not based on Meteor can use the DDP client to fetch data from a Meteor-service
  • We can gradually migrate outdated front-end applications into Meteor
  • We can use other CLI tools besides Meteor’s like WebPack, Angular and Ionic CLIs and more and not be locked in on a single CLI
  • Use Meteor when and where it excels and where it fits your needs

I believe that through practical example you can get the hang of it and understand exactly what I’m talking about, by simply fulfilling the scenario described in the second paragraph.

How it works

Let’s dive in! We will begin with creating our client using create-react-app, by running the following command:

$ create-react-app my-frontend-app

Then, we will create a web API service using Meteor’s CLI by typing the following command:

$ meteor create api

Now that they are both created, Let’s connect them to each other, so the React client will know how to use Meteor collections and retrieve data from them using MCB.

First, you’ll need to install MCB globally using NPM using the following command:

$ npm install -g meteor-client-bundler

This will make MCB available globally as a CLI under the name meteor-client:

$ meteor-client — help

Thanks to MCB, we can create a Meteor client with all the necessary dependencies in it using the bundle command. The bundle command takes a configuration file and can be operated differently. The easiest and fastest solution would be providing it the path where the Meteor server is at, using the -s, — source <dirpath> option:

$ meteor-client bundle — source=api

This will create a new file called meteor-client.js under the directory node_modules, which can easily be loaded anywhere in the project like so:

import “meteor-client”;

If you want, you can change the output destination by providing a -d, — destination <filepath> option:

$ meteor-client bundle — destination=dist/meteor-client.bundle.js

Moreover, you don’t necessarily have to have the client and server on the same machine. The server can be hosted on a completely different computer, yet we can generate its appropriate client. This can be achieved by providing the -c, — config <configpath> option:

$ meteor-client bundle — config=meteor-client.config.json

Here’s an example config:

{
“runtime”: {
“DDP_DEFAULT_CONNECTION_URL”: “http://127.0.0.1:8100
},
“import”: [
“meteor-base@1.0.4”,
“mongo@1.1.14”,
“reactive-var@1.0.11”,
“jquery@1.11.10”,
“tracker@1.1.1”,
“standard-minifier-css@1.3.2”,
“standard-minifier-js@1.2.1”,
“es5-shim@4.6.15”,
“ecmascript@0.6.1”,
“shell-server@0.2.1”
]
}

Each field in the configuration file represents the following:

  • runtime — Meteor’s runtime config. Most commonly used to set the URL of the Meteor server we would like to interface with.
  • import — A list of packages we would like to include in our bundle. The bundle will also take care of loading them in the right order and with the required dependencies

You can also specify the server’s URL explicitly using the — url <urlpath> option:

$ meteor-client bundle — url=http://127.0.0.1:8100

How MCB works under the hood

Basically, MCB takes a list of Meteor packages we would like to load in our client. Based on these, it builds a temporary Meteor application and composes a unified file from the fetched packages, with a focus in their chronological loading order.

Still sharing Client and Server code

If you’re using any sort of a configurable module bundler like Webpack, you can recreate one of Meteor’s greatest behaviors where we can load the same script on both client and server with a single definition. This will require you to add an alias for the server’s directory path, and define a special handler for imported Meteor packages. In the case of Webpack, the config extension should look like so:

module.exports = {
// …
resolve: {
alias: [
api: “path/to/meteor/server”
]
},
externals: function (context, request, callback) {
var match = request.match(/^meteor\/(.+)$/);
var pack = match && match[1];
if (pack) {
callback(null, ‘Package[“‘ + pack + ‘“]’);
}
}
// …
};

This should achieve the following result on the client:

Import { FooCollection, BarCollection } from “api/collections”;
Import { Accounts } from “meteor/accounts-base”;

And at the same time, we can use almost identical importations on the server:

Import { FooCollection, BarCollection } from “./collections”;
Import { Accounts } from “meteor/accounts-base”;

In conclusion

These were the key-concepts of Meteor Client Bundler. If you want to build an app while using the Meteor platform for all your stack, or you want to interact with a Meteor server and use any other front-end library or setup, MCB got everything you need, and will get you on the right track.

For a simple example of using MBC, check out this React-Meteor Todo app remake and for a more full-scale app check out the Ionic CLI WhatsApp clone project.

More information regards MCB can be found in its official Github repository over here: https://github.com/Urigo/meteor-client-bundler

I want to thank Eytan Manor for helping me make this library!

Leverage the power of Meteor with any client-side framework was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

MDG acquires Kadira APM

$
0
0

What’s next for the best performance monitoring tool for Meteor apps

I’m excited to announce that Meteor Development Group has signed a definitive agreement to acquire the Kadira APM product.

The Kadira APM dashboard.

Since Arunoda’s announcement last December that Kadira would be shutting down, we’ve explored a number of options to ensure continuity and a bright future for Meteor’s best application performance tool. Unsurprisingly, many Meteor developers have told us that Kadira is the most valuable tool they use to scale, tune, and analyze their apps. I’m delighted where we’ve landed — bringing Kadira APM under the MDG umbrella makes a lot of sense as part of our commitment to the Meteor platform and developer community.

We’re working closely now with Arunoda and a number of Kadira customers. If you’d like to get early access to our efforts, please let us know. In the coming weeks, we’ll open things up to everyone and organize a transition off the old Kadira system.

I hope you’re as excited as we are. This agreement puts Meteor APM on solid footing, lets us respond even faster to customer requests, and opens up many opportunities for us to coordinate improvements across Meteor, Galaxy, and Kadira that help teams with critical applications in production.

Stay tuned as there will be more to share soon.


MDG acquires Kadira APM was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

You can deploy to Galaxy Asia-Pacific starting today!

$
0
0

We’re excited to announce that Galaxy is now generally available in the Asia-Pacific region!

If you have data locality requirements or want more responsive performance for users in Asia, you can now enjoy zero-devops deployments that run in Galaxy’s AWS ap-southeast2 (Sydney) region.

Since launching Galaxy Europe last year, we’ve seen that region grow to support production apps for hundreds of customers.

In surveying Meteor users worldwide, we heard requests that Asia-Pacific, and specifically Sydney, should be next. We’ve been in Early Access for Galaxy Asia-Pacific over the past week and during that period multiple customers have successfully deployed and run their apps in that region.

To deploy to your choice of AWS regions, including USA, Europe, or Asia-Pacific, use our guide!


You can deploy to Galaxy Asia-Pacific starting today! was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.


Kadira APM is now open source

$
0
0

Today we’re happy to announce that we have open sourced the code for the Kadira APM product for monitoring the performance of Meteor applications!

Before I dive into the details, a bit of background on our acquisition of Kadira APM and why we’re open sourcing the code:

Why we’re open sourcing Kadira

We heard in December 2016 that the Kadira APM service was scheduled to be shut down in early 2017. Because we know how important this tool is to everybody running Meteor apps in production, we moved quickly to acquire the code to ensure that everybody in the community could continue using it forever.

We worked with Kadira to extend the shut-down date of the current Kadira APM service to May 15th to give everyone a chance to migrate to another solution, whether one based on this original source code or by using the new, commercial Meteor APM we’ve integrated into our Galaxy hosting service.

How to get the Kadira code

We have made the original Kadira code available under the MIT License at this GitHub repo — https://github.com/kadira-open/kadira-server. This license means that anyone can use or modify the source code to self-host Kadira or even start a commercial project.

As the code we’re using for our commercial Meteor APM product has diverged from Kadira’s original code, we will not maintain or host an active Kadira open source project ourselves. This means the repo will be read-only: we will not be answering any opened issues or accepting pull requests.

That being said, we are excited that some maintainers have already stepped forward to create a community fork, and we’re doing what we can to help kick off that effort with Arunoda’s help. We look forward to see how the project develops under their leadership and will make sure to update you on their progress in this publication!


Kadira APM is now open source was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Announcing Meteor 1.4.4

$
0
0

Node.js and npm updates, Cordova Google Sign-In, and hybrid minification

Today we’re excited to announce Meteor 1.4.4, a routine incremental release to update core dependencies, fix bugs, improve stability, and address a critical Google authentication change for Cordova apps. Read on for details on upgrading, release improvements, and what’s coming next.

How to upgrade

To update an existing app to Meteor 1.4.4, simply run meteor update in any Meteor application directory.

As a reminder, make sure your application’s .meteor directory is committed to your version-control system (e.g. Git, Subversion, etc.) so it’s easy to roll-back if you ever encounter problems during any upgrade.

Node.js, npm, and node-gyp

As usual with new Meteor releases, underlying dependencies of the framework have been updated to their latest versions in Meteor 1.4.4, with Node.js at 4.8.1 and npm at 4.4.4. Additionally, Windows developers using Visual Studio 2017 will benefit from improved support for binary npm packages thanks to the update of node-gyp to 3.6.0.

See the Node.js 4.8.1 release notes for the full details, including numerous bug fixes and performance benefits.

Critical Cordova updates for Google OAuth

Meteor developers with mobile apps based on Cordova, who let their users authenticate with Google OAuth (via the accounts-google, google, or google-oauth packages): please pay close attention to this section!

Google announced in August 2016 that they would be blocking OAuth logins from embedded web-views (such as the WebView UI element on Android and UIWebView/WKWebView on iOS), and started displaying the following message on the iOS and Android consent pages late last year:

Notice for developers: authorization requests in embedded browsers will be blocked on April 20, 2017.

If this describes your Cordova application, be sure to update accounts-google to version 1.1.2 to enable the new login process which internally utilizes the Google Sign-In API (thanks to Eddy Verbruggen’s cordova-plugin-googleplus Cordova package).

Please let us know if you have any trouble with this transition, and soon!

Minifier improvements for ES6

“Minification” is a common optimization to reduce the amount of code that has to be downloaded by clients in production. By removing comments and whitespace, transforming superLongVerboseAndDescriptive variable names into single-character equivalents, eliminating certain kinds of unreachable code, and restructuring syntax to save a few characters here and there, the minifier can easily reduce client bundle sizes by 80% or more.

Minification usually takes place after a tool like Babel has compiled modern JavaScript syntax to older, more widely supported syntax, so the minifier generally does not need to handle bleeding-edge syntax. Over time, however, the bleeding-edge becomes the commonplace, and we eventually stop needing to compile it into something else. That’s progress, but the minifier has to keep up. Lately, we’ve seen an increase in complaints that our minifier (based on UglifyJS) was failing to handle common syntax.

While it was tempting to replace UglifyJS with a different minifier, none of the other options were nearly as fast, so we adopted a hybrid solution: when UglifyJS fails to minify a given file, we now catch the exception and fall back to the slower (but more future-friendly) Babili minifier. With this simple strategy, Meteor developers automatically benefit whenever UglifyJS improves its ECMAScript support or whenever Babili improves its performance.

Best of all, this Babili integration was driven almost entirely by the hard work of community contributor @sethmurphy18. Thank you, Seth!

New export-from syntax

Speaking of bleeding-edge ECMAScript features, Meteor 1.4.4 introduces support for two new kinds of export ... from "./module" declarations:

As in previous Meteor releases, the module.importSync API is provided by the Reify module compiler, though it used to be called module.import.

The complete ECMAScript proposals with additional explanation can be found here and here. In short, these two new styles of export declaration make it slightly easier to re-export symbols from other modules without having to import those symbols with temporary names and then export them in a separate declaration.

And much more!

Many other changes and bug-fixes made it into Meteor 1.4.4, including better support for custom .babelrc plugins that modify import declarations and improved Galaxy deployments for Windows users. Check out the full release notes in the Meteor repository.

What’s next?

As the version number suggests, Meteor 1.4.4 is an incremental release in the Meteor 1.4 line.

We are simultaneously working on a more significant and exciting Meteor 1.5 release, which you can follow here. To try the new features of Meteor 1.5, run meteor update --release 1.5-beta.14 in any application directory, though please make sure your .meteor directory is committed to version control so you can roll back easily. Though Meteor 1.5 is still in “beta,” we consider it relatively stable, so please report any bugs you encounter.

Longer term goals along with periodic status updates are outlined in Roadmap.md. Worth noting here is that the effort to upgrade Meteor to Node 6 and beyond has recently made substantial progress. There’s even a very early preview release you can try, though please keep in mind that no version of Meteor 1.6 is ready for production yet.


Announcing Meteor 1.4.4 was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Introducing Galaxy Professional & Built-in APM

$
0
0

We’re excited to announce that Galaxy Professional, an enhanced tier of containers that includes built-in APM, is now available to all Galaxy customers.

Bringing APM to Galaxy

When we learned last December that Kadira APM was shutting down, we put together a plan to answer two questions: 1. What could we do right away to ensure everyone would have access to a critical Meteor APM tool; and 2. Were there opportunities this change might create for the Meteor developer community in the long term?

After acquiring the Kadira codebase, we considered keeping it standalone in its current form, but we ultimately decided that path wasn’t right for us. For one thing, Kadira’s SaaS infrastructure, monitoring, and billing systems are completely different from Galaxy’s, so we would be taking on twice the operational burden instead of leveraging our existing systems. More importantly, we felt there was an opportunity to deliver something really great for our thousands of Galaxy customers — a fully integrated APM option that we could keep investing in.

Familiar APM functionality now integrated with Galaxy!

What we’re releasing today is the first step on that path. We’ve tied Kadira’s core instrumentation into Galaxy’s container-based model and utility billing system. Every app on Galaxy is now a click away from great APM features like subscription timing and error tracking. Longer term, we’re going to integrate additional APM functionality deeper into Meteor core and Galaxy, roll out alerting features based on it, and investigate what else we can do from this starting point. We’d love to hear your ideas. For those who want to roll their own Kadira APM solution, we also released the original Kadira source code as an open source distribution last week.

This plan is an example of how we think about our role as the company behind Meteor. You can count on us to take care of infrastructure details and have your back on the platform, so you can focus on writing great JavaScript and building your business.

Introducing Galaxy Professional

Launching today, Galaxy Professional is a new type of container that includes must-have features like for critical apps, like built-in Meteor APM and IP whitelisting, all in one place. You can turn on Galaxy Professional containers and get access to APM with a single click for any app in your account. It’s all ready to go — as part of an early access rollout, some of our largest Galaxy customers have already been running their most important apps on Professional containers.

If you have an important app that needs features like performance monitoring, we recommend running it on Galaxy Professional. The basic Galaxy functionality you have come to rely on will be called Galaxy Essentials going forward. You can select either Essentials or Professional containers to run each app in your account. Going forward, we’ll make investments in both Galaxy Essentials and Professional. New features that make it easier to deploy and reliably run apps will go into Essentials; features that only make sense for critical apps will go into Professional.

Extra Security & Support

Galaxy Professional also includes IP whitelisting, a key feature to secure connections between Meteor apps and external services including MongoDB hosts or 3rd-party API providers. Since IP whitelisting has non-trivial costs for us to deliver, it will only be available for apps deployed on Galaxy Professional containers going forward. If you are already using IP whitelisting today as part of your application, please email support@meteor.com and let us know — we’ll work on a migration plan with you.

On top of IP whitelisting, Galaxy Pro also comes with prioritized support. Any standard support cases submitted by customers using Galaxy Pro for any app in their account will receive “top of queue” attention by our support team.

Galaxy Pricing

Galaxy Essentials pricing remains unchanged at $0.08 per gb-ecu hour across all container sizes and regions.

Galaxy Professional is priced at $0.11 per gb-ecu hour across all container sizes in all regions (US, EU, APAC). Similar to Essentials, you can also pre-pay annually for Galaxy Professional container capacity to save 20–30% off pay-as-you-go rates. Contact Galaxy sales to learn more about pre-paid options for either Essentials or Professional container capacity.

Enable Galaxy Professional with a single click for any app!

Start using Galaxy Professional for your important apps with a single click to get built-in APM and enhanced security and support!


Introducing Galaxy Professional & Built-in APM was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Fun with Meteor Methods

$
0
0

Exploring the concurrency of method calls

This post builds on “Using Promises and async/await in Meteor” and “Using Promises on the Client in Meteor”. It compares “traditional” methods with async methods and gives some insight into why you should (or should not) use this.unblock().

Introduction

You just can’t avoid asynchronous code in JavaScript. Not even in Meteor with sync-style coding on the server (where Meteor hides the asynchronous nature of much of JavaScript behind a facade of Fibers and Futures)— it is, after all, sync-style, not sync.

With async and await now able to replace much of that facade and clarify where asynchronous components are used, it’s a good time to step back and look at possibly unexpected pitfalls of sync-style coding around asynchronous functions.

Meteor Methods — a Recap.

Meteor methods provide predictable running of server code on behalf of the client. As requests arrive from each client they are queued for execution in the order they appear. As each method runs to completion it returns its data to the client.

We can see this at work with the following code:

The logClient method takes the parameter value (p) and simulates the effect of calling something like a REST endpoint by adding latency to the run-time. I used Meteor._sleepForMs (a Fiber based method) for adding in this latency.

On the client, we’re firing off five method calls. When each completes, we push the result onto a reactive array. We also measure the time taken to complete the execution of the calls. Note that although the calls are made sequentially, we do not wait for each to complete before firing off the next. This is Asynchronous JavaScript 101 — the code keeps running while we wait for the results.

On the server, we see this:

I20170208-14:14:06.974(0)? Starting sequence 1
I20170208-14:14:07.875(0)? Completed sequence 1
I20170208-14:14:07.876(0)? Starting sequence 2
I20170208-14:14:08.677(0)? Completed sequence 2
I20170208-14:14:08.678(0)? Starting sequence 3
I20170208-14:14:09.381(0)? Completed sequence 3
I20170208-14:14:09.381(0)? Starting sequence 4
I20170208-14:14:09.983(0)? Completed sequence 4
I20170208-14:14:09.984(0)? Starting sequence 5
I20170208-14:14:10.485(0)? Completed sequence 5

We see each call running to completion in sequence, with gaps of approximately 900, 800, 700, 600 and 500ms — the method is queuing client requests and executing them in order. The end-to-end time on the server is ~3.5 seconds. On the browser, the execution time is 1–2ms, because we’re not waiting for any call to complete before the next is queued:

Sequence: 1, Expected time: 900ms, Actual time: 902ms
Sequence: 2, Expected time: 800ms, Actual time: 801ms
Sequence: 3, Expected time: 700ms, Actual time: 704ms
Sequence: 4, Expected time: 600ms, Actual time: 603ms
Sequence: 5, Expected time: 500ms, Actual time: 502ms
Execution Time on Client = 1ms

In fact, the browser reports Execution Time on Client = 1ms long before the individual sequence report lines start to appear.

This is a useful technique for quickly kicking off actions for which you don’t need an immediate response. It may be that you are making some MongoDB calls and you have a pub/sub which will eventually ensure your client view is consistent.

However, if you need to use the result of a call in the next call, then it becomes necessary to wait until the preceding call has completed before starting the next. This example takes the returned response object and increments the value of p that was passed in (available in response.sequence) to get the next value to use:

The server output is as before, but the client now reports as follows:

Sequence: 1, Expected time: 900ms, Actual time: 904ms
Sequence: 2, Expected time: 800ms, Actual time: 802ms
Sequence: 3, Expected time: 700ms, Actual time: 700ms
Sequence: 4, Expected time: 600ms, Actual time: 602ms
Sequence: 5, Expected time: 500ms, Actual time: 501ms
Execution Time on Client = 3570ms

All is good — client and server agree on what’s happening and how long it takes for each step and also how long the total time is.

this.unblock()

From the Meteor docs (linked above):

On the server, methods from a given client run one at a time. The N+1th invocation from a client won’t start until the Nth invocation returns. However, you can change this by calling this.unblock. This will allow the N+1th invocation to start running in a new fiber.

The important part of that quote is the first sentence: “On the server, methods from a given client run one at a time.”

The unstated corollary to that is that methods from different clients run concurrently. However, oftentimes you see this.unblock() being used to allow several clients to execute a method at the same time — this is unnecessary — it’s the standard way Meteor methods work (without using this.unblock()).

The only use for this.unblock() is to allow a client to execute a method while that same client is already executing a method (the same method or another one). Unsurprisingly, this is a rare requirement.

Here’s what the server’s console shows when I call the method from two different clients at roughly the same time without using this.unblock():

I20170227-17:05:29.099(0)? Starting sequence 1
I20170227-17:05:29.910(0)? Starting sequence 1
I20170227-17:05:29.999(0)? Completed sequence 1
I20170227-17:05:30.013(0)? Starting sequence 2
I20170227-17:05:30.811(0)? Completed sequence 1
I20170227-17:05:30.812(0)? Completed sequence 2
I20170227-17:05:30.816(0)? Starting sequence 2
I20170227-17:05:30.820(0)? Starting sequence 3
I20170227-17:05:31.523(0)? Completed sequence 3
I20170227-17:05:31.527(0)? Starting sequence 4
I20170227-17:05:31.619(0)? Completed sequence 2
I20170227-17:05:31.623(0)? Starting sequence 3
I20170227-17:05:32.127(0)? Completed sequence 4
I20170227-17:05:32.131(0)? Starting sequence 5
I20170227-17:05:32.324(0)? Completed sequence 3
I20170227-17:05:32.327(0)? Starting sequence 4
I20170227-17:05:32.632(0)? Completed sequence 5
I20170227-17:05:32.928(0)? Completed sequence 4
I20170227-17:05:32.933(0)? Starting sequence 5
I20170227-17:05:33.432(0)? Completed sequence 5

You can see from the sequence numbers that the methods are already running concurrently (the end-to-end time was 4.3 seconds and associated client timings were 3569ms and 3568ms).

Now, add in this.unblock():

We’ll just run this with one client for clarity. On the server we get:

I20170227-17:20:49.267(0)? Starting sequence 1
I20170227-17:20:50.168(0)? Completed sequence 1
I20170227-17:20:50.173(0)? Starting sequence 2
I20170227-17:20:50.973(0)? Completed sequence 2
I20170227-17:20:50.979(0)? Starting sequence 3
I20170227-17:20:51.681(0)? Completed sequence 3
I20170227-17:20:51.684(0)? Starting sequence 4
I20170227-17:20:52.285(0)? Completed sequence 4
I20170227-17:20:52.288(0)? Starting sequence 5
I20170227-17:20:52.789(0)? Completed sequence 5

In the client we get:

Sequence: 1, Expected time: 900ms, Actual time: 901ms 
Sequence: 2, Expected time: 800ms, Actual time: 802ms
Sequence: 3, Expected time: 700ms, Actual time: 702ms
Sequence: 4, Expected time: 600ms, Actual time: 600ms
Sequence: 5, Expected time: 500ms, Actual time: 501ms
Execution Time on Client = 3562ms

So, no real change. Why? Well, we’re still using the (deeply nested) client code for dependent calls. Each call has to run to completion before the next is started. Let’s re-run using the original (independent client calls) code.

On the server we get:

I20170208-14:51:38.422(0)? Starting sequence 1
I20170208-14:51:38.422(0)? Starting sequence 2
I20170208-14:51:38.423(0)? Starting sequence 3
I20170208-14:51:38.423(0)? Starting sequence 4
I20170208-14:51:38.423(0)? Starting sequence 5
I20170208-14:51:38.925(0)? Completed sequence 5
I20170208-14:51:39.027(0)? Completed sequence 4
I20170208-14:51:39.124(0)? Completed sequence 3
I20170208-14:51:39.223(0)? Completed sequence 2
I20170208-14:51:39.321(0)? Completed sequence 1

An end-to-end time of 900ms — much better — and now we can clearly see how the method calls are being optimally processed. That 900ms is also entirely expected; it’s the time for the longest-running method to complete. All others fit inside that time.

In the browser we get:

Sequence: 5, Expected time: 500ms, Actual time: 502ms
Sequence: 4, Expected time: 600ms, Actual time: 603ms
Sequence: 3, Expected time: 700ms, Actual time: 701ms
Sequence: 2, Expected time: 800ms, Actual time: 801ms
Sequence: 1, Expected time: 900ms, Actual time: 900ms
Execution Time on Client = 1ms

Which is also what we expect here: method call 5 completes first, followed by 4, 3, 2 and 1. We can measure the actual time taken by rewriting the client code to use Promises and making use of the Promise.all method to collate all the returned data. For the basics of using Promises on the client, check out Using Promises on the Client in Meteor”.

Sequence: 1, Expected time: 900ms, Actual time: 900ms
Sequence: 2, Expected time: 800ms, Actual time: 801ms
Sequence: 3, Expected time: 700ms, Actual time: 700ms
Sequence: 4, Expected time: 600ms, Actual time: 601ms
Sequence: 5, Expected time: 500ms, Actual time: 501ms
Execution Time on Client = 951ms

Awesome! But wait — the server reported that requests were completed in the order 5–1, however the client is reporting it as 1–5. Here’s the thing: Promise.all orders the result array to match the order in the original request array, even though the individual Promises may resolve in a different order. This is an important point: the result array implies an order which may not be present. If you do need ordered resolution, enforce it at the client.

async methods

In Using Promises and async/await in Meteor we considered how we might use ES7 async/await in our Meteor methods. Let’s revise our method code and look at what happens when we use it in various ways from the client.

We added a small, Promise based sleep function to replace Meteor._sleepForMs().

First, we run this with the asynchronous client code we used right at the start.

On the server we see this:

I20170216-13:12:48.476(0)? Starting sequence 1
I20170216-13:12:48.477(0)? Starting sequence 2
I20170216-13:12:48.477(0)? Starting sequence 3
I20170216-13:12:48.479(0)? Starting sequence 4
I20170216-13:12:48.479(0)? Starting sequence 5
I20170216-13:12:48.978(0)? Completed sequence 5
I20170216-13:12:49.080(0)? Completed sequence 4
I20170216-13:12:49.177(0)? Completed sequence 3
I20170216-13:12:49.278(0)? Completed sequence 2
I20170216-13:12:49.377(0)? Completed sequence 1

On the client we see this:

Sequence: 5, Expected time: 500ms, Actual time: 501ms
Sequence: 4, Expected time: 600ms, Actual time: 600ms
Sequence: 3, Expected time: 700ms, Actual time: 703ms
Sequence: 2, Expected time: 800ms, Actual time: 801ms
Sequence: 1, Expected time: 900ms, Actual time: 900ms
Execution Time on Client = 1ms

This is the same behavior we got when we used this.unblock() earlier, even though we didn’t use it this time! It turns out that an async method behaves like a normal method which uses this.unblock().

Now let’s try the nested (non-Promise) client code which waits for each method to complete before starting the next.

On the server we see this:

I20170216-13:17:38.208(0)? Starting sequence 1
I20170216-13:17:39.109(0)? Completed sequence 1
I20170216-13:17:39.114(0)? Starting sequence 2
I20170216-13:17:39.915(0)? Completed sequence 2
I20170216-13:17:39.920(0)? Starting sequence 3
I20170216-13:17:40.621(0)? Completed sequence 3
I20170216-13:17:40.626(0)? Starting sequence 4
I20170216-13:17:41.227(0)? Completed sequence 4
I20170216-13:17:41.232(0)? Starting sequence 5
I20170216-13:17:41.732(0)? Completed sequence 5

On the client we see this:

Sequence: 1, Expected time: 900ms, Actual time: 900ms
Sequence: 2, Expected time: 800ms, Actual time: 802ms
Sequence: 3, Expected time: 700ms, Actual time: 701ms
Sequence: 4, Expected time: 600ms, Actual time: 602ms
Sequence: 5, Expected time: 500ms, Actual time: 501ms
Execution Time on Client = 3569ms

In other words, the expected, predictable sequential order of execution.

Finally, we’ll use the Promise.all version of the client code.

On the server we see this:

I20170216-13:20:19.227(0)? Starting sequence 1
I20170216-13:20:19.288(0)? Starting sequence 2
I20170216-13:20:19.290(0)? Starting sequence 3
I20170216-13:20:19.290(0)? Starting sequence 4
I20170216-13:20:19.291(0)? Starting sequence 5
I20170216-13:20:19.744(0)? Completed sequence 5
I20170216-13:20:19.829(0)? Completed sequence 4
I20170216-13:20:19.931(0)? Completed sequence 3
I20170216-13:20:20.031(0)? Completed sequence 2
I20170216-13:20:20.128(0)? Completed sequence 1

On the client we see this:

Sequence: 1, Expected time: 900ms, Actual time: 907ms
Sequence: 2, Expected time: 800ms, Actual time: 801ms
Sequence: 3, Expected time: 700ms, Actual time: 701ms
Sequence: 4, Expected time: 600ms, Actual time: 602ms
Sequence: 5, Expected time: 500ms, Actual time: 500ms
Execution Time on Client = 912ms

Again, that’s the same behavior we saw before with this.unblock() in the server.

In Conclusion

  1. Methods are independent as far as different clients are concerned. So for example, Bob’s client can call method A at the same time as Carol’s client calls method A — those method invocations will run concurrently — neither Bob nor Carol will wait for the other*.
  2. Using this.unblock() to try to improve (1) will do nothing — it’s already running as efficiently as it can.
  3. For any one client
    3.1. Methods are executed in the order they are called from the client — imagine a FIFO queue on the server for each client.
    3.2. If this.unblock() is not used, methods are also evaluated in order — the method runs to completion and then the queue is popped for the next method to execute.
    3.3. If this.unblock() is used (or you’re using async methods), methods may be evaluated out of order — the queue is popped until empty, each method starting up in a new fiber as soon as it’s popped. Methods finish independently of the order in which they were initially present in the queue. This may result in unpredictable interleaving which is a recipe for hard-to-diagnose, race-induced bugs. If you need to take advantage of this approach, you also need to be certain that it’s safe if your methods complete out of order.
  4. Use that async keyword as a handy reminder that you should check for interleaving safety.
  5. In order to avoid thinking about interleaving, you should enforce it at the client level (or use neither this.unblock(), nor async methods). It’s easier to do this using async/await on the client — the alternative is nesting and callback hell.
  6. If you’re using async methods, you don’t need this.unblock().

* This isn’t strictly true: Node.js is single threaded, so any CPU bound method will always hold off any other process until it completes (this.unblock() won’t help). However, if the method is running asynchronous code (typically some form of I/O), then the event loop will be made available to other clients, allowing multiple instances of the method to execute concurrently.


Fun with Meteor Methods was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Rewriting angular-meteor.com in Angular Universal

$
0
0
angular-meteor.com is now a universal app!

We recently finished re-writing and deploying our new angular-meteor.com website with completely new tooling using Angular Universal and our new tutorial infrastructure.

In this post, I’ll share our experience using Angular Universal, and introduce the tools that we created on top of it. We’ll write about (and open source) our new tutorial infrastructure in a following post, so stay tuned!

TL;DR

Our former website was a dynamic app. We wanted to rewrite it into a static website because:

  1. It needed a server and hosting.
  2. We needed a lot of tooling in order to make it SEO compatible.
  3. It loaded slowly.

We’re happy to say… The transition was successful! Check it out and take a look at the new tutorials here.

Here are the improvements this made possible:

  • The page loads much faster
  • No need for servers anymore, we use GitHub Pages

To accomplish this, we created a tool that takes various content types and renders it to any format we want:

  • Input sources — A unique markdown format for our tutorials and a JSDoc format.
  • Render targets — Our angular-meteor.com website, your own website or doc format, or a Medium post API.

Converting input sources to render outputs

Our new tooling is capable of getting input sources from various content types and generating output in any format we like. Currently, we published it as a package, which includes:

Tutorial as input

As part of the rewrite, we created a new tutorial infrastructure that we’ll talk about in a future post when we release a few more features. You can see it in action here — https://angular-meteor.com/tutorials/whatsapp2/ionic/setup

For the purpose of this post, the important thing to know about the infrastructure is that the code examples are being generated from a real app using real commits (inspired by Sashko Stubailo’s work on the Meteor tutorial).

The infrastructure renders markdown files with links to the git commits, and we need to turn those into a diff-box components with the actual code that changed in the commit, like here for example.

JSDoc as input

Let’s start again with the result of this section, so it will be simpler to understand: https://angular-meteor.com/api/angular2-meteor/latest/Meteor-RxJS

We want to use the JSDoc standard over our code (example), take this JSDoc definition, convert it into a standard markdown file, display it in our website, and finally expose it directly inside the repository of the package (example).

We wanted versioning because our API might change over time — that’s where Git comes to our aid. We also have a Git revision (commit id or tag) for each version of the package. That way, we can take a specific version of the file with it’s documentation from GitHub and generate the API reference for all of versions of the package and API docs.

Components, Directives, and utils

The Angular 2 components and directives are meant to display results of the markdown docs together with the special Git patch handlers. This means it’s using a regular markdown parser with the small addition of DiffBox, a Component we wrote that displays the changes in each commit in a diff format (just like a diff view in GitHub).

Also, we have directives that are useful for: navigation, creating links, displaying a list of steps of the tutorial, links to download those steps (based on git commit) and more.

We also have a route generator for the tutorial, which means that, based on your tutorial definition, this util will generate your routes for the Angular router with all the required resolve phase that the infrastructure needs (load files from GitHub, format, convert and so on).

Static HTML Generator

Our main output is our angular-meteor.com website. The utils wrap the sources with a beautiful design, custom pages and stylesheet, and then uses the last part of the infrastructure — the static page generator.

Using your application’s route definition (the generated tutorial routes, along with the custom pages you need), this tool loads the entire page (generated on the server side as we’re running in an Angular Universal environment) and saves it into a single HTML file that has no dependencies at all. The whole page is inside a single HTML file — no JS and no external CSS files!

Our next step is the deployment of this website, which is easy, because we are using an autonomous HTML files that every single HTTP server can serve. We chose GitHub Pages to host our website, so we don’t need any external server or hosting.

The Result

We managed to accomplish all of our goals for the new website:

We met our own needs:

  • It’s easy to maintain because it uses the same GitHub repository that stores the actual tutorial code.
  • It’s super fast and because it loads only static HTML files.
  • Its hosting is simple (GitHub Pages) and it has no server-side at all.

We created something that might be useful for others:

  • Extensions to Angular Universal that can accept your own inputs and outputs.
  • Tools for rendering markdown from remote source with Angular Universal.

Check out the website and code! Maybe you can find some utils for generating routes of API docs, or expose Components and Directives that you can use later to enrich your own website.

We saw that the Angular team has started working on a new angular.io implementation and would love to help with our tools and experiences from doing very similar work on our own website.

Most importantly — enjoy the new angular-meteor.com :)

Next steps for Angular-Meteor

In recent months, both Meteor and Angular have made huge leaps, so we have a lot of goodies to catch up on.

Our vision for the next version of Angular Meteor includes the following features:

But we want your help! If you’re interested in helping us tackle these exciting features, contact us directly!


Rewriting angular-meteor.com in Angular Universal was originally published in Meteor Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Viewing all 160 articles
Browse latest View live