49

Building a Search-Engine Optimized PWA with Angular - Part 1

 5 years ago
source link: https://www.tuicool.com/articles/hit/IjQNNbR
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Building a Search-Engine Optimized PWA with Angular — Part 1

BryeEjv.png!web

No matter how awesome the app you have built is, it won’t really shine with the users unless they can easily see it in their search results. This is why Search Engine Optimization (SEO) is something that any developer needs to have on their To-Do list when they are building their apps.

Back in 2017, surveys showed that about 27% of mobile users ignored the usual app stores and searched for apps on their own through search engines like Google and Bing.

Just open your the app store on your mobile device and search for something as simple as calculator. What you will get is an endless number of apps that somewhat do the same thing — Calculate.

This is why visibility is most important for app developers. Because people searching for apps through search engines will not venture farther that the 1st or 2nd page of the search results.

To understand how search engine optimization works, let’s take a look at one of my other articles, “How To Write Better Code in React”.

If you go to Google and just type “React” in the search bar, then currently you will find this article somewhere on Page 5!

But if you search for something like “better code react”, the article bumps all the way up to Page 1!

wThat’s enough about SEO for now. Now let’s take a look at Progressive Web Apps!

Based on a concept by Google, PWAs are a little different than the traditional mobile app. It is more like a website that is modified to work on mobile devices. The keyword here is “Progressive”, meaning these are apps/websites that can be gradually adjusted to the end device’s technical settings.

In this post, we will build a brand new Progressive Web App using Angular. You will get a hands-on experience of working with things like service workers and Angular Resolvers.

Getting Started

Build an Angular Project

Let’s start by creating a brand new Angular Project in our system. If you haven’t installed the Angular CLI in your device, then type the following command in your command terminal:

$ npm install -g @angular/cli

Then, create a new Angular project directory called comicstore . I want to enable routing in my app and write the style using SASS instead of plain old CSS. So I will also have to pass in a couple of flags to the ng new command as follows:

$ ng new comicstore --routing --style scss 
// wait for installation to complete
$ cd comicstore

Run the ng serve command to start the Angular Developement Server. The Server will launch the basic application in your browser at localhost:4200 .

Vf2AF3a.png!web

But we don’t really need all this stuff that Angular has graciously provided us with. So let’s get rid of it by going to the file src/app/app.component.html and replace the existing code with:

<h1>DC Comics Rebirth</h1>

Bootstrap

I am going to use Bootstrap a lot in this app, simply because it will save me time from writing down basic HTML and CSS things.

Go to the BootstrapCDN website and copy the URL for the Complete CSS package. Then in your project directory, go to the style.scss file and paste the URL inside an import statement.

