Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
GitHub is a social repository for open-source projects based around the Git version control system, and its primary function is to make it easy to share code and collaborate on projects. But it's also a great learning tool. In this sidebar, we'll quickly go over a few ways you can use GitHub to follow along with Discover Meteor.
This sidebar assumes you're not that familiar with Git and GitHub. If you're already comfortable with both, feel free to skip on to the next chapter!
The basic working block of a git repository is a commit. You can think of a commit as a snapshot of your codebase's state at a given moment in time.
Instead of simply giving you the finished code for Microscope, we've taken these snapshots every step of the way, and you can see all of them online on GitHub.
For example, this is what the last commit of the previous chapter looks like:
<%= screenshot "s3-1", "A Git commit as shown on GitHub." %>
What you see here is the “diff” (for “difference”) of the post_item.js
file, in other words the changes introduced by this commit. In this case, we created the post_item.js
file from scratch, so all its contents are highlighted in green.
Let's compare with an example from later on in the book:
<%= screenshot "s3-2", "Modifying code." %>
This time, only the modified lines are highlighted in green.
And of course, sometimes you're not adding or modifying lines of code, but deleting them:
<%= screenshot "s3-3", "Deleting code." %>
So we've seen the first use of GitHub: seeing what's changed at a glance.
Git's commit view shows us the changes included in this commit, but sometimes you might want to look at files that haven't changed, just to make sure what their code is supposed to look like at this stage of the process.
Once again GitHub comes through for us. When you're on a commit page, click the Browse code button:
<%= screenshot "s3-5", "The Browse code button." %>
You'll now have access to the repo as it stands at a specific commit:
<%= screenshot "s3-6", "The repository at commit 3-2." %>
GitHub doesn't give us a lot of visual clues that we're looking at a commit, but you can compare with the “normal” master view and see at a glance that the file structure is different:
<%= screenshot "s3-7", "The repository at commit 14-2." %>
We've just seen how to browse a commit's entire code online on GitHub. But what if you want to do the same thing locally? For example, you might want to run the app locally at a specific commit to see how it's supposed to behave at this point in the process.
To do this, we'll take our first steps (well, in this book at least) with the git
command line utility. For starters, make sure you have Git installed. Then clone (in other words, download a copy locally) the Microscope repository with:
That github_microscope
at the end is simply the name of the local directory you'll be cloning the app into. Assuming you already have a pre-existing microscope
directory, just pick any different name (it doesn't need to have the same name as the GitHub repo).
Let's cd
into the repository so that we can start using the git
command line utility:
Now when we cloned the repository from GitHub, we downloaded all the code of the app, which means we're looking at the code for the last ever commit.
Thankfully, there is a way to go back in time and “check out” a specific commit without affecting the other ones. Let's try it out:
Git informs us that we are in “detached HEAD” state, which means that as far as Git is concerned, we can observe past commits but we can't modify them. You can think of it as a wizard inspecting the past through a crystal ball.
(Note that Git also has commands that let you change past commits. This would be more like a time traveller going back in time and possibly stepping on a butterfly, but it's outside the scope of this brief introduction.)
The reason why you were able to simply type chapter3-1
is that we've pre-tagged all of Microscope's commits with the correct chapter marker. If this weren't the case, you'd need to first find out the commit's hash, or unique identifier.
Once again, GitHub makes our life easier. You can find a commit's hash in the bottom right corner of the blue commit header box, as shown here:
<%= screenshot "s3-4", "Finding a commit hash." %>
So let's try it with the hash instead of a tag (if this specific hash doesn't work, feel free to get another one from GitHub):
And finally, what if we want to stop looking into our magic crystal ball and come back to the present? We tell Git that we want to check out the master branch:
Note that you can also run the app with the meteor
command at any point in the process, even when in “detached HEAD” state. You might need to run a quick meteor update
first if Meteor complains about missing packages, since package code is not included in Microscope's Git repo.
Here's another common scenario: you're looking at a file and notice some changes you hadn't seen before. The thing is, you can't remember when the file changed. You could just look at each commit one by one until you find the right one, but there's an easier way thanks to GitHub's History feature.
First, access one of your repository's files on GitHub, then locate the “History” button:
<%= screenshot "s3-8", "GitHub's History button." %>
You now have a neat list of all the commits that affected this particular file:
<%= screenshot "s3-9", "Displaying a file's history." %>
To wrap things up, let's take a look at Blame:
<%= screenshot "s3-10", "GitHub's Blame button." %>
This neat view shows us line by line who modified a file, and in which commit (in other words, who's to blame when things aren't working anymore):
<%= screenshot "s3-11", "GitHub's Blame view." %>
Now Git is a fairly complex tool – and so is GitHub –, so we can't hope to cover everything in a single chapter. In fact, we've barely scratched the surface of what is possible with these tools. But hopefully, even that tiny bit will prove helpful as you follow along the rest of the book.
Some people like to work quietly on a project until it's perfect, while others can't wait to show the world as soon as possible.
If you're the first kind of person and would rather develop locally for now, feel free to skip this chapter. On the other hand, if you'd rather take the time to learn how to deploy your Meteor app online, we've got you covered.
We will be learning how to deploy a Meteor app in few different ways. Feel free to use each of them at any stage of your development process, whether you're working on Microscope or any other Meteor app. Let's get started!
<% note do %>
This is a sidebar chapter. Sidebars take a deeper look at more general Meteor topics independently of the rest of the book.
So if you'd rather go on with building Microscope, you can safely skip it for now and come back to it later.
<% end %>
A fast and easy (and free!) way to deploy your Meteor app is to deploy to Heroku using the Horse buildpack.
See the readme for a step-by-step explanation.
Galaxy is the Meteor Development Group's official hosting platform, and it's built in right into the Meteor command line tool via the meteor deploy
command.
Galaxy doesn't offer a free plan, but it's a great option once you're ready to push your app live.
Note that the Meteor Development Group used to provide a free hosting service (usually referred to as just “Meteor hosting”) but as of March 2016, that free tier sadly doesn't exist anymore.
Finally, if you'd rather deploy on your own servers, MupX is a handy Docker deploy script that will set up and deploy your app on any Digital Ocean, AWS, etc. box.
These three ways of deploying Meteor apps should be enough for most use cases. Of course, we know some of you would prefer to be in complete control and set up their Meteor server from scratch. But that's a topic for another day… or maybe another book!
To ease into Meteor development, we'll adopt an outside-in approach. In other words we'll build a "dumb" HTML/JavaScript outer shell first, and then hook it up to our app's inner workings later on.
This means that in this chapter we'll only concern ourselves with what's happening inside the /client
directory.
If you haven't done so already, create a new file named main.html
inside our /client
directory, and fill it with the following code:
<%= caption "client/main.html" %>
This will be our main app template. As you can see it's all HTML except for a single {{> postsList}}
template inclusion tag, which is an insertion point for the upcoming postsList
template. For now, let's create a couple more templates.
At its core, a social news site is composed of posts organized in lists, and that's exactly how we'll organize our templates.
Let's create a /templates
directory inside /client
. This will be where we put all our templates, and to keep things tidy we'll also create /posts
inside /templates
just for our post-related templates.
<% note do %>
Meteor is great at finding files. No matter where you put your code in the /client
directory, Meteor will find it and compile it properly. This means you never need to manually write include paths for JavaScript or CSS files.
It also means you could very well put all your files in the same directory, or even all your code in the same file. But since Meteor will compile everything to a single minified file anyway, we'd rather keep things well-organized and use a cleaner file structure.
<% end %>
We're finally ready to create our second template. Inside client/templates/posts
, create posts_list.html
:
<%= caption "client/templates/posts/posts_list.html" %>
And post_item.html
:
<%= caption "client/templates/posts/post_item.html" %>
Note the name="postsList"
attribute of the template element. This is the name that will be used by Meteor to keep track of what template goes where (note that the name of the actual file is not relevant).
It's time to introduce Meteor's templating system, Spacebars. Spacebars is simply HTML, with the addition of three things: inclusions (also sometimes known as “partials”), expressions and block helpers.
Inclusions use the {{> templateName}}
syntax, and simply tell Meteor to replace the inclusion with the template of the same name (in our case postItem
).
Expressions such as {{title}}
either call a property of the current object, or the return value of a template helper as defined in the current template's manager (more on this later).
Finally, block helpers are special tags that control the flow of the template, such as {{#each}}…{{/each}}
or {{#if}}…{{/if}}
.
<% note do %>
You can refer to the Spacebars documentation if you'd like to learn more about Spacebars.
<% end %>
Armed with this knowledge, we can start to understand what's going on here.
First, in the postsList
template, we're iterating over a posts
object with the {{#each}}…{{/each}}
block helper. Then, for each iteration we're including the postItem
template.
Where is this posts
object coming from? Good question. It's actually a template helper, and you can think of it as a placeholder for a dynamic value.
The postItem
template itself is fairly straightforward. It only uses three expressions: {{url}}
and {{title}}
both return the document's properties, and {{domain}}
calls a template helper.
Up to now we've been dealing with Spacebars, which is little more than HTML with a few tags sprinkled in. Unlike other languages like PHP (or even regular HTML pages, which can include JavaScript), Meteor keeps templates and their logic separated, and these templates don't do much by themselves.
In order to come to life, a template needs helpers. You can think of these helpers as the cooks that take raw ingredients (your data) and prepare them, before handing out the finished dish (the templates) to the waiter, who then presents it to you.
In other words, while the template's role is limited to displaying or looping over variables, the helpers are the one who actually do the heavy lifting by assigning a value to each variable.
<% note do %>
It might be tempting to think of the file containing all of a template's helpers as a controller of sorts. But that can be ambiguous, as controllers (at least in the MVC sense) usually have a slightly different role.
So we decided to stay away from that terminology, and simply refer to “the template's helpers“ or “the template's logic” when talking about a template's companion JavaScript code.
<% end %>
To keep things simple, we'll adopt the convention of naming the file containing the helpers after the template, but with a .js extension. So let's create posts_list.js
inside client/templates/posts
right away and start building our first helper:
<%= caption "client/templates/posts/posts_list.js" %>
If you've done it right, you should now be seeing something similar to this in your browser:
<%= screenshot "3-1", "Our first templates with static data" %>
We're doing two things here. First we're setting up some dummy prototype data in the postsData
array. That data would normally come from the database, but since we haven't seen how to do that yet (wait for the next chapter!) we're “cheating” by using static data.
Second, we're using Meteor's Template.postsList.helpers()
function to create a template helper called posts
that returns the postsData
array we just defined above.
If you remember, we are using that posts
helper in our postsList
template:
<%= caption "client/templates/posts/posts_list.html" %>
Defining the posts
helper means it is now available for our template to use, so our template will be able to iterate over our postsData
array and pass each object contained within to the postItem
template.
<%= commit "3-1", "Added basic posts list template and static data." %>
domain
HelperSimilarly, we'll now create post_item.js
to hold the postItem
template's logic:
<%= caption "client/templates/posts/post_item.js" %>
This time our domain
helper's value is not an array, but an anonymous function. This pattern is much more common (and more useful) compared to our previous simplified dummy data example.
<%= screenshot "3-2", "Displaying domains for each links." %>
The domain
helper takes a URL and returns its domain via a bit of JavaScript magic. But where does it take that url from in the first place?
To answer that question we need to go back to our posts_list.html
template. The {{#each}}
block helper not only iterates over our array, it also sets the value of this
inside the block to the iterated object.
This means that between both {{#each}}
tags, each post is assigned to this
successively, and that extends all the way inside the included template's manager (post_item.js
).
We now understand why this.url
returns the current post's URL. And moreover, if we use {{title}}
and {{url}}
inside our post_item.html
template, Meteor knows that we mean this.title
and this.url
and returns the correct values.
<%= commit "3-2", "Setup a domain
helper on the postItem
." %>
<% note do %>
Although this is not specific to Meteor, here's a quick explanation of the above bit of “JavaScript magic”. First, we're creating an empty anchor (a
) HTML element and storing it in memory.
We then set its href
attribute to be equal to the current post's URL (as we've just seen, in a helper this
is the object currently being acted upon).
Finally, we take advantage of that a
element's special hostname
property to get back the link's domain name without the rest of the URL.
<% end %>
If you've followed along correctly, you should be seeing a list of posts in your browser. That list is just static data, so it doesn't take advantage of Meteor's real-time features just yet. We'll show you how to change that in the next chapter!
<% note do %>
You might have noticed that you didn't even need to manually reload your browser window whenever you changed a file.
This is because Meteor tracks all the files within your project directory, and automatically refreshes your browser for you whenever it detects a modification to one of them.
Meteor's hot code reload is pretty smart, even preserving the state of your app in-between two refreshes!
<% end %>
First impressions are important, and Meteor's install process should be relatively painless. In most cases, you'll be up and running in less than five minutes.
To begin with, if you're on Mac OS or Linux you can install Meteor by opening a terminal window and typing:
If you're running Windows, refer to the install instructions on the Meteor site.
This will install the meteor
executable onto your system and have you ready to use Meteor.
<% note do %>
If you can't (or don't want to) install Meteor locally, we recommend checking out Nitrous.io.
Nitrous.io is a service that lets you run apps and edit their code right in your browser, and we've written a short guide to help you get set up.
You can simply follow that guide up to (and including) the "Installing Meteor" section, and then follow along with the book again starting from the "Creating a Simple App" section of this chapter.
<% end %>
Now that we have installed Meteor, let's create an app. To do this, we use Meteor's command line tool meteor
:
This command will download Meteor, and set up a basic, ready to use Meteor project for you. When it's done, you should see a directory, microscope/
, containing the following directories and files:
The app that Meteor has created for you is a simple boilerplate application demonstrating a few simple patterns.
Even though our app doesn't do much, we can still run it. To run the app, go back to your terminal and type:
Now point your browser to http://localhost:3000/
(or the equivalent http://0.0.0.0:3000/
) and you should see something like this:
<%= screenshot "2-1", "Meteor's Hello World." %>
<%= commit "2-1", "Created basic microscope project." %>
Congratulations! You've got your first Meteor app running. By the way, to stop the app all you need to do is bring up the terminal tab where the app is running, and press ctrl+c
.
Also note that if you're using Git, this is a good time to initialize your repo with git init
.
<% note do %>
There was a time where Meteor relied on an external package manager called Meteorite. Since Meteor version 0.9.0, Meteorite is not needed anymore since its features have been assimilated into Meteor itself.
So if you encounter any references to Meteorite's mrt
command line utility while browsing Meteor-related material, you can safely replace them by the usual meteor
.
<% end %>
We will now use Meteor's package system to add the Bootstrap framework to our project.
This is no different from adding Bootstrap the usual way by manually including its CSS and JavaScript files, except that we rely on the package maintainer to keep everything up to date for us.
The bootstrap
package is maintained by the twbs
user, which gives us the full name of the package, twbs:bootstrap
.
Note that we're adding Bootstrap 3. Some of the screenshots in this book were taken with an older version of Microscope running Bootstrap 2, which means they might look slightly different.
We'll also add the Session package, which will come in handy later:
Although Session is a first-party Meteor package, it's not enabled by default in new Meteor apps so we need to add it manually.
This is a good time to check which packages we're running. It turns out that in addition to the one we just added, Meteor also comes with a few packages enabled out of the box. You can see the list by opening the packages
file inside the hidden .meteor
directory:
This might seem a bit overwhelming, but you don't need to worry about every single package right now. Just verify that our twbs:bootstrap
package was successfully added at the end of your package list.
Also, note that unlike twbs:bootstrap
, the other packages don't have an author:
part in their name, signaling the fact that these are official, core Meteor packages.
<%= commit "2-2", "Added bootstrap package." %>
As soon as you've added the Bootstrap package you should notice a change in our bare-bones app:
<%= screenshot "2-1b", "With Bootstrap." %>
Unlike the “traditional” way of including external assets, we haven't had to link up any CSS or JavaScript files, because Meteor takes care of all that for us! That's just one of the many advantages of Meteor packages.
While we're on the subject of packages, you'll notice we also have a package.json
file in our repository:
This file is used to tell NPM (Node's package manager) what to do, just like the .meteor/packages
file tells Meteor which packages to run. One key difference between both packages system though is that unlike Meteor, NPM doesn't automatically parse an app's package.json
file. So you'll have to do it manually every time you add or remove an NPM package.
Let's do it right now with:
<% note do %>
When speaking about packages in the context of Meteor, it pays to be specific. Meteor uses five basic types of packages:
The meteor-base
package stands alone: it contains Meteor's core components, and a Meteor app can't run without it.
First-party packages come bundled with Meteor. Some, such as mongo
or session
, are included with new Meteor apps by default but can be removed if you don't need them, while others (such as check
or http
) need to be added explicitly.
Local packages are specific to your app, and live in its local /packages
directory.
Atmosphere packages are custom, third-party packages that have been published to Atmosphere, Meteor's online package repository. They all follow the author:package
naming convention.
Finally, NPM packages are Node.js packages. They can't be included in your Meteor package list, but instead are listed in your app's package.json
file.
<% end %>
Before we begin coding, we must set up our project properly. To ensure we have a clean build, open up the client
and server
directory and delete the contents of client/main.html
, client/main.js
. Then go ahead and delete server/main.js
entirely.
Next, create two new root directories inside /microscope
: /public
, and /lib
.
Don't worry if all this breaks the app for now, we'll start filling in these files in the next chapter.
We should mention that some of these directories are special. When it comes to running code, Meteor has a few rules:
Code in the /server
directory only runs on the server.
Code in the /client
directory only runs on the client.
Everything else runs on both the client and server.
Your static assets (fonts, images, etc.) go in the /public
directory.
And it's also useful to know how Meteor decides in which order to load your files:
Files in /lib
are loaded before anything else.
Any main.*
file is loaded after everything else.
Everything else loads in alphabetical order based on the file name.
Note that although Meteor has these rules, it doesn't really force you to use any predefined file structure for your app if you don't want to. So the structure we suggest is just our way of doing things, not a rule set in stone.
We encourage you to check out the official Meteor docs if you want more details on this.
<% note do %>
If you're coming to Meteor from other frameworks such as Ruby on Rails, you might be wondering if Meteor apps adopt the MVC (Model View Controller) pattern.
The short answer is no. Unlike Rails, Meteor doesn't impose any predefined structure to your app. So in this book we'll simply lay out code in the way that makes the most sense to us, without worrying too much about acronyms.
<% end %>
OK, we lied. We don't actually need the public/
directory for the simple reason that Microscope doesn't use any static assets! But, since most other Meteor apps are going to include at least a couple images, we thought it was important to cover it too.
By the way, you might also notice a hidden .meteor
directory. This is where Meteor stores its own code, and modifying things in there is usually a very bad idea. In fact, you don't really ever need to look in this directory at all. The only exceptions to this are the .meteor/packages
and .meteor/release
files, which are respectively used to list your smart packages and the version of Meteor to use. When you add packages and change Meteor releases, it can be helpful to check the changes to these files.
<% note do %>
The only thing we'll say about the age-old underscore (my_variable
) vs camelCase (myVariable
) debate is that it doesn't really matter which one you pick as long as you stick to it.
In this book, we're using camelCase because it's the usual JavaScript way of doing things (after all, it's JavaScript, not java_script!).
The only exceptions to this rule are file names, which will use underscores (my_file.js
), and CSS classes, which use hyphens (.my-class
). The reason for this is that in the filesystem, underscores are most common, while the CSS syntax itself already uses hyphens (font-family
, text-align
, etc.).
<% end %>
This book is not about CSS. So to avoid slowing you down with styling details, we've decided to make the whole stylesheet available from the start, so you don't need to worry about it ever again.
CSS automatically gets loaded and minified by Meteor, so unlike other static assets it goes into /client
, not /public
. Go ahead and create a client/stylesheets/
directory now, and put this style.css
file inside it:
<%= caption "client/main.css" %>
<%= commit "2-3","Re-arranged file structure." %>
<% note do %>
In this book we'll be writing in pure JavaScript. But if you prefer CoffeeScript, Meteor has you covered. Simply add the CoffeeScript package and you'll be good to go:
meteor add coffeescript
<% end %>
Page preview for evaluation of importing data to GitBook
Do a little mental experiment for me. Imagine you're opening the same folder in two different windows on your computer.
Now click inside one of the two windows and delete a file. Did the file disappear from the other window as well?
You don't need to actually do these steps to know that it did. When we modify something on our local filesystems, the change is applied everywhere without the need for refreshes or callbacks. It just happens.
However, let's think about how the same scenario would play out on the web. For example, let's say you opened the same WordPress site admin in two browser windows and then created a new post in one of them. Unlike on the desktop, no matter how long you wait, the other window won't reflect the change unless you refresh it.
Over the years, we've gotten used to the idea that a website is something that you only communicate with in short, separate bursts.
But Meteor is part of a new wave of frameworks and technologies that are looking to challenge the status quo by making the web real-time and reactive.
Meteor is a platform built on top of Node.js for building real-time web apps. It's what sits between your app's database and its user interface and makes sure that both are kept in sync.
Since it's built on Node.js, Meteor uses JavaScript on both the client and on the server. What's more, Meteor is also able to share code between both environments.
The result of all this is a platform that manages to be very powerful and very simple by abstracting away many of the usual hassles and pitfalls of web app development.
So why should you spend your time learning Meteor rather than another web framework? Leaving aside all the various features of Meteor, we believe it boils down to one thing: Meteor is easy to learn.
More so than any other framework, Meteor makes it possible to get a real-time web app up and running on the web in a matter of hours. And if you've ever done front-end development before, you'll already be familiar with JavaScript and won't even need to learn a new language.
Meteor might be the ideal framework for your needs, or then again it might not. But since you can get started over the course of a few evenings or a week-end, why not try it and find out for yourself?
For the past couple years, we've been working on numerous Meteor projects, spanning the range from web to mobile apps, and from commercial to open-source projects.
We learned a ton, but it wasn't always easy to find the answers to our questions. We had to piece things together from many different sources, and in many cases even invent our own solutions. So with this book, we wanted to share all these lessons, and create a simple step-by-step guide that will walk you through building a full-fledged Meteor app from scratch.
The app we'll be building is a simplified version of a social news site like Hacker News or Reddit, which we'll call Microscope (by analogy with its big brother, Meteor open-source app Telescope). While building it, we'll address all the different elements that go into building a Meteor app, such as user accounts, Meteor collections, routing, and more.
One of our goals while writing the book was to keep things approachable and easy to understand. So, you should be able to follow along even if you have no experience with Meteor, Node.js, MVC frameworks, or even server-side coding in general.
On the other hand, we do assume familiarity with basic JavaScript syntax and concepts. But if you've ever hacked together some jQuery code or played around with the browser's developer console, you should be OK.
If you're not that comfortable with JavaScript yet, we suggest checking out our JavaScript primer for Meteor before getting started with the book.
In case you're wondering who we are and why you should trust us, here is a little more background on both of us.
Tom Coleman founded Percolate Studio, a web development shop with a focus on quality and user experience, was one of the creators of the Atmosphere package repository, and is also one of the brains behind many other Meteor open-source projects. He now works full-time for the Meteor Development Group.
Sacha Greif has worked with startups such as Hipmunk and RubyMotion as a product and web designer. He's the creator of Telescope and Sidebar (which is based on Telescope).
We wanted this book to be useful both for the novice Meteor user and the advanced programmer, so we split the chapters into two categories: regular chapters (numbered 1 through 14) and sidebars (.5 numbers).
Regular chapters will walk you through building the app, and will try to get you operational as soon as possible by explaining the most important steps without bogging you down with too much detail.
On the other hand, sidebars will go deeper into Meteor's intricacies, and will help you get a better understanding of what's really going on behind the scenes.
So if you're a beginner, feel free to skip the sidebars on your first read, and come back to them later on once you've played around with Meteor.
There's nothing worse than following along in a programming book and suddenly realizing your code has gotten out of sync with the examples and that nothing works like it should anymore.
To prevent this, we've set up a GitHub repository for Microscope, and we'll also provide direct links to git commits every few code changes. Here's an example of what that will look like:
<%= commit "11-2", "Display notifications in the header." %>
But note that just because we provide these commits doesn't mean you should just go from one git checkout
to the next. You will learn much better if you take the time to manually type out your app's code!
If you ever want to learn more about a particular aspect of Meteor, the official Meteor documentation and Meteor Guide are the best places to start.
We also recommend Stack Overflow for troubleshooting and questions, and the #meteor IRC channel if you need live help.
<% note do %>
While being familiar with Git version control is not strictly necessary to follow along with this book, we strongly recommend it.
If you want to get up to speed, we recommend Nick Farina's Git Is Simpler Than You Think.
If you're a Git novice, we also recommend the GitHub app (Mac OS), which lets you clone and manage repos without using the command line, or SourceTree (Mac OS & Windows), both of which are free.
<% end %>
If you'd like to get in touch with us, you can email us at hello@discovermeteor.com.
Additionally, if you find a typo or another mistake in the book's contents, you can let us know by submitting a bug in this GitHub repo.
If you have a problem with Microscope's code, you can submit a bug in Microscope's repository.
Finally, for every other question you can also just leave us a comment in this app's side panel.
Using this GitBook for Discover Meteor might be really great for the community
Consider porting content from Discover Meteor Book to this book for easier long term support, maintenance, etc.
See WIP concept at this GitBook link...