Starting an Angular 2 RC.6 project

Yakov Fain shows how to get started with the latest from the Angular 2 team.

By Yakov Fain
September 15, 2016
Plant containers Plant containers (source: Antranias via Pixabay)

Angular 2 is about to be officially released (most likely it’ll happen at the AngularConnect conference on September 25, 2016). The current version of of Angular is Release Candidate 6 and I’ll describe how to create your first project with this release.

During the last couple of months Angular 2 was substantially redesigned/improved in several areas.

Learn faster. Dig deeper. See farther.

Join the O'Reilly online learning platform. Get a free trial today and find answers on the fly, or master something new and useful.

Learn more

Now the app consists of modules, where one is a bootable module that identifies the root component of your app and declares other modules, components, directive, pipes, providers, and routes that are used in this module. Now there is no need to repeat these artifacts in every component. A module is a class decorated with the @NgModule() annotation, and you declare all these artifacts there. For example, the bootable module of your app may look like this:

import { NgModule } from '@angular/core';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
// other import statements are omitted for brevity

@NgModule({
  imports: [
      BrowserModule,
      FormsModule,
      ReactiveFormsModule,
      RouterModule.forRoot([
        {path: '',                    component: HomeComponent},
        {path: 'products/:productId', component: ProductDetailComponent}
      ])
  ],
  declarations: [
      ApplicationComponent,
      CarouselComponent,
      FooterComponent,
      HomeComponent,
      NavbarComponent,
      ProductDetailComponent,
      ProductItemComponent,
      SearchComponent,
      StarsComponent
  ],
  providers: [
      { provide: LocationStrategy, useClass: HashLocationStrategy },
      ProductService
  ],
  bootstrap: [ ApplicationComponent ]
})
export class AppModule {}

Only the bootable module needs BrowserModule. If your app uses several modules (e.g. ShipmentModule, BillingModule, FormsModule, HttpModule), those modules are called feature modules and are based on the CommonModule instead of the BrowserModule. Each of the feature modules can be loaded either eagerly when the app starts, or lazily, e.g. when the user clicks on the “shipping” link.

The code of your app can be compiled either dynamically or statically. If it’s dynamically compiled in the browser, this is called just-in-time compilation (JIT). If the code is precompiled, it’s called ahead-of-time (AoT) compilation. I’m talking about the Angular compiler-cli (ngc), and not just transpiling from TypeScript to JavaScript here. A half of the size of a small app is the Angular compiler itself, and just by using the AoT your app becomes slimmer because the compiler won’t be downloaded to the browser.

In this post we’ll use the JIT compilation, and I’ll show you how to start a new Angular 2 RC.6 project (managed by npm) from scratch without using the scaffolding tool Angular-CLI.

To start a new project, create a new directory (e.g. angular-seed) and open it in the command window. Then run the command npm init -y, which will create the initial version of the package.json configuration file. Normally npm init asks several questions while creating the file, but the -y flag makes it accept the default values for all options. The following example shows the log of this command running in the empty angular-seed directory.

$ npm init -y
 
Wrote to /Users/username/angular-seed/package.json:
 