@import url(<a href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" data-href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="nofollow noopener" target="_blank">https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css</a>)

Inline the HTML Template and Style

When I first started working with Angular, I noticed that each component in Angular has 4 files:

  • The Component Class
  • The Component’s HTML Template
  • The Component’s StyleSheet
  • The Component’s Tests

I realised that things would be much easier for me if I could move the HTML Template and the StyleSheet from an external file to the Component’s Class file itself. This would reduce the number of files for each of my App’s components and I won’t have to go into various files to make any changes to code later on.

To start, delete the files app.component.html and app.component.scss from the src/app folder. Then go to app.component.ts file and rename the templateUrl property as just template . Also, change this property’s content as shown below:

template: `
  <h1>DC Comics Rebirth</h1>
  <router-outlet></router-outlet>
`,

Similarly, rename the styleUrls property as styles and change the property’s content like this:

styles: [`
  h1{
    color: #0476F2;
  }
`]

We also need to tell Angular that we will be writing our HTML Template and Style inside the component file itself. To do this we will use the ng config command as shown below:

$ ng config schematics.@schematics/angular.component.inlineStyle true
$ ng config schematics.@schematics/angular.component.inlineTemplate true

You will then be able to see that some changes have been made to the schematics object in the angular.json file.

Qb6NVzf.png!web

Building the Application Layout

Instead of wasting time building the layout of our app from scratch, we can just use the module ui command to tell Angular to create a basic application layout for us. This layout will consist a component for header, footer, and the body of the layout.

The module ui is used with the ng generate command as shown below:

$ ng generate module ui --module App

This command will create a new folder called ui inside the src/app folder. Angular will add a import statement for this folder inside the app.module.ts file.

uiiEjuN.png!web

Next, we need to generate components for Header , Footer , and the Layout of the app.

$ ng generate component ui/containers/layout 
$ ng generate component ui/containers/header 
$ ng generate component ui/containers/footer

This will generate a main component file and a test file for each of these components.

Next, open the app-routing.module.ts file and add the default route to the LayoutComponent as shown below.

const routes: Routes = [{
  path: '',
  component: LayoutComponent,
  children: [],
}];

By doing this, our app will initially render the contents of LayoutComponent . You will also notice that our app still displays the h1 element that we had written inline in the app.component.ts file. To make things simpler, let’s move it to the layout.component.ts file.

First, go to app.component.ts file, and remove the styles array. Also remove the h1 element from the template property.

Now go to the layout.component.ts file that is located inside the app/ui/containers/layout folder, and rewrite the template property as shown below:

template: `
  <app-header></app-header>
  <div class="container my-8 py-8">
    <router-outlet></router-outlet>
  </div>
  <app-footer></app-footer>
`,

If get an error on your browser, it is probably because Angular has not added the RouterModule as an import to the ui.module.ts file. If that is the case, then go ahead and take care of it right away.

@NgModule({
imports: [
CommonModule,
RouterModule
],
declarations: [
LayoutComponent,
HeaderComponent,
FooterComponent
]
})

As the name of this app suggests, this app is a dummy store for comics. And since I mostly follow DC Comics, that is what this store is going to “sell”. So I am going to Google the logo for DC Comics and save it in the src/assets folder as logo.svg .

Lets go ahead and add this logo to the header component of our app. Go the the header.component.ts file and add the following properties to the HeaderComponent class.

public logo = 'assets/logo.svg';
public title = 'DC Comics Rebirth';
public links = [{
  label: 'Comics',
  url: '/Comics',
}]

Erase the template property’s content. Instead, we will add a new nav tag as shown below:

template: `
  <nav class=navbar navbar-expand navbar-blue fixed-top>
`

You will notice that there is now a thick black line at the top of the browser. Next, let’s add the logo and title to this header. Below the nav element, write:

<a routerLink="/" class="navbar-brand">
  <img [attr.src]="logo" [attr.alt]="title" width="30" height="30>
  {{title}}
</a>

I had also create a link called Comics . So I am going to add this link to the header component as well. Below the a tag, write a new div element as shown below:

<div class="collapse navbar-collpase">     
  <div class="navbar-nav">         
    <a class="nav-item nav-link" *ngFor="let link of links"
    [routerLink]="link.urk" routerLinkActive="active"
    [routerLinkActiveOptions]="{ exact: true }">         
    {{ link.label }}         
    </a>     
  </div> 
</div>

Finally, your header component should look something like this:

yayQb2I.png!web

Let’s take care of the footer component as well. Go to the footer.component.ts file and erase everything inside the template property. Lets add a new nav element inside the template property with same classes as that of the one in header.

template: `
  <nav class="navbar navbar-expand navbar-dark bg-dark fixed-bottom">
`

You should a thick black border at the bottom the browser page. This will be our footer. You can write anything you want in here. I am going to write a simple disclaimer.

<div class="navbar-text m-auto text-white">
  The comics and characters and everything else presented here belongs to DC Comics.
</div>

Retrieving Data in Angular

Let’s start by creating a new routing file called comic .

$ ng g m comic --routing

This command will create a new folder called comic inside the app folder.

Open the app-routing.module.ts file and create two new routes inside the children array.

children: [{
  path: '',
  pathMatch: 'full',
  redirectTo: '/comics',
  }, {
  path: 'comics',
  loadChildren: './comic/comic.module#ComicModule'
}],

Here, the first route will redirect the user from any undefined routes to the comics route. The second route is the actual comics route.

Now when you refresh the browser, it will directly take you to the comics route.

Lets also create a new module for comic :

$ ng g cl comic/models/comic

You will now get a new folder called models inside the comic folder. It will contain a single file names comic.ts . Add the following properties inside this file.

export class Comic {
  public id: string;
  public name: string;
  public description: string;
  public image: string;
  public price: number;
}

Next, create a couple of containers to help us retrieve and pass data to other components.

$ ng g c comic/containers/comic-list
$ ng g c comic/containers/comic-detail

These commands will create two new container components — comic-list and comic-detail .

Open comic-routing.module.ts file and add a route to ComicListComponent . The path for this route will just be an empty string. Similarly, add a route to ComicDetailComponent with the path set to  :id .

const routes: Routes = [{     
  path: '',     
  component: ComicListComponent, 
}, {     
  path: ':id',     
  component: ComicDetailComponent, 
}]

Open the comic-list.component.ts file and set the template property to comics .

template: `
  {{comics | json}}
`,

Do the same thing for the template property of comic-detail.component.ts file.

Inside the component class of comic-list.component.ts and comic-detail.component.ts , add a new comics property that is of Comic[] type and initialize it as an empty array.

public comic: Comic[] = new Comic();

Then open the comic-detail.component.ts file and inject ActivatedRoute inside the class’s constructor method. This will allow us to fetch the id property from the URL. Also assign this.comic.id to this.route.snapshot.paraMap.get('id') inside ngOnInit .

constructor(private route: ActivatedRoute) {}
ngOnInit() {
  this.comic.id = this.route.snapshot.paramMap.get('id');
}

Make sure that ActivatedRoute is imported inside this file.

import { ActivatedRoute } from ‘@angular/router’;

This concludes the Part 1 of this series. Part 2 will be up very soon.

Shared with :heart: inBit’s blog

Bit seamlessly turns any component or module into an API you can share and use across projects. Give it a try alone or with your team, it’s open source :)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK