Understanding Angular 2 Workflow
As those who have been following my Angular 2 series know, I’ve been using Angular CLI for creating and organizing projects. Although it automatically provides one with a basic project template, sometimes ‘basic’ is not enough. A project may need to be modified for any number of reasons - a common case is when one needs to manually add certain libraries, even when using npm to install them.
To modify the internals of a project, it is necessary to first understand the AngularJS 2 workflow and directory structure. When a new project is created through build tools like CLI, gulp
, npm
, etc., control files are created along with the source code. Most Angular tutorials cover these files only as a corollary to explaining the core TypeScript language. For someone who just wants to change their project’s behavior a bit, those may be needlessly complex. So, in this article, I will explain the files controlling the AngularJS 2 workflow and how the workflow can be customized with them. Let’s get started!
Before starting, though, please be aware that this article draws on the previous articles it is assumed that you are familiar with how to build projects through the CLI , through using the starter/basic template without the CLI , and at least the basics of project structure (e.g. components, index.html, etc.) .
Understanding Project Workflow
Most online tutorials on the CLI go over the command-line options and give some functional overview, but do not go into detail on what project management files are created nor what purpose those files serve. In order to understand a project that is created through the CLI, let’s start by creating a new project:
$ng new AngularJS2-Workflow
This will automatically create several directories and files. Let’s focus on the ones most relevant to workflow customization.
First, the src/
directory is created, which contains all of the project’s source code. In that directory will be main.ts
(among other files). That is entry point for the application - where the execution starts. In general, main.ts
does not need to be manually modified, as
$ng generate <some-component>
will automatically update and add the new components as needed.
The e2e
directory stores end-to-end test files. These are separate from unit tests. The AngularJS 2 CLI supports unit testing natively through Karma and end-to-end testing through Protractor, with configuration files karma.conf
and protractor.conf
, respectively. Please see here for more information on Protractor and here for more on Karma. While testing is important to a workflow, it is not the subject of this tutorial and may be revisited in a future article.
The node_modules
directory is not automatically generated at project creation, but will be automatically created through installing modules via npm install
. This directory will contain the libraries, along with their type definitions. (More on type definitions later on.) Although libraries can be installed globally, the general practice is to install libraries uniquely per-module. If migrating from earlier versions of AngularJS, it is important to note that modules are compiled via SystemJS and not Webpack. (For more on the differences, please see here.
Understanding Auto-generated Project Files
package.json
package.json
is a control file for the npm
package management system, one of the systems on which AngularJS 2 depends. It defines all of meta-information for the project and all of its dependencies. In many senses, it is the single most important file to the workflow.
The default package.json
created by the CLI looks something like this:
package.json
{
"name": "angular-js2-workflow",
"version": "0.0.0",
"license": "MIT",
"angular-cli": {},
"scripts": {
"ng": "ng",
"start": "ng serve",
"lint": "tslint \"src/**/*.ts\" --project src/tsconfig.json --type-check && tslint \"e2e/**/*.ts\" --project e2e/tsconfig.json --type-check",
"test": "ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "protractor"
},
"private": true,
"dependencies": {
"@angular/common": "^2.3.1",
"@angular/compiler": "^2.3.1",
"@angular/core": "^2.3.1",
"@angular/forms": "^2.3.1",
"@angular/http": "^2.3.1",
"@angular/platform-browser": "^2.3.1",
"@angular/platform-browser-dynamic": "^2.3.1",
"@angular/router": "^3.3.1",
"core-js": "^2.4.1",
"rxjs": "^5.0.1",
"ts-helpers": "^1.1.1",
"zone.js": "^0.7.2"
},
"devDependencies": {
"@angular/compiler-cli": "^2.3.1",
"@types/jasmine": "2.5.38",
"@types/node": "^6.0.42",
"angular-cli": "1.0.0-beta.26",
"codelyzer": "~2.0.0-beta.1",
"jasmine-core": "2.5.2",
"jasmine-spec-reporter": "2.5.0",
"karma": "1.2.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-jasmine": "^1.0.2",
"karma-remap-istanbul": "^0.2.1",
"protractor": "~4.0.13",
"ts-node": "1.2.1",
"tslint": "^4.3.0",
"typescript": "~2.0.3"
}
}
(Note: As the CLI is currently in beta, some of this may look slightly different. Please see here for the current version.)
Note the two large arrays - dependencies
and devDependencies
. What’s the difference?
Any library needed at runtime belongs in the dependencies
array. When installing a library via npm install
, the dependencies
array will be automatically edited and updated. While anyone using the project will need all the dependencies
(that’s why they’re called dependencies, after all), the end-users probably don’t need (or care about) the testing frameworks, documentation generators, code checkers - all of the build-time requirements. Those belong in the devDependencies
array, and are not installed automatically with the generated project.
For more information about the format and capabilities of the package.json file, please see here.
angular-cli.json
angular-cli.json
defines asset (resource) locations and directory structure, and looks something like this:
angular-cli.json
{
"project": {
"version": "1.0.0-beta.26",
"name": "angular-js2-workflow"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [],
"environments": {
"source": "environments/environment.ts",
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"prefixInterfaces": false,
"inline": {
"style": false,
"template": false
},
"spec": {
"class": false,
"component": true,
"directive": true,
"module": false,
"pipe": true,
"service": true
}
}
}
To share resources between packages to use assets outside of the project tree, simply modify the appropriate entries in this file.
index.html
When initially installed, this does nothing, as can be seen below:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>AngularJS 2 Workflow</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<angular-js2-workflow-root>Loading...</angular-js2-workflow-root>
</body>
</html>
However, the CLI will automatically add script lines to load libraries as part of the install process, and the main.ts
, after transpilation, will be added as main.js
.
tsconfig.json
This contains the TypeScript configuration:
{
"compilerOptions": {
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"mapRoot": "./",
"module": "es6",
"moduleResolution": "node",
"outDir": "src/dist/out-tsc",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"src/node_modules/@types"
]
}
}
As mentioned in the introduction, this tutorial will not go into TypeScript. For more information on TypeScript and the tsconfig.json file, please see here.
typings.json
The typings.json
file does not exist by default, but is created and updated as libraries are installed. JavaScript does not have (exactly) have namespaces, so Typings (the TypeScript Definition Manager) is a library to wrap modules in their own “namespace” to avoid naming conflicts whilst still providing access to the functionality.
AngularJS 2 modules provide their typing information in .d.ts
files, which are automatically added to the typings directory at the time of install. For external libraries, the typing information must be installed manually.
Customizing The Workflow
While we have used the files created by the CLI as our examples thus far, to explain customization we will use the basic template as used in previous articles.
Installing Libraries
From the basic template, package.json
looks a bit different:
package.json
{
"name": "angular-2",
"version": "1.0.0",
"scripts": {
"start": "concurrently \"npm run tsc:w\" \"npm run lite\" ",
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"typings": "typings",
"postinstall": "typings install"
},
"license": "ISC",
"dependencies": {
"angular2": "2.0.0-beta.13",
"systemjs": "0.19.25",
"es6-shim": "^0.35.0",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2",
"zone.js": "0.6.6"
},
"devDependencies": {
"concurrently": "^2.0.0",
"lite-server": "^2.1.0",
"typescript": "^1.8.9",
"typings":"^0.7.11"
}
}
Here, the dependencies are (mostly) not defined in terms of modules, but rather in terms of packages. Also, as this is a much simpler template than what the CLI provides, very few libraries are initially included. Let’s fix that in a simple case:
$npm install –save-dev semver
That updates the package.json
file by adding those libraries to the devDependencies
array.
There will also be a typings.json
file in the node_modules
directory:
typings.json
{
"ambientDependencies": {
"es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#7de6c3dd94feaeb21f20054b9f30d5dabc5efabd",
"jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#7de6c3dd94feaeb21f20054b9f30d5dabc5efabd"
}
}
Now, to install the typings information, do:
$typings install npm:semver
And then we run:
$npm install
index.html
is also different:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Angular 2 QuickStart</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<!-- Load libraries (Note: IE required polyfills, in this exact order_ -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<!-- Configure SystemJS -->
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/js/main').then(null, console.error.bind(console));
</script>
</head>
<body>
<div class="container-fluid">
<my-app>Loading...</my-app>
</div>
</body>
</html>
This shows a little better how libraries can be manually preloaded.
All that’s left is to modify app/ts/app.component.ts
with your code, and:
$npm start
should show the running server, with several files in app/js
transpiled and loaded.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment