How to create a full stack app — “optimistically” [Part 1/2]

What if I told you there is a convenient button which can make your Meteor app faster in just a click? Who wouldn’t click it. Even if it were a little more than that. Actually it is. Anyways, you can’t resist optimising your app by unlocking some of its hidden features, right? Well, look no further, as I’ll be explaining and demonstrating this by creating a simple MeteorJS web and mobile app in a 2 part series, and making it 2–10 times faster than the usual ones by leveraging the features of fast rendering and optimistic UI. We’ll have 3 buttons, each of which show a number that increment upon clicking. I’m going to call this the Clicky app (clicks are so fascinating aren’t they).

Live demo and the source code of the final app, in case you’re curious.

Everything will be from scratch so don’t worry if you’re new to Meteor. Moreover, FR and optimistic UI are more of concepts than features, so, although really easy to be enabled in the Meteor’s stack, they can be implemented in virtually any web or mobile app. Once you get the concept, you will want to plug them in everywhere and nitro boost your apps’ speed. Alright, let’s get started, shall we?

The Setup

If you haven’t already, install the meteor CLI simply by

$ curl https://install.meteor.com/ | sh

Now, run the meteor create command followed by your project’s name, to let meteor setup a starter project for you

$ meteor create clicky

Let it grind for some time, after which meteor will create a starter app for us. You can try this starter app by running meteor in the project directory

$ cd clicky
$ meteor

Point your browser to localhost:3000 to see it work

There you have it folks! Click the button and watch the counter go up… forever. Well, that’s not exactly the Clicky app I have in mind for a few reasons. First, the counter is not persistent, meaning it will revert to zero once you hit refresh. Second, we want to have a unified counter, which will be same for anyone who visits the app, and should update instantaneously for everyone, whenever someone clicks. Finally, the UI seems to need help too, especially the crap of hyperlinks. We’ll be creating the UI in this part of the series, and tackling the first two problems in the next.

Let’s take a quick look at the various files and folders in the boilerplate app provided to us

client/ main.js main.html main.css server/ main.js package.json .meteor .gitignore

Essentially, we have four magic folders in a meteor project:

  • client/
  • server/
  • imports/
  • public/

client/

Everything in this folder will be loaded at the client-side only. That means any HTML file in the this folder will directly be displayed in the browser, and all the javascript and CSS files in this folder are automatically injected in the HTML, without the need for or tags.

server/

Everything in the this folder is loaded at the server-side only. The files in the server/ are used to define the various methods and schemas, which can be used by both the client and the server, throughout the app.

imports/

Any files in this folder are not loaded anywhere by default. All the files in this folder, as the name suggests, need to be imported by either the client or the server, or both. Typically, all of our code (visual components, routes, methods, schemas, etc.) is kept hierarchically under this folder. The files under client/ and server/ act only as entry points, as they would just import files from this folder. Also, since files under client/ cannot import files under server/ and vice-versa, this folder serves as a common ground for sharing code between the client and the server. Usually, we create a startup file, for both client and server, in imports/startup/client and imports/startup/server, so that these are the only files that are needed to be imported from client/main.js and server/main.js respectively.

public/

This folder is meant to contain all the static content to be loaded at the client. So for example, files like public/logo.png or public/some/thing.json can be accessed via /logo.png and /some/thing.json URLs on the client. Anything outside these directories will be loaded at both the client and the server. You can use Meteor.isClient and Meteor.isServer boolean values to separate the code in this case. You can read more about the directory structure and special folders here. Time to dive into the code now!

The Clean Up

First, let’s clean up the client/main.html file, as we won’t be needing anything from this code

I’ve put a <meta /> tag to make our app a bit more mobile-friendly.

Next, coming to the client/main.js, again we won’t be needing any of this code, particularly because this code uses the Blaze library. Frankly, I know nothing about Blaze, except that it’s Meteor’s own front end rendering system, and is the first preference in Meteor’s starter app (and I always have to clear it out). Personally, I’d prefer Facebook’s far more mature React library. Let’s setup react in our app

$ meteor npm install --save react react-dom react-mounter

meteor npm is meteor’s bundled version of npm, provided so you can get away without installing npm globally, in case you haven’t.

Remember what we discussed in the previous section? The files in client/ and server/ should act only as entry points, and we will just import the respective startup files in them

Once we’ve done that, we will rarely have to write any code outside of the imports/ folder. Neat, right?

