Now 2.0 and Angular Single-Page Apps
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!