Cloud Computing — by Haseeb Jamil on Unsplash

Now 2.0 and Angular Single-Page Apps

Martin Džejky Jakubik
6 min readNov 21, 2018

Now 2.0 came out!

And they changed a lot of things about how you deploy your app. Previously you could just use Docker to deploy anything you want and now there are these Builders and…

Wait… what is he talking about? Okay, let’s take a step back.

Now takes the concept of serverless to a whole new level. I mean, it really does! Imagine that you are in your application repository and you just call this:

now

Boom! After a few moments, your application is deployed to the cloud. So easy, right?

Now makes serverless application deployment easy.
Don’t spend time configuring the cloud. Just push your code.

In version 1, there were 3 ways to deploy your app:

  • You could just host static files
  • You could run a Node script
  • You could deploy a Docker image

In version 2, things are quite different. I’ll spare you the technical details (mostly because I don’t understand them) and focus on the most important thing for us, Angular developers:

How to use Now 2.0 to host my single-page Angular app???

Prerequisites

This is pretty straight-forward, right? Just install Now CLI and Angular CLI. For example, on Mac I did this:

yarn global add @angular/cli
brew cask install now

Now you should have both ng and now in your PATH.

Example Angular App

Let’s start by creating a simple Angular application. We don’t need any tests or anything special, just an app with routing enabled. We need to use routing to also test that Now always serves the index.html file. First thing first, we’ll use the Angular CLI to generate a brand new app for us.

ng new now-angular-app --skip-tests
cd now-angular-app

Then run the following command to serve your app on localhost:4200 :

yarn start

Routing

That is the most basic Angular app you can have. However, we want to add routing. For that, we will need 2 new components and @angular/router dependency installed.

yarn add @angular/router
ng g c components/home-view
ng g c components/about-view

As the next step, we need to import the RouterModule in our application. Add this to the main module in app.module.ts to the imports section:

imports: [
// ... existing imports
RouterModule.forRoot([
{
path: '',
pathMatch: 'full',
component: HomeViewComponent
}, {
path: 'about',
component: AboutViewComponent
}
])
]

Finally, replace the HTML template of the app.component.html with the router outlet:

<router-outlet></router-outlet>

Phew, that was a lot of work… You can now visit localhost:4200 to see the home page and localhost:4200/about to see the about page.

Deploying

At last! This is what we have been waiting for!

now

Well, not so fast… The first thing you get is this warning — WARN! Your project is missing a now.json file with a `version` property. That’s an easy fix, just add a now.json file into the project with this content:

{
"version": 2
}

If you re-deploy now, there’s no warning in the console anymore. You might get an URL like this — now-angular-app-rhdik8cm3.now.sh. However, when you visit it, you will only see the static files hosted on a CDN. That is not what we wanted to achieve, is it?

Now Builders

Now has this concept of builders. They are modules (or build steps) that take your source, build it in some way, and then host the result. The result can either be more static files or a lambda. In our case, we want to build the application and host the dist directory. There’s this neat official builder exactly for this purpose called Static Build builder. It will install the dependencies, call a now-build script from package.json file, and host the resulting dist directory.

Let’s use it! Add this script to your package.json file:

"scripts": {
// ... existing scripts
"now-build": "ng build --prod"
}

Then we need to tell Now to use the Static Build builder. That is configured using the now.json file. Update the file so it looks like this:

{
"version": 2,
"builds": [
{ "src": "package.json", "use": "@now/static-build" }
]
}

Notice that we have to provide the name of the builder (in this case @now/static-build) and a path to our package.json file.

This is it! The final moments of our journey! Prepare yourself! Run this command and sit tight:

now

Here Comes the Failure

As I was writing this article, I was expecting that this would give me a working deployment with my Angular application working as expected. Instead, I was met with a failure and a log.

Ups… And I wanted to write an interesting article. Well, I decided to publish it anyway. At least you know how it is supposed to work. When I have more information about the issue, I’ll update this post or add a link to a new one. Wish me luck!

You can help me, discuss, or just vote for this issue on Github:

Anyway, after a few days, the original issue contains a solution to our problem. This is the new now.json configuration file:

{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@now/static-build",
"config": {
"useBuildUtils": "@now/build-utils@canary"
}
}
]
}

The problem was with Yarn cache, it took too much space during the deployment. This configuration makes it so that Yarn stores its cache in the memory instead of the disk. See the discussion in the linked Github issue.

This produces the desired outcome — the deployment what I got is now-angular-app-j3r1fklxe.now.sh and it looks like our desired Angular application:

However, there’s one last problem. The about page does not currently work because Now does not know that we have a single-page application.

Routing

In order to let Now know that we have a single-page application, we need to set up Now routes to support it. Basically we need to tell Now to always serve the index.html file except when the URL contains a link to an asset.

Add this to the now.json file:

"routes": [
{ "src": "(.*\\..*))", "dest": "$1" },
{ "src": ".*", "dest": "/index.html" }
]

This configuration ensures that the requests for files are handled as before and all other requests serve the index.html file. The first regular expression matches all URLs which contain a dot and serves the original file. The second regular expression matches everything else and serves the index.html file. You might get a deployment like this: now-angular-app-jzwfx1ixe.now.sh.

As you can see, the about page now works correctly! Yay!

Thank you for reading this article! ❤️ Originally this article ended with the Now error about no space left on device. I created a Github issue here:

Since then, folks have suggested a solution so I updated this article and finished it. Just like I originally intended. Here’s a link to the final Now deployment: now-angular-app-jzwfx1ixe.now.sh. Also check out the app repository:

If you like this article, make sure to smash that 👏 button and share it with you friends. More are coming so you might want to follow me, too. Just saying. Have a nice day!

--

--

Martin Džejky Jakubik

Frontend developer @ Exponea. Writing about things I learn along the way.