{
  "name": "angular-seed",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Most of the generated configuration is needed either for publishing the project into the npm registry or while installing the package as a dependency for another project.

Because we’re not going to publish our app into the npm registry, you should remove all of the properties except name, description, and scripts. The configuration of any npm-based project is located in the file package.json, which can look like this:

{
  "name": "angular-seed",
  "description": "A simple npm-managed project",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

The script’s configuration allows you to specify commands that you can run in the command window. By default, npm init creates the test command, which can be run like this: npm test. Let’s replace it with the start command that we’ll be using for launching a web server that will feed our app to the browser. Several simple web servers are available and we’ll be using the one called live-server that we’ll add to the generated package.json a bit later. Here’s the configuration of the scripts property:

{
  ...
  "scripts": {
    "start": "live-server"
  }
}

The start command is one of the pre-defined commands in npm scripts, and you can run it from the command window by entering npm start. Actually, you can define and run any other command that would serve as a shortcut for any command you could run manually, but in this case you’d need to run such command as follows: npm run mycommand.

Now we want npm to download Angular to this project as a dependency. We want Angular with its dependencies to be downloaded to our project directory node-modules. We also want local versions of SystemJS, live-server, the TypeScript compiler, and any other third-party libraries that our app needs.

So let’s add the dependencies and devDependencies sections to the package.json file so it’ll include everything that a typical Angular 2 app needs:

 {
  "name": "angular-seed",
  "description": "My simple project",
  "private": true,
  "scripts": {
    "start": "live-server"
  },
  "dependencies": {
    "@angular/common": "2.0.0-rc.6",
    "@angular/compiler": "2.0.0-rc.6",
    "@angular/core": "2.0.0-rc.6",
    "@angular/forms": "2.0.0-rc.6",
    "@angular/http": "2.0.0-rc.6",
    "@angular/platform-browser": "2.0.0-rc.6",
    "@angular/platform-browser-dynamic": "2.0.0-rc.6",
    "@angular/router": "^3.0.0-rc.2",

    "core-js": "^2.4.0",
    "rxjs": "5.0.0-beta.11",
    "systemjs": "0.19.37",
    "zone.js": "0.6.17"
  },
  "devDependencies": {
    "live-server": "0.8.2",
    "typescript": "^2.0.0"
  }
}

Now run the command npm install on the command line from the directory where your package.json is located, and npm will download the preceding packages and their dependencies into the node_modules folder. After this process is complete, you’ll see a couple of hundred (sigh) directories and in the node_modules dir, including @angular, systemjs, live-server, and typescript.

angular-seed
├── index.html
├── package.json
└── app
└── app.ts
├──node_modules
├── @angular
├── systemjs
├── typescript
├── live-server
└── …

In the angular-seed folder, let’s create a slightly modified version of index.html with the following content:

<!DOCTYPE html>
<html>
<head>
  <title>Angular seed project</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="node_modules/typescript/lib/typescript.js"></script>
  <script src="node_modules/core-js/client/shim.min.js"></script>
  <script src="node_modules/zone.js/dist/zone.js"></script>
  <script src="node_modules/systemjs/dist/system.src.js"></script>
  <script src="systemjs.config.js"></script>
  <script>
    System.import('app').catch(function(err){ console.error(err); });
  </script>
</head>

<body>
<app>Loading...</app>
</body>
</html>

The script tags load the required dependencies of Angular from the local directory node_modules. Angular modules will be loaded according to the SystemJS configuration file systemjs.config.jsm which can look as follows:

System.config({
    transpiler: 'typescript',
    typescriptOptions: {emitDecoratorMetadata: true},
    map: {
      '@angular': 'node_modules/@angular',
      'rxjs'    : 'node_modules/rxjs'
    },
    paths: {
      'node_modules/@angular/*': 'node_modules/@angular/*/bundles'
    },
    meta: {
      '@angular/*': {'format': 'cjs'}
    },
    packages: {
      'app'                              : {main: 'main', defaultExtension: 'ts'},
      'rxjs'                             : {main: 'Rx'},
      '@angular/core'                    : {main: 'core.umd.min.js'},
      '@angular/common'                  : {main: 'common.umd.min.js'},
      '@angular/compiler'                : {main: 'compiler.umd.min.js'},
      '@angular/platform-browser'        : {main: 'platform-browser.umd.min.js'},
      '@angular/platform-browser-dynamic': {main: 'platform-browser-dynamic.umd.min.js'}
    }
});

The app code will consist of three files:

  • app.component.ts – the one and only component of our app
  • app.module.ts – The declaration of the module that will include our component
  • main.ts – the bootstrap of the module

Let’s create the file app.component.ts with the following content:

----
import {Component} from '@angular/core';
 
@Component({
    selector: 'app',
    template: `<h1>Hello !</h1>`
})
export class AppComponent {
    name: string;
 
    constructor() {
        this.name = 'Angular 2';
    }
}

Now you need to create a module that will contain our AppComponent. We’ll place his code inside the app.module.ts file:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
 
@NgModule({
    imports:      [ BrowserModule ],
    declarations: [ AppComponent ],
    bootstrap:    [ AppComponent ]
})
export class AppModule { }

This file just contains the definition of the Angular module. The class is annotated with @NgModule that includes the BrowserModule that every browser must import. Since our module contains only one class, we need to list it in the declarations property, and list it as the bootstrap class.

In the section packages of the SystemJS config file we mapped the name app to main.ts that will look like this:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule }  from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

The last line of the above script actually compiles and loads the module.

Start the application by executing the npm start command from the angular-seed directory, and it’ll open your browser and show the message “Loading…” for a second, followed by “Hello Angular 2!”.

You can find the source code of our angular-seed project (the RC.6 version) here.


This post was originally published on Yakov Fain’s blog. It’s republished with permission.

Post topics: Web Programming
Share: