Setting up a project in Angular2 (rc6 and beyond)

Soon^1), there will be the angular-cli command line tool, to automate the process of setting up a new project in Angular2. However, its still useful to understand what angular-cli actually does. This is a quick walk-through, from start to final project set-up.

Create a directory (here "ng2-app"), cd into it, and create a new empty npm package, accepting all defaults.

mkdir ng2-app && cd $_ && npm init -y

Next, install the most recent Angular2 release into the directory, using npm. For that, simply add all required packages to the packages.json configuration file you just created. Your packages.json should look like this

{
  "name": "ng2-app",
  "description": "Manual set-up Angular2 project.",
  "private": true,
  "scripts": {
    "start": "live-server --mount=/:./src/ --entry-file=./src/index.html"
  },
  "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": "^1.0.0",
    "typescript": "^2.0.0"
  }
}

To install all required packages, run npm install in your project directory.

npm install

While the dependencies are installing, have a look at the above code. Especially at the line "scripts": { "start": "..." }. Here, we define a command to run a development server that launches our Angular2 app in a browser. With --mount=/:./src/ the root path http://127.0.0.1/ is mapped to the ./src/ directory. And, very useful for one-page-apps, we will always serve the index.html file for any path in the browser adress bar with --entry-file=./src/index.html, because we want Angular2 to handle the routing. We will use this as npm start at the end of this text.

After all dependencies have installed successfully, we now need to create some files:

We will losely follow convention used by angular-cli and use a subdirectory app/ for files that belong to the app itself. The file tree should be as follows

[ng2-app]
  |
  |-[src]
  |   |
  |   |-[app]
  |   |   |
  |   |   |- app.component.ts
  |   |   |- app.module.ts
  |   |   |- main.ts
  |   |
  |   |- index.html
  |   |- systemjs.config.js
  |
  |-[node_modules]
  |   |
  |   |-[@angular]
  |   |-[typescript]
  |   |- ...and a bazilion other directories...
  |
  |- package.json

Let's begin with the boilerplate for index.html. This loads typescript.js, the typescript JIT^2) compiler, shim.js to fix up older browsers, zone.js to get property bindings, and systemjs and its config file, to get the who thing started up.

# -- ./src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <base href="/">
    <title>Angular2 project</title>
    <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>

Next up is systemjs.config.js that will tell the app loader what to do with all those files and functions, and where to find files that are imported by other files. Take a minute to look at it and understand what it does.

# -- ./src/systemjs.config.js
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/common': { main: 'common.umd.min.js' },
    '@angular/compiler': { main: 'compiler.umd.min.js' },
    '@angular/core': { main: 'core.umd.min.js' },
    '@angular/forms': { main: 'forms.umd.min.js' },
    '@angular/platform-browser': { main: 'platform-browser.umd.min.js' },
    '@angular/platform-browser-dynamic': {
      main: 'platform-browser-dynamic.umd.min.js'
    }
  }
});

Noticed the first line under packages: {} where it defines app? That refers to the next file: main.ts. That's our TypeScript app's entry point, where the bootstrapping happens. Create the file in the app/ directory with the following boilerplate

// -- ./src/app/main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule }  from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

The module platformBrowserDynamic does the JiT compiling of our app, so when your app is ready for deployment, you can just replace it by the AoT compiler call. The AppModule it works on is your app's Root Module.

Every Angular2 app has one root module (though if you don't define one yourself, Angular2 will go ahead and create one for you automatically, so that's nice). But in this case, lets define a root module explicitly, and then a main component.

// -- ./src/app/app.module.ts
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 { }

So far, a script in our index.html has invoked the SystemJS loader, that called our main.ts script, that invoked Angular2's bootstrap machine, feeding it our app's root module. Now, as a last step, our root module imports our main component's class AppComponent and hands it to the bootstrap field of NgModule.

Below is some boilerplate for app.component.ts that you should replace with your actual app code

// -- ./src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app',
  template: `<h1>The app works {{ status }}!</h1>`
})
export class AppComponent {
  status: string;

  constructor() {
    this.status = 'great';
  }
}

That was all. Remember "scripts": { "start": "..." } from the package.json file? Now is the time. In the project's root directory, run

npm start

If all goes well, this opens a new tab in your default browser with the output of the app. From here, you can start writing your Angular2 app.

Sources, tutorials, docs


1) Probably shortly after the Angular2 Summit in Boston from 26-28 September 2016.

2) Just-in-time compilation compiles the app in the browser. Good for development, but slow for production. With rc6, Angular got an easily usable AoT (ahead-of-time) compiler as well, that should be used for production in most cases.