Anyways, let’s create the client’s startup file first, in the imports/ folder. We generally create separate folders for client and server imports/startup/client and imports/startup/server/. Use these folders for keeping startup related stuff, like the routing configuration for the client, and the initial database fixtures for the server.

Let’s just import the routing file in the index file

Leave the server’s startup file for a later section, by keeping it empty for now

Before moving further, I’d like to add a quick step for setting up linting in our meteor development environment (how can we end the Clean Up section without linting). Let’s use the linting configuration that is published and followed by people at Airbnb

$ npm install --save-dev babel-eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-meteor eslint-plugin-react eslint-plugin-jsx-a11y eslint-import-resolver-meteor eslint @meteorjs/eslint-config-meteor

Just install the given modules, and setup the .eslintrc file

We’ll place the command to check for linting as a convenient script in our package.json

...
"scripts": { "start": "meteor run", "lint": "node_modules/eslint/bin/eslint.js ." },
...

Simply run npm run lint anytime you want to ensure you’re writing clean code.

The Routing

The routes file will be the first file where which we actually start mounting our React components. We can used the FlowRouter package for routing, which is “tailor-made” for meteor, but again, I would prefer a much more robust React Router package, as it looks more promising in case we want to extend our app by, say, deciding to use redux for state management, or port our app to mobile platforms (which we will, stay tuned)

$ npm install --save react-router-dom

Yes, the react-router package is now called react-router-dom as the former does not export DOM-aware components anymore.

In routes.js we’ll be creating a single route for /, and mount the visuals using react-mounter

Let’s see what we’re trying to do.

Basically, it renders the Basic component, that will be the layout component, at the default route. We’ll create this Basic layout so that it renders the page’s main content, ie. App view, which in turn, consists of various reusable components. But first, let’s see what these different categories of components are, and where should we keep them in a meteor app.

If you’ve been using React lately, you probably know that we separate our UI components into two categories, dumb and smart. Dumb components are pure, stateless, and reusable components, which may be used multiple times on a single page, while smart components are bigger, connected (with a data source), and stateful components, which take up almost all the screen-space on a particular route. We dedicate a separate folder, called imports/ui/ for the UI related stuff. We’ll be creating three subfolders in this

  • components/ for dumb and reusable components
  • pages/ for smart components
  • layouts/ for rendering layout related UI elements, like the navigation bar, around the page’s content

Let’s create the layout and the page’s content in the next section.

The Visuals

We’ll be using the materialize package to give our app a dash of Material design system. Materialize has a convenient meteor package which takes care of all the setup required

$ meteor add materialize:materialize

Now, we can simply use the various classes provided by materialize, and make sure our app doesn’t look like 80s.

Coming back to our layout file, which will be pretty straight forward as we won’t be requiring any navigation bars or sidebars for this app. It should simply render our App page at the parent route, passed down as the match.path prop due to react-router

And in a separate inline styles file, set the layout’s height, so that it covers the screen’s entire height (100% viewport-height)

Finally, export the Basic layout component through an index.js file (so that it can be conveniently imported as imports/ui/layouts/Basic)

Now, we’ll create the App page, which will render our main content (finally, let’s talk business). On the app’s page, let’s have three different teams, red, green, and blue, represented by three different buttons. These buttons will display the number of times they’ve been clicked, and therefore it should be incremented on each click

Here, the state of our App component tracks the number of clicks for each team (for now, until a later section, when we’ll create the meteor’s back end to keep track of this). For each team, I render a custom <ClickyButton /> component. This component is passed the button’s team (or colour) name, the number of clicks, and the event handler to be called on the click event. Since this will be a stateless, reusable component, we’ll be placing this in the imports/ui/components/ folder

As a finishing touch to your designing, make your app a bit more decorated by slightly changing the app’s background colour. Since we want this to be applied to the whole page, we’ll be doing this in our app’s CSS file

Take a moment, and have a look at your beautiful responsive app. You know the drill

$ npm start

And go to localhost:3000

Desktop
Mobile

That’s right, start clicking, and see which colour your mouse pointer loves the most! Can you wait to show this awesome, feature-heavy app to your friend? Wait until we connect this with the back end, so we can go multiplayer, and see clicks in real time!

Jump over to the part 2 of the series. See you there!


Originally published at anubhavdhawan.wordpress.com on September 14, 2017.