docs(QuickStart): incorporate misko's suggestions/corrections

closes #502
This commit is contained in:
Ward Bell 2015-12-14 15:44:50 -08:00
parent 8e8963270b
commit bc74ee4ac3
5 changed files with 134 additions and 48 deletions

View File

@ -9,4 +9,6 @@ import {Component} from 'angular2/core';
template: '<h1>My First Angular 2 App</h1>' template: '<h1>My First Angular 2 App</h1>'
}) })
// #enddocregion metadata // #enddocregion metadata
// #docregion export
export class AppComponent { } export class AppComponent { }
// #enddocregion export

View File

@ -9,7 +9,7 @@
}, },
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"angular2": "2.0.0-alpha.52", "angular2": "2.0.0-alpha.53",
"systemjs": "0.19.6", "systemjs": "0.19.6",
"es6-promise": "^3.0.2", "es6-promise": "^3.0.2",
"es6-shim": "^0.33.3", "es6-shim": "^0.33.3",

View File

@ -39,7 +39,7 @@ code-example(format="").
Let's follow a process that's closer to what we'd do in real life. Let's follow a process that's closer to what we'd do in real life.
1. Set up our development environment 1. Set up our development environment
1. Write the Angular root component for our main app 1. Write the Angular root component for our app
1. Bootstrap it to take control of the main web page 1. Bootstrap it to take control of the main web page
1. Write the main page (`index.html`) 1. Write the main page (`index.html`)
@ -127,48 +127,53 @@ code-example(format="").
### Add the component file ### Add the component file
Now add a file named **app.component.ts** and paste the following lines: Now add a file named **app.component.ts** and paste the following lines:
+makeExample('quickstart/ts/app/app.component.ts', null, 'app/app.component.ts')(format=".") +makeExample('quickstart/ts/app/app.component.ts', null, 'app/app.component.ts')(format=".")
:marked :marked
Let's review this file in detail, starting at the bottom where we define a class.
### The Component class ### The Component class
At the bottom of the file is an empty, do-nothing class named `AppComponent`. At the bottom of the file is an empty, do-nothing class named `AppComponent`.
When we're ready to build a substantive application, When we're ready to build a substantive application,
we can expand this class with properties and application logic. we can expand this class with properties and application logic.
Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart. Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart.
We do **export** the `AppComponent` class. Our component is a module.
Another part of the application will import our module and put it to work.
### Modules ### Modules
Angular apps are modular. They consist of many files each dedicated to a purpose. Angular apps are modular. They consist of many files each dedicated to a purpose.
Our `app.component` file is both the home and the name of the module that
provides the application's root component &mdash; its top level component.
Most application files *export* one thing such as a component.
Our `app.component` file exports the `AppComponent`.
+makeExample('quickstart/ts/app/app.component.ts', 'export', 'app/component.ts (export)')(format=".")
:marked
The act of exporting turns the file into a module.
The name of the file (without extension) is usually the name of the module.
Accordingly, '*app.component*' is the name of our first module.
A more sophisticated application would have child components that descended from A more sophisticated application would have child components that descended from
`AppComponent` in a visual tree. `AppComponent` in a visual tree.
A more sophisticated app would have more files and modules, at least as many as it had components.
Quickstart isn't sophisticated; one component is all we need. Quickstart isn't sophisticated; one component is all we need.
Yet modules play a fundamental organizational role in even this small app. Yet modules play a fundamental organizational role in even this small app.
Modules rely on other modules. In TypeScript Angular apps, when we need something Modules rely on other modules. In TypeScript Angular apps, when we need something
provided by another module, we import it. provided by another module, we import it.
When another module needs to refer to `AppComponent`, it imports the `AppComponent` *symbol* like this:
Angular is a collection of library modules. +makeExample('quickstart/ts/app/boot.ts', 'app-component','app/boot.ts (import)')(format=".")
Each library is a module made up of several, related feature modules.
The `angular2/core` library is the primary module and we need something from it.
We need the `Component`function.
When we want something from a module, we `import` it.
We begin by importing the `Component` symbol from Angular.
+makeExample('quickstart/ts/app/app.component.ts', 'import')(format=".")
:marked :marked
Then we use it to define metadata about the `AppComponent` Angular is also modular. It is a collection of library modules.
Each library is itself a module made up of several, related feature modules.
When we need something from Angular, we import it from an Angular library module.
We need something from Angular right now to help us define metadata about our component.
### Component Metadata ### Component Metadata
A class becomes an Angular component when we give it metadata. A class becomes an Angular component when we give it metadata.
Angular needs the metadata to understand how to construct the view Angular needs the metadata to understand how to construct the view
and how the component interacts with other parts of the application. and how the component interacts with other parts of the application.
We define a component's metadata with the `Component` function. We define a component's metadata with the Angular `Component` function.
We access that function by importing it from the primary Angular library,`angular2/core`.
+makeExample('quickstart/ts/app/app.component.ts', 'import', 'app/component.ts (import)')(format=".")
:marked
In TypeScript we apply that function to the class as a *decorator* In TypeScript we apply that function to the class as a *decorator*
by prefixing it with the **@** symbol and invoking it by prefixing it with the **@** symbol and invoking it
just above the component class: just above the component class:
@ -178,7 +183,7 @@ code-example(format="").
The configuration object passed to the `@Component` method has two The configuration object passed to the `@Component` method has two
fields, a `selector` and a `template`. fields, a `selector` and a `template`.
The `selector` specifies a CSS selector for a host HTML element named `my-app`. The `selector` specifies a simple CSS selector for a host HTML element named `my-app`.
Angular creates and displays an instance of our `AppComponent` Angular creates and displays an instance of our `AppComponent`
wherever it encounters a `my-app` element in the host HTML. wherever it encounters a `my-app` element in the host HTML.
@ -203,17 +208,11 @@ code-example(format="").
We import both. Then we call `bootstrap`, passing in the **root component type**, We import both. Then we call `bootstrap`, passing in the **root component type**,
`AppComponent`. `AppComponent`.
.l-sub-section .l-sub-section
:marked :marked
### bootstrapping is platform-specific Learn why we import `bootstrap` from `angular2/platform/browser`
Note that `bootstrap` function comes from a *different library*, `angular2/platform/browser`. and why we create a separate *boot.ts* file in the [appendex below](#boot).
Most Angular applications run only in a browser and we'll call the bootstrap function from
this library most of the time.
It is possible to load a component in a different enviroment such as we might do
if we wished to render the first page of our application on the server.
That would require a different kind of bootstrap function.
:marked :marked
We've asked Angular to launch the app in a browser with our component at the root. We've asked Angular to launch the app in a browser with our component at the root.
Where will Angular put it? Where will Angular put it?
@ -232,7 +231,7 @@ code-example(format="").
cd .. cd ..
:marked :marked
Now create the`index.html` file and paste the following lines: Now create the`index.html` file and paste the following lines:
+makeExample('quickstart/ts/index.html', null, 'index.html') +makeExample('quickstart/ts/index.html', null, 'index.html')(format=".")
:marked :marked
There are three noteworthy sections of HTML: There are three noteworthy sections of HTML:
@ -311,7 +310,7 @@ code-example(format="").
quickstart/ts/app/boot.ts, quickstart/ts/app/boot.ts,
quickstart/ts/index.html, quickstart/ts/index.html,
quickstart/ts/package.1.json, quickstart/ts/package.1.json,
quickstart/ts/tsconfig.json quickstart/ts/tsconfig.1.json
`,null, `,null,
`app/app.component.ts, app/boot.ts, index.html,package.json, tsconfig.json`) `app/app.component.ts, app/boot.ts, index.html,package.json, tsconfig.json`)
:marked :marked
@ -345,6 +344,20 @@ code-example(format="").
There is no essential material here. Continued reading is for the curious. There is no essential material here. Continued reading is for the curious.
.l-main-section
:marked
<a id="es6support"></a>
### Appendix: Browser ES6 support
Angular 2 relies on some ES2015 features, most of them found in modern
browsers. Some browsers (including IE 11) require a shim to support the
the needed functionality.
Try loading the following shim *above* the other scripts in the `index.html`:
code-example(language="html" format=".").
&lt;script src=&quot;node_modules/es6-shim/es6-shim.js&quot;&gt;&lt;/script&gt;
:marked
.l-main-section .l-main-section
:marked :marked
<a id="package-json"></a> <a id="package-json"></a>
@ -386,7 +399,8 @@ code-example(format="").
* `npm run lite` - run the [lite-server](https://www.npmjs.com/package/lite-server), * `npm run lite` - run the [lite-server](https://www.npmjs.com/package/lite-server),
a light-weight, static file server, written and maintained by [John Papa](http://johnpapa.net/) a light-weight, static file server, written and maintained by [John Papa](http://johnpapa.net/)
with excellent support for Angular apps that use routing. with excellent support for Angular apps that use routing.
<!-- Move this to the Style Guide when we have one --> <!-- Move this to the Style Guide when we have one -->
.l-main-section .l-main-section
:marked :marked
@ -447,7 +461,7 @@ code-example(format="").
:marked :marked
Learn more about SystemJS configuration [here](https://github.com/systemjs/systemjs/blob/master/docs/config-api.md). Learn more about SystemJS configuration [here](https://github.com/systemjs/systemjs/blob/master/docs/config-api.md).
:marked :marked
With those caustions in mind, what are we doing here? With those cautions in mind, what are we doing here?
+makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration')(format=".") +makeExample('quickstart/ts/index.html', 'systemjs', 'index.html (System configuration')(format=".")
:marked :marked
The `packages:` line tells SystemJS what to do when it sees a request for a The `packages:` line tells SystemJS what to do when it sees a request for a
@ -492,12 +506,75 @@ code-example(format="").
.l-main-section .l-main-section
:marked :marked
<a id="es6support"></a> <a id="boot"></a>
### Appendix: Browser ES6 support ### Appendix: ***boot.ts***
Angular 2 relies on some ES2015 features, most of them found in modern
browsers. Some browsers (including IE 11) require a shim to support the
the needed functionality.
Try loading the following shim *above* the other scripts in the `index.html`:
code-example(language="html" format="."). #### Bootstrapping is platform-specific
&lt;script src=&quot;node_modules/es6-shim/es6-shim.js&quot;&gt;&lt;/script&gt; We import the `bootstrap` function from `angular2/platform/browser`,
not `angular2/core`. There's a good reason.
We only call "core" those capabilities that are the same across all platform targets.
True, most Angular applications run only in a browser and we'll call the bootstrap function from
this library most of the time. It's pretty "core" if we're always writing for a browser.
But it is possible to load a component in a different enviroment.
We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/)
We might wish to render the first page of our application on the server
to improve launch performance or facilitate
[SEO](http://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf).
These targes require a different kind of bootstrap function that we'd import from a different library.
#### Why do we create a separate ***boot.ts*** file?
The *boot.ts* file is tiny. This is just a QuickStart.
We could have folded its few lines into the `app.component` file
and spared ourselves some complexity.
We didn't for what we believe to be good reasons:
1. Doing it right is easy
1. Testability
1. Reusability
1. Separation of concerns
1. We learned about import and export
#### It's easy
Sure it's an extra step and an extra file. How hard is that in the scheme of things?
We'll see that a separate `boot.ts` is beneficial for *most* apps
even if it isn't critical for the QuickStart.
Let's develop good habits now while the cost is low.
#### Testability
We should be thinking about testability from the beginning
even if we know we'll never test the QuickStart.
It is difficult to unit test a component when there is a call to `bootstrap` in the same file.
As soon as we load the component file to test the component,
the `bootstrap` function tries to load the application in the browser.
It throws an error because we're not expecting to run the entire application,
just test the component.
Relocating the `bootstrap` function to `boot.ts` eliminates this spurious error
and leaves us with a clean component module file.
#### Reusability
We refactor, rename, and relocate files as our application evolves.
We can't do any of those things while the file calls `bootstrap`.
we can't move it.
We can't reuse the component in another application.
We can't pre-render the component on the server for better performance.
#### Separation of concerns
A component's responsibility is to present and manage a view.
Launching the application has nothing to do with view management.
That's a separate concern. The friction we're encountering in testing and reuse
stems from this unnecessary mix of responsibilities.
#### Import/Export
While writing a separate `boot.ts` file we learned an essential Angular skill:
how to export from one module and import into another.
We'll do a lot of that as we learn more Angular.

View File

@ -40,22 +40,22 @@ var _rxData = [
{ {
pattern: 'script', pattern: 'script',
from: 'node_modules/angular2/bundles/angular2.dev.js', from: 'node_modules/angular2/bundles/angular2.dev.js',
to: 'https://code.angularjs.org/2.0.0-alpha.52/angular2.dev.js' to: 'https://code.angularjs.org/2.0.0-alpha.53/angular2.dev.js'
}, },
{ {
pattern: 'script', pattern: 'script',
from: 'node_modules/angular2/bundles/router.dev.js', from: 'node_modules/angular2/bundles/router.dev.js',
to: 'https://code.angularjs.org/2.0.0-alpha.52/router.dev.js' to: 'https://code.angularjs.org/2.0.0-alpha.53/router.dev.js'
}, },
{ {
pattern: 'script', pattern: 'script',
from: 'node_modules/angular2/bundles/http.dev.js', from: 'node_modules/angular2/bundles/http.dev.js',
to: 'https://code.angularjs.org/2.0.0-alpha.52/http.dev.js' to: 'https://code.angularjs.org/2.0.0-alpha.53/http.dev.js'
}, },
{ {
pattern: 'script', pattern: 'script',
from: 'node_modules/angular2/bundles/testing.js', from: 'node_modules/angular2/bundles/testing.js',
to: 'https://code.angularjs.org/2.0.0-alpha.52/testing.js' to: 'https://code.angularjs.org/2.0.0-alpha.53/testing.js'
}, },
{ {
pattern: 'link', pattern: 'link',

View File

@ -95,7 +95,14 @@ function initConfigAndCollectFileNames(configFileName) {
} }
}); });
// var defaultExcludes = [ '!**/node_modules/**','!**/typings/**','!**/tsconfig.json', '!**/*plnkr.json', '!**/*plnkr.html', '!**/*plnkr.no-link.html' ]; // var defaultExcludes = [ '!**/node_modules/**','!**/typings/**','!**/tsconfig.json', '!**/*plnkr.json', '!**/*plnkr.html', '!**/*plnkr.no-link.html' ];
var defaultExcludes = [ '!**/typings/**','!**/tsconfig.json', '!**/*plnkr.json', '!**/*plnkr.html', '!**/*plnkr.no-link.html', '!**/package.json', '!**/example-config.json' ]; var defaultExcludes = [
'!**/typings/**',
'!**/tsconfig.json',
'!**/*plnkr.*',
'!**/package.json',
'!**/example-config.json',
'!**/*.spec.*'
];
Array.prototype.push.apply(gpaths, defaultExcludes); Array.prototype.push.apply(gpaths, defaultExcludes);
config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] }); config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] });