Compare commits
233 Commits
api-overlo
...
6.0.4
Author | SHA1 | Date | |
---|---|---|---|
41698bf5fd | |||
23c50e27fc | |||
0ae8ea254a | |||
19deca159b | |||
dc3e8aa0fb | |||
a9222c0ade | |||
ea3127e3f9 | |||
8e30f7b1aa | |||
46d81b48ac | |||
3e51a2cb26 | |||
faf60d9310 | |||
0639cb9de1 | |||
810d025488 | |||
efe49c141a | |||
a3d9878c9d | |||
10213d0ca0 | |||
0e1919c2db | |||
d579b8ce05 | |||
d69ba735ee | |||
2991b1b217 | |||
b18cf21e99 | |||
c17098dae6 | |||
43e3073687 | |||
f28878f92f | |||
a10bdefa8b | |||
2f377dbcdd | |||
e2e7b4943e | |||
b8a1363bb2 | |||
e9e6a58dd0 | |||
5932a79713 | |||
7c6a082afd | |||
8a2fe5b7c9 | |||
c9eb4910eb | |||
a634a5abbc | |||
41225026e4 | |||
e9f2203347 | |||
906b3ec8e7 | |||
1cb0c4644a | |||
9d28a27215 | |||
f04aef48f2 | |||
d249852f4a | |||
707dd59767 | |||
4d2570576a | |||
76e58e6cca | |||
a27066b9d2 | |||
29dfc8f3ac | |||
b5533e0ee5 | |||
b275d378df | |||
96655f7aac | |||
253f509493 | |||
5a02ae2f84 | |||
f860752902 | |||
efa126f157 | |||
715135b117 | |||
c30fc52d99 | |||
434eb971e4 | |||
6e31e22d41 | |||
8fef926cd2 | |||
7698afedb1 | |||
a583d12660 | |||
a867d71ece | |||
84b43daf65 | |||
9b3423b50d | |||
d6041d83ec | |||
a638f504eb | |||
a29c756251 | |||
f206eb94bb | |||
3d6e82eccd | |||
154289305e | |||
469b1e4a9a | |||
7fee1fd442 | |||
0ee5b7efa5 | |||
afff84c03f | |||
23f2a7069f | |||
42260702f7 | |||
eec231d21e | |||
95344d6039 | |||
1c9839e91d | |||
bc1a66e907 | |||
2a83dbb0d8 | |||
4007d00403 | |||
61e32ac3c4 | |||
43ee10fbbd | |||
eb90039ea1 | |||
5d318ff234 | |||
f3361abdd7 | |||
52cbe894e9 | |||
41c2030534 | |||
daee41a40a | |||
68bd45ba87 | |||
0f6407750b | |||
95fca24fd8 | |||
a8f6542115 | |||
c6b618d020 | |||
ad6052e397 | |||
e9d1709156 | |||
b5d3de50cc | |||
734d37b231 | |||
bc2063807c | |||
2a528fcb15 | |||
752b83ac81 | |||
56be3375ec | |||
1b83b3fb15 | |||
14d4625ede | |||
fd880a8de4 | |||
bd3dddce4b | |||
1336a9451f | |||
d280077412 | |||
2b578f5c61 | |||
12dcb313af | |||
f576851ecc | |||
ca6cb66c32 | |||
484233f6c1 | |||
3d8799b3a2 | |||
8733843c11 | |||
f1097914c5 | |||
06776d1d10 | |||
2b31b6dc3f | |||
2254ac23e4 | |||
38c678fdcd | |||
1a655836cb | |||
2e466f4bea | |||
7b06fa88ab | |||
3d712894ae | |||
75b8edae03 | |||
fe7f48c1d5 | |||
29600cbb19 | |||
5581e97d2a | |||
19262d9f90 | |||
1eb1c6315d | |||
3807599a4d | |||
2ed41d9e38 | |||
5eb9c01bb6 | |||
09d9662386 | |||
844cbd9774 | |||
373a47dda9 | |||
83f12f3047 | |||
bbc416cdcd | |||
07f2098655 | |||
9b53a6e779 | |||
65f8505fb6 | |||
5a5ea45c40 | |||
52a3657b48 | |||
3824e3f858 | |||
05aa5e0179 | |||
4ddeb030e7 | |||
afe6380429 | |||
947ea17a09 | |||
a190c45a64 | |||
902781803f | |||
0d480ac0dc | |||
6934bf4863 | |||
7e7ea33fb0 | |||
5bd8c6887e | |||
d28ab372c8 | |||
d0ccf5f169 | |||
ecde15298a | |||
983e5f2d7e | |||
5fc4299e0a | |||
1823d5dd1c | |||
91d4da0d2f | |||
22eb8e26fc | |||
f6002c1702 | |||
14138f6382 | |||
f11daa2031 | |||
31a435ef5b | |||
3e92b22258 | |||
2e5457c824 | |||
1ab5fba92e | |||
e1e57ddaa7 | |||
ee7cb48877 | |||
a30c57090a | |||
8a49ec4f27 | |||
697b6c040c | |||
4008e36e80 | |||
e47bb52084 | |||
ac2b530f4b | |||
64bf6edf00 | |||
adf6235479 | |||
04c18ac1aa | |||
1b26dd8cdb | |||
f721b06bde | |||
0bc8443e12 | |||
db17231597 | |||
540626a3a6 | |||
391bfcede5 | |||
d8de6488dd | |||
151fb66848 | |||
02424ff0d0 | |||
f0925d9705 | |||
212b806eda | |||
b9431e88fb | |||
7790cfa0d0 | |||
41b5149509 | |||
06f865640d | |||
824f74f27b | |||
5301c43eed | |||
f280d1aef1 | |||
5e741d42a6 | |||
0035d41030 | |||
08f447ceec | |||
8953f123e3 | |||
6274007e3b | |||
ee76be7783 | |||
a8c720bc3a | |||
ac47a3cd93 | |||
041458a3d2 | |||
2cb74b748f | |||
cb0bfe7a43 | |||
8ee11aeaa6 | |||
bf89fcb361 | |||
4f70c5b6f7 | |||
ad3ebec2a5 | |||
3f5d61f2dd | |||
11ada7f78b | |||
0b96bc7456 | |||
fefadadff3 | |||
946057ae29 | |||
d4293aaaaa | |||
e3dcc227f6 | |||
c9230dd90e | |||
234af9ba59 | |||
7204028d3e | |||
f7c55952bf | |||
e38e3bd135 | |||
cd20c01ba1 | |||
12a191ef3f | |||
65e67b3c3a | |||
32e57f6197 | |||
7de69ba29b | |||
44193c0b94 | |||
6db8241ffa | |||
33c594516c |
@ -12,8 +12,8 @@
|
|||||||
## IMPORTANT
|
## IMPORTANT
|
||||||
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
||||||
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
||||||
var_1: &docker_image angular/ngcontainer:0.3.3
|
var_1: &docker_image angular/ngcontainer:0.3.0
|
||||||
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.3.3
|
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.3.0
|
||||||
|
|
||||||
# Define common ENV vars
|
# Define common ENV vars
|
||||||
var_3: &define_env_vars
|
var_3: &define_env_vars
|
||||||
@ -85,7 +85,7 @@ jobs:
|
|||||||
# This avoids waiting for the slowest build target to finish before running the first test
|
# This avoids waiting for the slowest build target to finish before running the first test
|
||||||
# See https://github.com/bazelbuild/bazel/issues/4257
|
# See https://github.com/bazelbuild/bazel/issues/4257
|
||||||
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
|
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
|
||||||
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only --test_tag_filters=-manual,-ivy-only
|
- run: bazel query --output=label //... | xargs bazel test
|
||||||
|
|
||||||
# CircleCI will allow us to go back and view/download these artifacts from past builds.
|
# CircleCI will allow us to go back and view/download these artifacts from past builds.
|
||||||
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
|
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
|
||||||
@ -111,42 +111,6 @@ jobs:
|
|||||||
paths:
|
paths:
|
||||||
- "node_modules"
|
- "node_modules"
|
||||||
- "~/bazel_repository_cache"
|
- "~/bazel_repository_cache"
|
||||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
|
||||||
test_ivy_jit:
|
|
||||||
<<: *job_defaults
|
|
||||||
resource_class: xlarge
|
|
||||||
steps:
|
|
||||||
- *define_env_vars
|
|
||||||
- checkout:
|
|
||||||
<<: *post_checkout
|
|
||||||
# See remote cache documentation in /docs/BAZEL.md
|
|
||||||
- run: .circleci/setup_cache.sh
|
|
||||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
|
||||||
- *setup-bazel-remote-cache
|
|
||||||
|
|
||||||
- restore_cache:
|
|
||||||
key: *cache_key
|
|
||||||
|
|
||||||
- run: bazel run @yarn//:yarn
|
|
||||||
- run: bazel query --output=label //... | xargs bazel test --define=compile=jit --build_tag_filters=ivy-jit --test_tag_filters=-manual,ivy-jit
|
|
||||||
|
|
||||||
test_ivy_aot:
|
|
||||||
<<: *job_defaults
|
|
||||||
resource_class: xlarge
|
|
||||||
steps:
|
|
||||||
- *define_env_vars
|
|
||||||
- checkout:
|
|
||||||
<<: *post_checkout
|
|
||||||
# See remote cache documentation in /docs/BAZEL.md
|
|
||||||
- run: .circleci/setup_cache.sh
|
|
||||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
|
||||||
- *setup-bazel-remote-cache
|
|
||||||
|
|
||||||
- restore_cache:
|
|
||||||
key: *cache_key
|
|
||||||
|
|
||||||
- run: bazel run @yarn//:yarn
|
|
||||||
- run: bazel query --output=label //... | xargs bazel test --define=compile=local --build_tag_filters=ivy-local --test_tag_filters=-manual,ivy-local
|
|
||||||
|
|
||||||
# This job exists only for backwards-compatibility with old scripts and tests
|
# This job exists only for backwards-compatibility with old scripts and tests
|
||||||
# that rely on the pre-Bazel dist/packages-dist layout.
|
# that rely on the pre-Bazel dist/packages-dist layout.
|
||||||
@ -176,8 +140,6 @@ jobs:
|
|||||||
root: dist
|
root: dist
|
||||||
paths:
|
paths:
|
||||||
- packages-dist
|
- packages-dist
|
||||||
- packages-dist-ivy-jit
|
|
||||||
- packages-dist-ivy-local
|
|
||||||
|
|
||||||
# We run the integration tests outside of Bazel for now.
|
# We run the integration tests outside of Bazel for now.
|
||||||
# They are a separate workflow job so that they can be easily re-run.
|
# They are a separate workflow job so that they can be easily re-run.
|
||||||
@ -187,10 +149,6 @@ jobs:
|
|||||||
# See comments inside the integration/run_tests.sh script.
|
# See comments inside the integration/run_tests.sh script.
|
||||||
integration_test:
|
integration_test:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
# Note: we run Bazel in one of the integration tests, and it can consume >2G
|
|
||||||
# of memory. Together with the system under test, this can exhaust the RAM
|
|
||||||
# on a 4G worker so we use a larger machine here too.
|
|
||||||
resource_class: xlarge
|
|
||||||
steps:
|
steps:
|
||||||
- *define_env_vars
|
- *define_env_vars
|
||||||
- checkout:
|
- checkout:
|
||||||
@ -242,8 +200,6 @@ workflows:
|
|||||||
jobs:
|
jobs:
|
||||||
- lint
|
- lint
|
||||||
- test
|
- test
|
||||||
- test_ivy_jit
|
|
||||||
- test_ivy_aot
|
|
||||||
- build-packages-dist
|
- build-packages-dist
|
||||||
- integration_test:
|
- integration_test:
|
||||||
requires:
|
requires:
|
||||||
@ -256,8 +212,6 @@ workflows:
|
|||||||
requires:
|
requires:
|
||||||
# Only publish if tests and integration tests pass
|
# Only publish if tests and integration tests pass
|
||||||
- test
|
- test
|
||||||
- test_ivy_jit
|
|
||||||
- test_ivy_aot
|
|
||||||
- integration_test
|
- integration_test
|
||||||
# Get the artifacts to publish from the build-packages-dist job
|
# Get the artifacts to publish from the build-packages-dist job
|
||||||
# since the publishing script expects the legacy outputs layout.
|
# since the publishing script expects the legacy outputs layout.
|
||||||
|
@ -163,7 +163,7 @@ groups:
|
|||||||
files:
|
files:
|
||||||
- "packages/compiler/*"
|
- "packages/compiler/*"
|
||||||
users:
|
users:
|
||||||
- alxhub #primary
|
- chuckjaz #primary
|
||||||
- vicb
|
- vicb
|
||||||
- mhevery
|
- mhevery
|
||||||
- IgorMinar #fallback
|
- IgorMinar #fallback
|
||||||
|
@ -22,7 +22,6 @@ node_modules_filegroup(
|
|||||||
"jasmine",
|
"jasmine",
|
||||||
"minimist",
|
"minimist",
|
||||||
"protobufjs",
|
"protobufjs",
|
||||||
"protractor",
|
|
||||||
"reflect-metadata",
|
"reflect-metadata",
|
||||||
"source-map-support",
|
"source-map-support",
|
||||||
"tsickle",
|
"tsickle",
|
||||||
@ -35,9 +34,6 @@ node_modules_filegroup(
|
|||||||
"@types",
|
"@types",
|
||||||
"@webcomponents/custom-elements",
|
"@webcomponents/custom-elements",
|
||||||
],
|
],
|
||||||
patterns = [
|
|
||||||
"node_modules/protractor/**",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
187
CHANGELOG.md
187
CHANGELOG.md
@ -1,190 +1,3 @@
|
|||||||
<a name="6.0.9"></a>
|
|
||||||
## [6.0.9](https://github.com/angular/angular/compare/6.0.8...6.0.9) (2018-07-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
* **common:** format fractional seconds ([#24844](https://github.com/angular/angular/issues/24844)) ([3c93d07](https://github.com/angular/angular/commit/3c93d07)), closes [#24831](https://github.com/angular/angular/issues/24831)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.1.0-rc.0"></a>
|
|
||||||
# [6.1.0-rc.0](https://github.com/angular/angular/compare/6.1.0-beta.3...6.1.0-rc.0) (2018-07-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **common:** do not round factional seconds ([#24831](https://github.com/angular/angular/issues/24831)) ([a527c69](https://github.com/angular/angular/commit/a527c69)), closes [#24384](https://github.com/angular/angular/issues/24384)
|
|
||||||
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([ff84c5c](https://github.com/angular/angular/commit/ff84c5c)), closes [#24155](https://github.com/angular/angular/issues/24155)
|
|
||||||
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([dcabb05](https://github.com/angular/angular/commit/dcabb05)), closes [#24609](https://github.com/angular/angular/issues/24609)
|
|
||||||
* **compiler:** fix a few non-tree-shakeable code patterns ([#24677](https://github.com/angular/angular/issues/24677)) ([50d4a4f](https://github.com/angular/angular/commit/50d4a4f))
|
|
||||||
* **compiler-cli:** Use typescript to resolve modules for metadata ([#22856](https://github.com/angular/angular/issues/22856)) ([0d5f2d3](https://github.com/angular/angular/commit/0d5f2d3))
|
|
||||||
* **core:** mark NgModule as not the root if APP_ROOT is set to false ([#24814](https://github.com/angular/angular/issues/24814)) ([1089261](https://github.com/angular/angular/commit/1089261))
|
|
||||||
* **core:** use addCustomEqualityTester instead of overriding toEqual ([#22983](https://github.com/angular/angular/issues/22983)) ([0922228](https://github.com/angular/angular/commit/0922228)), closes [#22939](https://github.com/angular/angular/issues/22939)
|
|
||||||
* **language-service:** do not overwrite native `Reflect` ([#24299](https://github.com/angular/angular/issues/24299)) ([6881404](https://github.com/angular/angular/commit/6881404)), closes [#21420](https://github.com/angular/angular/issues/21420)
|
|
||||||
* **platform-browser:** add missing deps for HammerGesturesPlugin ([#24682](https://github.com/angular/angular/issues/24682)) ([13d60ea](https://github.com/angular/angular/commit/13d60ea))
|
|
||||||
* **platform-browser:** mark Meta and Title services as tree shakable providers ([#24815](https://github.com/angular/angular/issues/24815)) ([197387d](https://github.com/angular/angular/commit/197387d))
|
|
||||||
* **platform-browser:** workaround wrong import path generated by ngc for DOCUMENT ([#24830](https://github.com/angular/angular/issues/24830)) ([7d27ecc](https://github.com/angular/angular/commit/7d27ecc))
|
|
||||||
* **router:** add ability to recover from malformed url ([#23283](https://github.com/angular/angular/issues/23283)) ([86d254d](https://github.com/angular/angular/commit/86d254d)), closes [#21468](https://github.com/angular/angular/issues/21468)
|
|
||||||
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([52d43a9](https://github.com/angular/angular/commit/52d43a9))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **core:** add support for ShadowDOM v1 ([#24718](https://github.com/angular/angular/issues/24718)) ([3553977](https://github.com/angular/angular/commit/3553977))
|
|
||||||
* **core:** add support for using async/await with Jasmine ([#24637](https://github.com/angular/angular/issues/24637)) ([71100e6](https://github.com/angular/angular/commit/71100e6))
|
|
||||||
* typescript 2.9 support ([#24652](https://github.com/angular/angular/issues/24652)) ([e3064d5](https://github.com/angular/angular/commit/e3064d5))
|
|
||||||
* **service-worker:** add support for `?` in SW config globbing ([#24105](https://github.com/angular/angular/issues/24105)) ([250527c](https://github.com/angular/angular/commit/250527c))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.0.8"></a>
|
|
||||||
## [6.0.8](https://github.com/angular/angular/compare/6.0.7...6.0.8) (2018-07-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **common:** do not round factional seconds ([#24831](https://github.com/angular/angular/issues/24831)) ([0746485](https://github.com/angular/angular/commit/0746485)), closes [#24384](https://github.com/angular/angular/issues/24384)
|
|
||||||
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([9a98de9](https://github.com/angular/angular/commit/9a98de9)), closes [#24155](https://github.com/angular/angular/issues/24155)
|
|
||||||
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([a92f111](https://github.com/angular/angular/commit/a92f111)), closes [#24609](https://github.com/angular/angular/issues/24609)
|
|
||||||
* **compiler-cli:** Use typescript to resolve modules for metadata ([#22856](https://github.com/angular/angular/issues/22856)) ([7717ff1](https://github.com/angular/angular/commit/7717ff1))
|
|
||||||
* **core:** use addCustomEqualityTester instead of overriding toEqual ([#22983](https://github.com/angular/angular/issues/22983)) ([b8975a9](https://github.com/angular/angular/commit/b8975a9)), closes [#22939](https://github.com/angular/angular/issues/22939)
|
|
||||||
* **language-service:** do not overwrite native `Reflect` ([#24299](https://github.com/angular/angular/issues/24299)) ([de1c44f](https://github.com/angular/angular/commit/de1c44f)), closes [#21420](https://github.com/angular/angular/issues/21420)
|
|
||||||
* **router:** add ability to recover from malformed url ([#23283](https://github.com/angular/angular/issues/23283)) ([2d4f4b5](https://github.com/angular/angular/commit/2d4f4b5)), closes [#21468](https://github.com/angular/angular/issues/21468)
|
|
||||||
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([183b079](https://github.com/angular/angular/commit/183b079))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **core:** add support for ShadowDOM v1 ([#24718](https://github.com/angular/angular/issues/24718)) ([6c55a13](https://github.com/angular/angular/commit/6c55a13))
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.1.0-beta.3"></a>
|
|
||||||
# [6.1.0-beta.3](https://github.com/angular/angular/compare/6.1.0-beta.2...6.1.0-beta.3) (2018-06-28)
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
|
|
||||||
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
|
|
||||||
|
|
||||||
<a name="6.0.7"></a>
|
|
||||||
## [6.0.7](https://github.com/angular/angular/compare/6.0.6...6.0.7) (2018-06-27)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
|
|
||||||
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.1.0-beta.2"></a>
|
|
||||||
# [6.1.0-beta.2](https://github.com/angular/angular/compare/6.1.0-beta.1...6.1.0-beta.2) (2018-06-20)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([d8f7b29](https://github.com/angular/angular/commit/d8f7b29)), closes [#20363](https://github.com/angular/angular/issues/20363)
|
|
||||||
* **core:** Injector correctly honors the @Self flag ([#24520](https://github.com/angular/angular/issues/24520)) ([ccbda9d](https://github.com/angular/angular/commit/ccbda9d))
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.0.6"></a>
|
|
||||||
## [6.0.6](https://github.com/angular/angular/compare/6.0.5...6.0.6) (2018-06-20)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([e543c73](https://github.com/angular/angular/commit/e543c73)), closes [#20363](https://github.com/angular/angular/issues/20363)
|
|
||||||
* **core:** Injector correctly honors the @Self flag ([#24520](https://github.com/angular/angular/issues/24520)) ([f5b3661](https://github.com/angular/angular/commit/f5b3661))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.1.0-beta.1"></a>
|
|
||||||
# [6.1.0-beta.1](https://github.com/angular/angular/compare/6.1.0-beta.0...6.1.0-beta.1) (2018-06-13)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([dc4a3d0](https://github.com/angular/angular/commit/dc4a3d0))
|
|
||||||
* **bazel:** Allow ng_module to depend on targets w no deps ([#24446](https://github.com/angular/angular/issues/24446)) ([282d351](https://github.com/angular/angular/commit/282d351))
|
|
||||||
* **docs-infra:** use script nomodule to load IE polyfills, skip other polyfills ([#24317](https://github.com/angular/angular/issues/24317)) ([8be6892](https://github.com/angular/angular/commit/8be6892)), closes [#23647](https://github.com/angular/angular/issues/23647)
|
|
||||||
* **ivy:** compute transitive scopes from NgModuleDef only ([#24334](https://github.com/angular/angular/issues/24334)) ([1135563](https://github.com/angular/angular/commit/1135563))
|
|
||||||
* **ivy:** correctly handle queries with embedded views ([#24418](https://github.com/angular/angular/issues/24418)) ([014949f](https://github.com/angular/angular/commit/014949f))
|
|
||||||
* **ivy:** remove debugger statement ([#24480](https://github.com/angular/angular/issues/24480)) ([70ef061](https://github.com/angular/angular/commit/70ef061))
|
|
||||||
* **ivy:** special case [style] and [class] bindings for future use ([#23232](https://github.com/angular/angular/issues/23232)) ([1b253e1](https://github.com/angular/angular/commit/1b253e1))
|
|
||||||
* **router:** fix lazy loading of aux routes ([#23459](https://github.com/angular/angular/issues/23459)) ([5731d07](https://github.com/angular/angular/commit/5731d07)), closes [#10981](https://github.com/angular/angular/issues/10981)
|
|
||||||
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([3ed2d75](https://github.com/angular/angular/commit/3ed2d75)), closes [#24095](https://github.com/angular/angular/issues/24095)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **common:** introduce KeyValuePipe ([#24319](https://github.com/angular/angular/issues/24319)) ([2b49bf7](https://github.com/angular/angular/commit/2b49bf7))
|
|
||||||
* **core:** export defaultKeyValueDiffers to private api ([#24319](https://github.com/angular/angular/issues/24319)) ([92b278c](https://github.com/angular/angular/commit/92b278c))
|
|
||||||
* **core:** expose a Compiler API for accessing module ids from NgModule types ([#24258](https://github.com/angular/angular/issues/24258)) ([bd02b27](https://github.com/angular/angular/commit/bd02b27))
|
|
||||||
* **core:** KeyValueDiffer#diff allows null values ([#24319](https://github.com/angular/angular/issues/24319)) ([52ce9d5](https://github.com/angular/angular/commit/52ce9d5))
|
|
||||||
* **ivy:** a generic visitor which allows prefixing nodes for ngtsc ([#24230](https://github.com/angular/angular/issues/24230)) ([ca79e11](https://github.com/angular/angular/commit/ca79e11))
|
|
||||||
* **ivy:** add support of ApplicationRef.bootstrapModuleFactory ([#23811](https://github.com/angular/angular/issues/23811)) ([e3759f7](https://github.com/angular/angular/commit/e3759f7))
|
|
||||||
* **ivy:** namespaced attributes added to output instructions ([#24386](https://github.com/angular/angular/issues/24386)) ([82c5313](https://github.com/angular/angular/commit/82c5313))
|
|
||||||
* **ivy:** now supports SVG and MathML elements ([#24377](https://github.com/angular/angular/issues/24377)) ([8c1ac28](https://github.com/angular/angular/commit/8c1ac28))
|
|
||||||
* **router:** implement scrolling restoration service ([#20030](https://github.com/angular/angular/issues/20030)) ([49c5234](https://github.com/angular/angular/commit/49c5234)), closes [#13636](https://github.com/angular/angular/issues/13636) [#10929](https://github.com/angular/angular/issues/10929) [#7791](https://github.com/angular/angular/issues/7791) [#6595](https://github.com/angular/angular/issues/6595)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.0.5"></a>
|
|
||||||
## [6.0.5](https://github.com/angular/angular/compare/6.0.4...6.0.5) (2018-06-13)
|
|
||||||
|
|
||||||
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([0139173](https://github.com/angular/angular/commit/0139173))
|
|
||||||
* **bazel:** Allow ng_module to depend on targets w no deps ([#24446](https://github.com/angular/angular/issues/24446)) ([ea3669e](https://github.com/angular/angular/commit/ea3669e))
|
|
||||||
* **docs-infra:** use script nomodule to load IE polyfills, skip other polyfills ([#24317](https://github.com/angular/angular/issues/24317)) ([e876535](https://github.com/angular/angular/commit/e876535)), closes [#23647](https://github.com/angular/angular/issues/23647)
|
|
||||||
* **router:** fix lazy loading of aux routes ([#23459](https://github.com/angular/angular/issues/23459)) ([d20877b](https://github.com/angular/angular/commit/d20877b)), closes [#10981](https://github.com/angular/angular/issues/10981)
|
|
||||||
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([ea2987c](https://github.com/angular/angular/commit/ea2987c)), closes [#24095](https://github.com/angular/angular/issues/24095)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.1.0-beta.0"></a>
|
|
||||||
# [6.1.0-beta.0](https://github.com/angular/angular/compare/6.0.0-rc.5...6.1.0-beta.0) (2018-06-06)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([d2a8687](https://github.com/angular/angular/commit/d2a8687))
|
|
||||||
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([b492b9e](https://github.com/angular/angular/commit/b492b9e))
|
|
||||||
* **animations:** properly clean up queried element styles in safari/edge ([#23633](https://github.com/angular/angular/issues/23633)) ([da9ff25](https://github.com/angular/angular/commit/da9ff25))
|
|
||||||
* **animations:** retain state styling for nodes that are moved around ([#23534](https://github.com/angular/angular/issues/23534)) ([65211f4](https://github.com/angular/angular/commit/65211f4))
|
|
||||||
* **animations:** retain trigger-state for nodes that are moved around ([#24238](https://github.com/angular/angular/issues/24238)) ([8db928d](https://github.com/angular/angular/commit/8db928d))
|
|
||||||
* **benchpress:** Fix promise chain in chrome_driver_extension. ([#23458](https://github.com/angular/angular/issues/23458)) ([d4b6c41](https://github.com/angular/angular/commit/d4b6c41))
|
|
||||||
* **compiler:** avoid a crash in ngc-wrapped. ([#23468](https://github.com/angular/angular/issues/23468)) ([e1c4930](https://github.com/angular/angular/commit/e1c4930))
|
|
||||||
* **compiler:** generate constant array for i18n attributes ([#23837](https://github.com/angular/angular/issues/23837)) ([cfde36d](https://github.com/angular/angular/commit/cfde36d))
|
|
||||||
* **compiler:** generate core-compliant hostBindings property ([#24087](https://github.com/angular/angular/issues/24087)) ([01b5acd](https://github.com/angular/angular/commit/01b5acd)), closes [#24013](https://github.com/angular/angular/issues/24013)
|
|
||||||
* **compiler:** handle undefined annotation metadata ([#23349](https://github.com/angular/angular/issues/23349)) ([ca776c5](https://github.com/angular/angular/commit/ca776c5))
|
|
||||||
* **compiler-cli:** don't rely on incompatible TS method ([#23550](https://github.com/angular/angular/issues/23550)) ([b1f040f](https://github.com/angular/angular/commit/b1f040f))
|
|
||||||
* **core:** avoid eager providers re-initialization ([#23559](https://github.com/angular/angular/issues/23559)) ([0c6dc45](https://github.com/angular/angular/commit/0c6dc45))
|
|
||||||
* **core:** call ngOnDestroy on all services that have it ([#23755](https://github.com/angular/angular/issues/23755)) ([fc03427](https://github.com/angular/angular/commit/fc03427)), closes [#22466](https://github.com/angular/angular/issues/22466) [#22240](https://github.com/angular/angular/issues/22240) [#14818](https://github.com/angular/angular/issues/14818)
|
|
||||||
* **elements:** always check to create strategy ([#23825](https://github.com/angular/angular/issues/23825)) ([b1cda36](https://github.com/angular/angular/commit/b1cda36))
|
|
||||||
* **elements:** prevent closure renaming of platform properties ([#23843](https://github.com/angular/angular/issues/23843)) ([d4b8b24](https://github.com/angular/angular/commit/d4b8b24))
|
|
||||||
* **forms:** properly handle special properties in FormGroup.get ([#22249](https://github.com/angular/angular/issues/22249)) ([9367e91](https://github.com/angular/angular/commit/9367e91)), closes [#17195](https://github.com/angular/angular/issues/17195)
|
|
||||||
* **platform-server:** avoid clash between server and client style encapsulation attributes ([#24158](https://github.com/angular/angular/issues/24158)) ([b96a3c8](https://github.com/angular/angular/commit/b96a3c8))
|
|
||||||
* **platform-server:** avoid dependency cycle when using http interceptor ([#24229](https://github.com/angular/angular/issues/24229)) ([60aa943](https://github.com/angular/angular/commit/60aa943)), closes [#23023](https://github.com/angular/angular/issues/23023)
|
|
||||||
* **platform-server:** don't reflect innerHTML property to attibute ([#24213](https://github.com/angular/angular/issues/24213)) ([6a663a4](https://github.com/angular/angular/commit/6a663a4)), closes [#19278](https://github.com/angular/angular/issues/19278)
|
|
||||||
* **platform-server:** provide Domino DOM types globally ([#24116](https://github.com/angular/angular/issues/24116)) ([c73196e](https://github.com/angular/angular/commit/c73196e)), closes [#23280](https://github.com/angular/angular/issues/23280) [#23133](https://github.com/angular/angular/issues/23133)
|
|
||||||
* **router:** avoid freezing queryParams in-place ([#22663](https://github.com/angular/angular/issues/22663)) ([89f64e5](https://github.com/angular/angular/commit/89f64e5)), closes [#22617](https://github.com/angular/angular/issues/22617)
|
|
||||||
* **router:** cache route handle if found ([#22475](https://github.com/angular/angular/issues/22475)) ([4cfa571](https://github.com/angular/angular/commit/4cfa571)), closes [#22474](https://github.com/angular/angular/issues/22474)
|
|
||||||
* **router:** correct the segment parsing so it won't break on ampersand ([#23684](https://github.com/angular/angular/issues/23684)) ([553a680](https://github.com/angular/angular/commit/553a680))
|
|
||||||
* **service-worker:** add badge to NOTIFICATION_OPTION_NAMES ([#23241](https://github.com/angular/angular/issues/23241)) ([fb59b2d](https://github.com/angular/angular/commit/fb59b2d)), closes [#23196](https://github.com/angular/angular/issues/23196)
|
|
||||||
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0bdd30e](https://github.com/angular/angular/commit/0bdd30e))
|
|
||||||
* **service-worker:** correctly handle requests with empty `clientId` ([#23625](https://github.com/angular/angular/issues/23625)) ([e0ed59e](https://github.com/angular/angular/commit/e0ed59e)), closes [#23526](https://github.com/angular/angular/issues/23526)
|
|
||||||
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([1d378e2](https://github.com/angular/angular/commit/1d378e2))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **compiler:** support `// ...` and `// TODO` in mock compiler expectations ([#23441](https://github.com/angular/angular/issues/23441)) ([c6b206e](https://github.com/angular/angular/commit/c6b206e))
|
|
||||||
* **compiler-cli:** update `tsickle` to `0.29.x` ([#24233](https://github.com/angular/angular/issues/24233)) ([f69ac67](https://github.com/angular/angular/commit/f69ac67))
|
|
||||||
* **platform-browser:** add HammerJS lazy-loader symbols to public API ([#23943](https://github.com/angular/angular/issues/23943)) ([26fbf1d](https://github.com/angular/angular/commit/26fbf1d))
|
|
||||||
* **platform-browser:** allow lazy-loading HammerJS ([#23906](https://github.com/angular/angular/issues/23906)) ([313bdce](https://github.com/angular/angular/commit/313bdce))
|
|
||||||
* **platform-server:** use EventManagerPlugin on the server ([#24132](https://github.com/angular/angular/issues/24132)) ([d6595eb](https://github.com/angular/angular/commit/d6595eb))
|
|
||||||
* **router:** add navigation execution context info to activation hooks ([#24204](https://github.com/angular/angular/issues/24204)) ([20c463e](https://github.com/angular/angular/commit/20c463e)), closes [#24202](https://github.com/angular/angular/issues/24202)
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.0.4"></a>
|
<a name="6.0.4"></a>
|
||||||
## [6.0.4](https://github.com/angular/angular/compare/6.0.3...6.0.4) (2018-06-06)
|
## [6.0.4](https://github.com/angular/angular/compare/6.0.3...6.0.4) (2018-06-06)
|
||||||
|
|
||||||
|
@ -227,15 +227,10 @@ The following is the list of supported scopes:
|
|||||||
|
|
||||||
There are currently a few exceptions to the "use package name" rule:
|
There are currently a few exceptions to the "use package name" rule:
|
||||||
|
|
||||||
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g.
|
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
|
||||||
public path changes, package.json changes done to all packages, d.ts file/format changes, changes
|
|
||||||
to bundles, etc.
|
|
||||||
* **changelog**: used for updating the release notes in CHANGELOG.md
|
* **changelog**: used for updating the release notes in CHANGELOG.md
|
||||||
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
* **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo
|
||||||
repo
|
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
|
||||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
|
||||||
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
|
||||||
specific package (e.g. `docs: fix typo in tutorial`).
|
|
||||||
|
|
||||||
### Subject
|
### Subject
|
||||||
The subject contains a succinct description of the change:
|
The subject contains a succinct description of the change:
|
||||||
|
32
WORKSPACE
32
WORKSPACE
@ -6,23 +6,23 @@ workspace(name = "angular")
|
|||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.10.1.zip",
|
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.9.1.zip",
|
||||||
strip_prefix = "rules_nodejs-0.10.1",
|
strip_prefix = "rules_nodejs-0.9.1",
|
||||||
sha256 = "634206524d90dc03c52392fa3f19a16637d2bcf154910436fe1d669a0d9d7b9c",
|
sha256 = "6139762b62b37c1fd171d7f22aa39566cb7dc2916f0f801d505a9aaf118c117f",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "io_bazel_rules_webtesting",
|
name = "io_bazel_rules_webtesting",
|
||||||
url = "https://github.com/bazelbuild/rules_webtesting/archive/7ffe970bbf380891754487f66c3d680c087d67f2.zip",
|
url = "https://github.com/bazelbuild/rules_webtesting/archive/v0.2.0.zip",
|
||||||
strip_prefix = "rules_webtesting-7ffe970bbf380891754487f66c3d680c087d67f2",
|
strip_prefix = "rules_webtesting-0.2.0",
|
||||||
sha256 = "4fb0dca8c9a90547891b7ef486592775a523330fc4555c88cd8f09270055c2ce",
|
sha256 = "cecc12f07e95740750a40d38e8b14b76fefa1551bef9332cb432d564d693723c",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_typescript",
|
name = "build_bazel_rules_typescript",
|
||||||
url = "https://github.com/bazelbuild/rules_typescript/archive/0.15.1.zip",
|
url = "https://github.com/bazelbuild/rules_typescript/archive/0.15.0.zip",
|
||||||
strip_prefix = "rules_typescript-0.15.1",
|
strip_prefix = "rules_typescript-0.15.0",
|
||||||
sha256 = "3792cc20ef13bb1d1d8b1760894c3320f02a87843e3a04fed7e8e454a75328b6",
|
sha256 = "1aa75917330b820cb239b3c10a936a10f0a46fe215063d4492dd76dc6e1616f4",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
@ -34,13 +34,13 @@ http_archive(
|
|||||||
# This commit matches the version of buildifier in angular/ngcontainer
|
# This commit matches the version of buildifier in angular/ngcontainer
|
||||||
# If you change this, also check if it matches the version in the angular/ngcontainer
|
# If you change this, also check if it matches the version in the angular/ngcontainer
|
||||||
# version in /.circleci/config.yml
|
# version in /.circleci/config.yml
|
||||||
BAZEL_BUILDTOOLS_VERSION = "82b21607e00913b16fe1c51bec80232d9d6de31c"
|
BAZEL_BUILDTOOLS_VERSION = "fd9878fd5de921e0bbab3dcdcb932c2627812ee1"
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "com_github_bazelbuild_buildtools",
|
name = "com_github_bazelbuild_buildtools",
|
||||||
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
||||||
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
||||||
sha256 = "edb24c2f9c55b10a820ec74db0564415c0cf553fa55e9fc709a6332fb6685eff",
|
sha256 = "27bb461ade23fd44ba98723ad98f84ee9c83cd3540b773b186a1bc5037f3d862",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fetching the Bazel source code allows us to compile the Skylark linter
|
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||||
@ -58,10 +58,10 @@ http_archive(
|
|||||||
# Even better, things like aspects will visit the entire graph including
|
# Even better, things like aspects will visit the entire graph including
|
||||||
# ts_library rules in the devkit repository.
|
# ts_library rules in the devkit repository.
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "angular_cli",
|
name = "angular_devkit",
|
||||||
url = "https://github.com/angular/angular-cli/archive/v6.1.0-rc.0.zip",
|
url = "https://github.com/angular/devkit/archive/v0.3.1.zip",
|
||||||
strip_prefix = "angular-cli-6.1.0-rc.0",
|
strip_prefix = "devkit-0.3.1",
|
||||||
sha256 = "8cf320ea58c321e103f39087376feea502f20eaf79c61a4fdb05c7286c8684fd",
|
sha256 = "31d4b597fe9336650acf13df053c1c84dcbe9c29c6a833bcac3819cd3fd8cad3",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
@ -77,7 +77,7 @@ http_archive(
|
|||||||
|
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
||||||
|
|
||||||
check_bazel_version("0.15.0")
|
check_bazel_version("0.13.0")
|
||||||
node_repositories(package_json = ["//:package.json"])
|
node_repositories(package_json = ["//:package.json"])
|
||||||
|
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
||||||
|
@ -52,7 +52,8 @@ export class BuildCleaner {
|
|||||||
protected removeDir(dir: string) {
|
protected removeDir(dir: string) {
|
||||||
try {
|
try {
|
||||||
if (shell.test('-d', dir)) {
|
if (shell.test('-d', dir)) {
|
||||||
shell.chmod('-R', 'a+w', dir);
|
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
||||||
|
(shell as any).chmod('-R', 'a+w', dir);
|
||||||
shell.rm('-rf', dir);
|
shell.rm('-rf', dir);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -106,7 +106,8 @@ export class BuildCreator extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
shell.chmod('-R', 'a-w', outputDir);
|
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
||||||
|
(shell as any).chmod('-R', 'a-w', outputDir);
|
||||||
shell.rm('-f', inputFile);
|
shell.rm('-f', inputFile);
|
||||||
resolve();
|
resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -98,7 +98,8 @@ class Helper {
|
|||||||
const prDir = this.getPrDir(pr, isPublic);
|
const prDir = this.getPrDir(pr, isPublic);
|
||||||
|
|
||||||
if (fs.existsSync(prDir)) {
|
if (fs.existsSync(prDir)) {
|
||||||
shell.chmod('-R', 'a+w', prDir);
|
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
||||||
|
(shell as any).chmod('-R', 'a+w', prDir);
|
||||||
shell.rm('-rf', prDir);
|
shell.rm('-rf', prDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "yarn clean-dist",
|
"prebuild": "yarn clean-dist",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"build-watch": "yarn build --watch",
|
"build-watch": "yarn tsc --watch",
|
||||||
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
||||||
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
|
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
|
||||||
"lint": "tslint --project tsconfig.json",
|
"lint": "tslint --project tsconfig.json",
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"@types/jasmine": "^2.6.0",
|
"@types/jasmine": "^2.6.0",
|
||||||
"@types/jsonwebtoken": "^7.2.3",
|
"@types/jsonwebtoken": "^7.2.3",
|
||||||
"@types/node": "^8.0.30",
|
"@types/node": "^8.0.30",
|
||||||
"@types/shelljs": "^0.8.0",
|
"@types/shelljs": "^0.7.4",
|
||||||
"@types/supertest": "^2.0.3",
|
"@types/supertest": "^2.0.3",
|
||||||
"concurrently": "^3.5.0",
|
"concurrently": "^3.5.0",
|
||||||
"nodemon": "^1.12.1",
|
"nodemon": "^1.12.1",
|
||||||
|
@ -69,9 +69,9 @@
|
|||||||
"@types/express-serve-static-core" "*"
|
"@types/express-serve-static-core" "*"
|
||||||
"@types/mime" "*"
|
"@types/mime" "*"
|
||||||
|
|
||||||
"@types/shelljs@^0.8.0":
|
"@types/shelljs@^0.7.4":
|
||||||
version "0.8.0"
|
version "0.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.0.tgz#0caa56b68baae4f68f44e0dd666ab30b098e3632"
|
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.4.tgz#137b5f31306eaff4de120ffe5b9d74b297809cfc"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/glob" "*"
|
"@types/glob" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
2
aio/content/examples/.gitignore
vendored
2
aio/content/examples/.gitignore
vendored
@ -60,8 +60,6 @@ dist/
|
|||||||
!rollup-config.js
|
!rollup-config.js
|
||||||
aot-compiler/**/*.d.ts
|
aot-compiler/**/*.d.ts
|
||||||
aot-compiler/**/*.factory.d.ts
|
aot-compiler/**/*.factory.d.ts
|
||||||
upgrade-phonecat-2-hybrid/aot/**/*
|
|
||||||
!upgrade-phonecat-2-hybrid/aot/index.html
|
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
!i18n/src/systemjs-text-plugin.js
|
!i18n/src/systemjs-text-plugin.js
|
||||||
|
@ -40,7 +40,5 @@ export class HighlightDirective {
|
|||||||
// #docregion color-2
|
// #docregion color-2
|
||||||
@Input() appHighlight: string;
|
@Input() appHighlight: string;
|
||||||
// #enddocregion color-2
|
// #enddocregion color-2
|
||||||
|
|
||||||
// #docregion
|
|
||||||
}
|
}
|
||||||
// #enddocregion
|
|
||||||
|
@ -16,7 +16,6 @@ describe('Form Validation Tests', function () {
|
|||||||
|
|
||||||
tests('Template-Driven Form');
|
tests('Template-Driven Form');
|
||||||
bobTests();
|
bobTests();
|
||||||
crossValidationTests();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Reactive form', () => {
|
describe('Reactive form', () => {
|
||||||
@ -26,7 +25,6 @@ describe('Form Validation Tests', function () {
|
|||||||
|
|
||||||
tests('Reactive Form');
|
tests('Reactive Form');
|
||||||
bobTests();
|
bobTests();
|
||||||
crossValidationTests();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -44,8 +42,7 @@ let page: {
|
|||||||
powerOption: ElementFinder,
|
powerOption: ElementFinder,
|
||||||
errorMessages: ElementArrayFinder,
|
errorMessages: ElementArrayFinder,
|
||||||
heroFormButtons: ElementArrayFinder,
|
heroFormButtons: ElementArrayFinder,
|
||||||
heroSubmitted: ElementFinder,
|
heroSubmitted: ElementFinder
|
||||||
crossValidationErrorMessage: ElementFinder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function getPage(sectionTag: string) {
|
function getPage(sectionTag: string) {
|
||||||
@ -62,8 +59,7 @@ function getPage(sectionTag: string) {
|
|||||||
powerOption: section.element(by.css('#power option')),
|
powerOption: section.element(by.css('#power option')),
|
||||||
errorMessages: section.all(by.css('div.alert')),
|
errorMessages: section.all(by.css('div.alert')),
|
||||||
heroFormButtons: buttons,
|
heroFormButtons: buttons,
|
||||||
heroSubmitted: section.element(by.css('.submitted-message')),
|
heroSubmitted: section.element(by.css('.submitted-message'))
|
||||||
crossValidationErrorMessage: section.element(by.css('.cross-validation-error-message')),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,29 +172,3 @@ function bobTests() {
|
|||||||
expectFormIsValid();
|
expectFormIsValid();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function crossValidationTests() {
|
|
||||||
const emsg = 'Name cannot match alter ego.';
|
|
||||||
|
|
||||||
it(`should produce "${emsg}" error after setting name and alter ego to the same value`, function () {
|
|
||||||
page.nameInput.clear();
|
|
||||||
page.nameInput.sendKeys('Batman');
|
|
||||||
|
|
||||||
page.alterEgoInput.clear();
|
|
||||||
page.alterEgoInput.sendKeys('Batman');
|
|
||||||
|
|
||||||
expectFormIsInvalid();
|
|
||||||
expect(page.crossValidationErrorMessage.getText()).toBe(emsg);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be ok again with different values', function () {
|
|
||||||
page.nameInput.clear();
|
|
||||||
page.nameInput.sendKeys('Batman');
|
|
||||||
|
|
||||||
page.alterEgoInput.clear();
|
|
||||||
page.alterEgoInput.sendKeys('Superman');
|
|
||||||
|
|
||||||
expectFormIsValid();
|
|
||||||
expect(page.crossValidationErrorMessage.isPresent()).toBe(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@ import { AppComponent } from './app.component';
|
|||||||
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
||||||
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
||||||
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
||||||
import { IdentityRevealedValidatorDirective } from './shared/identity-revealed.directive';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -19,8 +19,7 @@ import { IdentityRevealedValidatorDirective } from './shared/identity-revealed.d
|
|||||||
AppComponent,
|
AppComponent,
|
||||||
HeroFormTemplateComponent,
|
HeroFormTemplateComponent,
|
||||||
HeroFormReactiveComponent,
|
HeroFormReactiveComponent,
|
||||||
ForbiddenValidatorDirective,
|
ForbiddenValidatorDirective
|
||||||
IdentityRevealedValidatorDirective
|
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ]
|
bootstrap: [ AppComponent ]
|
||||||
})
|
})
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
/* tslint:disable: member-ordering forin */
|
|
||||||
// #docplaster
|
|
||||||
// #docregion
|
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
|
||||||
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-hero-form-reactive',
|
|
||||||
templateUrl: './hero-form-reactive.component.html',
|
|
||||||
styleUrls: ['./hero-form-reactive.component.css'],
|
|
||||||
})
|
|
||||||
export class HeroFormReactiveComponent implements OnInit {
|
|
||||||
|
|
||||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
|
||||||
|
|
||||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
|
||||||
|
|
||||||
heroForm: FormGroup;
|
|
||||||
|
|
||||||
// #docregion form-group
|
|
||||||
ngOnInit(): void {
|
|
||||||
// #docregion custom-validator
|
|
||||||
this.heroForm = new FormGroup({
|
|
||||||
'name': new FormControl(this.hero.name, [
|
|
||||||
Validators.required,
|
|
||||||
Validators.minLength(4),
|
|
||||||
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
|
|
||||||
]),
|
|
||||||
'alterEgo': new FormControl(this.hero.alterEgo),
|
|
||||||
'power': new FormControl(this.hero.power, Validators.required)
|
|
||||||
});
|
|
||||||
// #enddocregion custom-validator
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() { return this.heroForm.get('name'); }
|
|
||||||
|
|
||||||
get power() { return this.heroForm.get('power'); }
|
|
||||||
// #enddocregion form-group
|
|
||||||
}
|
|
||||||
// #enddocregion
|
|
@ -1,5 +0,0 @@
|
|||||||
/* #docregion cross-validation-error-css */
|
|
||||||
.cross-validation-error input {
|
|
||||||
border-left: 5px solid red;
|
|
||||||
}
|
|
||||||
/* #enddocregion cross-validation-error-css */
|
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
<div [hidden]="formDir.submitted">
|
<div [hidden]="formDir.submitted">
|
||||||
|
|
||||||
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
@ -37,13 +36,6 @@
|
|||||||
formControlName="alterEgo" >
|
formControlName="alterEgo" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- #docregion cross-validation-error-message -->
|
|
||||||
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
|
|
||||||
Name cannot match alter ego.
|
|
||||||
</div>
|
|
||||||
<!-- #enddocregion cross-validation-error-message -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select id="power" class="form-control"
|
<select id="power" class="form-control"
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
/* tslint:disable: member-ordering forin */
|
/* tslint:disable: member-ordering forin */
|
||||||
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
||||||
import { identityRevealedValidator } from '../shared/identity-revealed.directive';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-form-reactive',
|
selector: 'app-hero-form-reactive',
|
||||||
templateUrl: './hero-form-reactive.component.html',
|
templateUrl: './hero-form-reactive.component.html'
|
||||||
styleUrls: ['./hero-form-reactive.component.css'],
|
|
||||||
})
|
})
|
||||||
export class HeroFormReactiveComponent implements OnInit {
|
export class HeroFormReactiveComponent implements OnInit {
|
||||||
|
|
||||||
@ -18,19 +17,24 @@ export class HeroFormReactiveComponent implements OnInit {
|
|||||||
|
|
||||||
heroForm: FormGroup;
|
heroForm: FormGroup;
|
||||||
|
|
||||||
|
// #docregion form-group
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
// #docregion custom-validator
|
||||||
this.heroForm = new FormGroup({
|
this.heroForm = new FormGroup({
|
||||||
'name': new FormControl(this.hero.name, [
|
'name': new FormControl(this.hero.name, [
|
||||||
Validators.required,
|
Validators.required,
|
||||||
Validators.minLength(4),
|
Validators.minLength(4),
|
||||||
forbiddenNameValidator(/bob/i)
|
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
|
||||||
]),
|
]),
|
||||||
'alterEgo': new FormControl(this.hero.alterEgo),
|
'alterEgo': new FormControl(this.hero.alterEgo),
|
||||||
'power': new FormControl(this.hero.power, Validators.required)
|
'power': new FormControl(this.hero.power, Validators.required)
|
||||||
}, { validators: identityRevealedValidator }); // <-- add custom validator at the FormGroup level
|
});
|
||||||
|
// #enddocregion custom-validator
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() { return this.heroForm.get('name'); }
|
get name() { return this.heroForm.get('name'); }
|
||||||
|
|
||||||
get power() { return this.heroForm.get('power'); }
|
get power() { return this.heroForm.get('power'); }
|
||||||
|
// #enddocregion form-group
|
||||||
}
|
}
|
||||||
|
// #enddocregion
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { Directive } from '@angular/core';
|
|
||||||
import { AbstractControl, FormGroup, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from '@angular/forms';
|
|
||||||
|
|
||||||
// #docregion cross-validation-validator
|
|
||||||
/** A hero's name can't match the hero's alter ego */
|
|
||||||
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
|
|
||||||
const name = control.get('name');
|
|
||||||
const alterEgo = control.get('alterEgo');
|
|
||||||
|
|
||||||
return name && alterEgo && name.value === alterEgo.value ? { 'identityRevealed': true } : null;
|
|
||||||
};
|
|
||||||
// #enddocregion cross-validation-validator
|
|
||||||
|
|
||||||
// #docregion cross-validation-directive
|
|
||||||
@Directive({
|
|
||||||
selector: '[appIdentityRevealed]',
|
|
||||||
providers: [{ provide: NG_VALIDATORS, useExisting: IdentityRevealedValidatorDirective, multi: true }]
|
|
||||||
})
|
|
||||||
export class IdentityRevealedValidatorDirective implements Validator {
|
|
||||||
validate(control: AbstractControl): ValidationErrors {
|
|
||||||
return identityRevealedValidator(control)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #enddocregion cross-validation-directive
|
|
@ -1,4 +0,0 @@
|
|||||||
/* #docregion */
|
|
||||||
.cross-validation-error input {
|
|
||||||
border-left: 5px solid red;
|
|
||||||
}
|
|
@ -2,11 +2,11 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<h1>Template-Driven Form</h1>
|
<h1>Template-Driven Form</h1>
|
||||||
<!-- #docregion cross-validation-register-validator -->
|
<!-- #docregion form-tag-->
|
||||||
<form #heroForm="ngForm" appIdentityRevealed>
|
<form #heroForm="ngForm">
|
||||||
<!-- #enddocregion cross-validation-register-validator -->
|
<!-- #enddocregion form-tag-->
|
||||||
<div [hidden]="heroForm.submitted">
|
<div [hidden]="heroForm.submitted">
|
||||||
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<!-- #docregion name-with-error-msg -->
|
<!-- #docregion name-with-error-msg -->
|
||||||
@ -39,13 +39,6 @@
|
|||||||
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- #docregion cross-validation-error-message -->
|
|
||||||
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
|
|
||||||
Name cannot match alter ego.
|
|
||||||
</div>
|
|
||||||
<!-- #enddocregion cross-validation-error-message -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select id="power" name="power" class="form-control"
|
<select id="power" name="power" class="form-control"
|
||||||
@ -69,4 +62,5 @@
|
|||||||
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
// #docregion component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-form-template',
|
selector: 'app-hero-form-template',
|
||||||
templateUrl: './hero-form-template.component.html',
|
templateUrl: './hero-form-template.component.html'
|
||||||
styleUrls: ['./hero-form-template.component.css'],
|
|
||||||
})
|
})
|
||||||
export class HeroFormTemplateComponent {
|
export class HeroFormTemplateComponent {
|
||||||
|
|
||||||
@ -16,4 +14,3 @@ export class HeroFormTemplateComponent {
|
|||||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||||
|
|
||||||
}
|
}
|
||||||
// #enddocregion
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
"description": "Validation",
|
"description": "Validation",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js",
|
"!**/*.js"
|
||||||
"!**/*.[1].*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,7 @@ button {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
code,
|
code, .code {
|
||||||
.code {
|
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
color: black;
|
color: black;
|
||||||
font-family: Courier, sans-serif;
|
font-family: Courier, sans-serif;
|
||||||
@ -22,18 +21,14 @@ div.code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
margin: 40px 0;
|
margin: 40px 0
|
||||||
}
|
}
|
||||||
|
|
||||||
td,
|
td, th {
|
||||||
th {
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #docregion p-span */
|
/* #docregion p-span */
|
||||||
p span {
|
p span { color: red; font-size: 70%; }
|
||||||
color: red;
|
|
||||||
font-size: 70%;
|
|
||||||
}
|
|
||||||
/* #enddocregion p-span */
|
/* #enddocregion p-span */
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
<!-- #docregion select-span -->
|
<!-- #docregion select-span -->
|
||||||
<select [(ngModel)]="hero">
|
<select [(ngModel)]="hero">
|
||||||
<span *ngFor="let h of heroes">
|
<span *ngFor="let h of heroes">
|
||||||
<span *ngIf="showSad || h?.emotion !== 'sad'">
|
<span *ngIf="showSad || h?.emotion != 'sad'">
|
||||||
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -147,7 +147,7 @@
|
|||||||
<!-- #docregion select-ngcontainer -->
|
<!-- #docregion select-ngcontainer -->
|
||||||
<select [(ngModel)]="hero">
|
<select [(ngModel)]="hero">
|
||||||
<ng-container *ngFor="let h of heroes">
|
<ng-container *ngFor="let h of heroes">
|
||||||
<ng-container *ngIf="showSad || h?.emotion !== 'sad'">
|
<ng-container *ngIf="showSad || h?.emotion != 'sad'">
|
||||||
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -14,7 +14,6 @@ export class AppComponent {
|
|||||||
heroTraits = [ 'honest', 'brave', 'considerate' ];
|
heroTraits = [ 'honest', 'brave', 'considerate' ];
|
||||||
|
|
||||||
// flags for the table
|
// flags for the table
|
||||||
|
|
||||||
attrDirs = true;
|
attrDirs = true;
|
||||||
strucDirs = true;
|
strucDirs = true;
|
||||||
divNgIf = false;
|
divNgIf = false;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -34,15 +33,11 @@ export class ConfusedHeroComponent {
|
|||||||
export class UnknownHeroComponent {
|
export class UnknownHeroComponent {
|
||||||
@Input() hero: Hero;
|
@Input() hero: Hero;
|
||||||
get message() {
|
get message() {
|
||||||
return this.hero && this.hero.name
|
return this.hero && this.hero.name ?
|
||||||
? `${this.hero.name} is strange and mysterious.`
|
`${this.hero.name} is strange and mysterious.` :
|
||||||
: 'Are you feeling indecisive?';
|
'Are you feeling indecisive?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const heroComponents = [
|
export const heroComponents =
|
||||||
HappyHeroComponent,
|
[ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ];
|
||||||
SadHeroComponent,
|
|
||||||
ConfusedHeroComponent,
|
|
||||||
UnknownHeroComponent
|
|
||||||
];
|
|
||||||
|
@ -15,7 +15,6 @@ export class ComposeMessageComponent {
|
|||||||
@HostBinding('style.position') position = 'absolute';
|
@HostBinding('style.position') position = 'absolute';
|
||||||
|
|
||||||
details: string;
|
details: string;
|
||||||
message: string;
|
|
||||||
sending = false;
|
sending = false;
|
||||||
|
|
||||||
constructor(private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
@ -18,11 +18,11 @@ nav a {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
nav a:visited, a:link {
|
nav a:visited, a:link {
|
||||||
color: #607d8b;
|
color: #607D8B;
|
||||||
}
|
}
|
||||||
nav a:hover {
|
nav a:hover {
|
||||||
color: #039be5;
|
color: #039be5;
|
||||||
background-color: #cfd8dc;
|
background-color: #CFD8DC;
|
||||||
}
|
}
|
||||||
nav a.active {
|
nav a.active {
|
||||||
color: #039be5;
|
color: #039be5;
|
||||||
|
@ -33,11 +33,11 @@ h4 {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
max-height: 120px;
|
max-height: 120px;
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
background-color: #607d8b;
|
background-color: #607D8B;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
.module:hover {
|
.module:hover {
|
||||||
background-color: #eee;
|
background-color: #EEE;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #607d8b;
|
color: #607d8b;
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,16 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { DashboardComponent } from './dashboard.component';
|
import { DashboardComponent } from './dashboard.component';
|
||||||
import { HeroSearchComponent } from '../hero-search/hero-search.component';
|
|
||||||
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { HEROES } from '../mock-heroes';
|
|
||||||
import { HeroService } from '../hero.service';
|
|
||||||
|
|
||||||
describe('DashboardComponent', () => {
|
describe('DashboardComponent', () => {
|
||||||
let component: DashboardComponent;
|
let component: DashboardComponent;
|
||||||
let fixture: ComponentFixture<DashboardComponent>;
|
let fixture: ComponentFixture<DashboardComponent>;
|
||||||
let heroService;
|
|
||||||
let getHeroesSpy;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
|
||||||
getHeroesSpy = heroService.getHeroes.and.returnValue( of(HEROES) );
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [ DashboardComponent ]
|
||||||
DashboardComponent,
|
|
||||||
HeroSearchComponent
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
RouterTestingModule.withRoutes([])
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: HeroService, useValue: heroService }
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -42,17 +22,4 @@ describe('DashboardComponent', () => {
|
|||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display "Top Heroes" as headline', () => {
|
|
||||||
expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Top Heroes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call heroService', async(() => {
|
|
||||||
expect(getHeroesSpy.calls.any()).toBe(true);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should display 4 links', async(() => {
|
|
||||||
expect(fixture.nativeElement.querySelectorAll('a').length).toEqual(4);
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
import { HeroSearchComponent } from './hero-search.component';
|
import { HeroSearchComponent } from './hero-search.component';
|
||||||
|
|
||||||
|
|
||||||
describe('HeroSearchComponent', () => {
|
describe('HeroSearchComponent', () => {
|
||||||
let component: HeroSearchComponent;
|
let component: HeroSearchComponent;
|
||||||
let fixture: ComponentFixture<HeroSearchComponent>;
|
let fixture: ComponentFixture<HeroSearchComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ HeroSearchComponent ],
|
declarations: [ HeroSearchComponent ]
|
||||||
imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule]
|
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -40,7 +40,7 @@ export class HeroService {
|
|||||||
// #enddocregion getHeroes-1
|
// #enddocregion getHeroes-1
|
||||||
.pipe(
|
.pipe(
|
||||||
// #enddocregion getHeroes-2
|
// #enddocregion getHeroes-2
|
||||||
tap(heroes => this.log('fetched heroes')),
|
tap(heroes => this.log(`fetched heroes`)),
|
||||||
// #docregion getHeroes-2
|
// #docregion getHeroes-2
|
||||||
catchError(this.handleError('getHeroes', []))
|
catchError(this.handleError('getHeroes', []))
|
||||||
);
|
);
|
||||||
@ -151,7 +151,7 @@ export class HeroService {
|
|||||||
// #docregion log
|
// #docregion log
|
||||||
/** Log a HeroService message with the MessageService */
|
/** Log a HeroService message with the MessageService */
|
||||||
private log(message: string) {
|
private log(message: string) {
|
||||||
this.messageService.add(`HeroService: ${message}`);
|
this.messageService.add('HeroService: ' + message);
|
||||||
}
|
}
|
||||||
// #enddocregion log
|
// #enddocregion log
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { HeroesComponent } from './heroes.component';
|
import { HeroesComponent } from './heroes.component';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
|
|
||||||
describe('HeroesComponent', () => {
|
describe('HeroesComponent', () => {
|
||||||
let component: HeroesComponent;
|
let component: HeroesComponent;
|
||||||
@ -9,8 +8,7 @@ describe('HeroesComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ HeroesComponent ],
|
declarations: [ HeroesComponent ]
|
||||||
imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule],
|
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -30,7 +30,7 @@ export class HeroService {
|
|||||||
getHeroes (): Observable<Hero[]> {
|
getHeroes (): Observable<Hero[]> {
|
||||||
return this.http.get<Hero[]>(this.heroesUrl)
|
return this.http.get<Hero[]>(this.heroesUrl)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(heroes => this.log('fetched heroes')),
|
tap(heroes => this.log(`fetched heroes`)),
|
||||||
catchError(this.handleError('getHeroes', []))
|
catchError(this.handleError('getHeroes', []))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -123,6 +123,6 @@ export class HeroService {
|
|||||||
|
|
||||||
/** Log a HeroService message with the MessageService */
|
/** Log a HeroService message with the MessageService */
|
||||||
private log(message: string) {
|
private log(message: string) {
|
||||||
this.messageService.add(`HeroService: ${message}`);
|
this.messageService.add('HeroService: ' + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"skipLibCheck": true,
|
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"suppressImplicitAnyIndexErrors": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"skipLibCheck": true,
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"typeRoots": [
|
||||||
|
"./node_modules/@types/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { platformBrowser } from '@angular/platform-browser';
|
import { platformBrowser } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppModuleNgFactory } from './app.module.ngfactory';
|
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
||||||
|
|
||||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ function xyzPhoneData(): PhoneData {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
get(id: string): Observable<PhoneData> {
|
get(id: string): Observable<PhoneData> {
|
||||||
return of(xyzPhoneData());
|
return Observable.of(xyzPhoneData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { SpyLocation } from '@angular/common/testing';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ class ActivatedRouteMock {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return of([
|
return Observable.of([
|
||||||
{name: 'Nexus S', snippet: '', images: []},
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
{name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
|
@ -9,8 +9,10 @@
|
|||||||
"lib": ["es2015", "dom"],
|
"lib": ["es2015", "dom"],
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"skipLibCheck": true,
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"typeRoots": [
|
||||||
|
"./node_modules/@types/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
@ -19,6 +21,7 @@
|
|||||||
],
|
],
|
||||||
|
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
|
"genDir": "aot",
|
||||||
"skipMetadataEmit" : true
|
"skipMetadataEmit" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"skipLibCheck": true,
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"typeRoots": [
|
||||||
|
"./node_modules/@types/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ function xyzPhoneData(): PhoneData {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
get(id: string): Observable<PhoneData> {
|
get(id: string): Observable<PhoneData> {
|
||||||
return of(xyzPhoneData());
|
return Observable.of(xyzPhoneData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion routestuff
|
// #docregion routestuff
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { SpyLocation } from '@angular/common/testing';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ class ActivatedRouteMock {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return of([
|
return Observable.of([
|
||||||
{name: 'Nexus S', snippet: '', images: []},
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
{name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"skipLibCheck": true,
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"typeRoots": [
|
||||||
|
"./node_modules/@types/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
12
aio/content/examples/webpack/config/helpers.js
Normal file
12
aio/content/examples/webpack/config/helpers.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// #docregion
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var _root = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
|
function root(args) {
|
||||||
|
args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
return path.join.apply(path, [_root].concat(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.root = root;
|
||||||
|
// #enddocregion
|
17
aio/content/examples/webpack/config/karma-test-shim.js
Normal file
17
aio/content/examples/webpack/config/karma-test-shim.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// #docregion
|
||||||
|
Error.stackTraceLimit = Infinity;
|
||||||
|
|
||||||
|
require('core-js/es6');
|
||||||
|
require('core-js/es7/reflect');
|
||||||
|
|
||||||
|
require('zone.js/dist/zone');
|
||||||
|
require('zone.js/dist/zone-testing');
|
||||||
|
|
||||||
|
var appContext = require.context('../src', true, /\.spec\.ts/);
|
||||||
|
|
||||||
|
appContext.keys().forEach(appContext);
|
||||||
|
|
||||||
|
var testing = require('@angular/core/testing');
|
||||||
|
var browser = require('@angular/platform-browser-dynamic/testing');
|
||||||
|
|
||||||
|
testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
|
39
aio/content/examples/webpack/config/karma.conf.js
Normal file
39
aio/content/examples/webpack/config/karma.conf.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// #docregion
|
||||||
|
var webpackConfig = require('./webpack.test');
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
var _config = {
|
||||||
|
basePath: '',
|
||||||
|
|
||||||
|
frameworks: ['jasmine'],
|
||||||
|
|
||||||
|
files: [
|
||||||
|
{pattern: './config/karma-test-shim.js', watched: false}
|
||||||
|
],
|
||||||
|
|
||||||
|
preprocessors: {
|
||||||
|
'./config/karma-test-shim.js': ['webpack', 'sourcemap']
|
||||||
|
},
|
||||||
|
|
||||||
|
webpack: webpackConfig,
|
||||||
|
|
||||||
|
webpackMiddleware: {
|
||||||
|
stats: 'errors-only'
|
||||||
|
},
|
||||||
|
|
||||||
|
webpackServer: {
|
||||||
|
noInfo: true
|
||||||
|
},
|
||||||
|
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: false,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: true
|
||||||
|
};
|
||||||
|
|
||||||
|
config.set(_config);
|
||||||
|
};
|
||||||
|
// #enddocregion
|
81
aio/content/examples/webpack/config/webpack.common.js
Normal file
81
aio/content/examples/webpack/config/webpack.common.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
|
var webpack = require('webpack');
|
||||||
|
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
var helpers = require('./helpers');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// #docregion entries, one-entry, two-entries
|
||||||
|
entry: {
|
||||||
|
// #enddocregion one-entry, two-entries
|
||||||
|
'polyfills': './src/polyfills.ts',
|
||||||
|
// #docregion two-entries
|
||||||
|
'vendor': './src/vendor.ts',
|
||||||
|
// #docregion one-entry
|
||||||
|
'app': './src/main.ts'
|
||||||
|
},
|
||||||
|
// #enddocregion entries, one-entry, two-entries
|
||||||
|
|
||||||
|
// #docregion resolve
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js']
|
||||||
|
},
|
||||||
|
// #enddocregion resolve
|
||||||
|
|
||||||
|
// #docregion loaders
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
loader: 'awesome-typescript-loader',
|
||||||
|
options: { configFileName: helpers.root('src', 'tsconfig.json') }
|
||||||
|
} , 'angular2-template-loader'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
loader: 'html-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
||||||
|
loader: 'file-loader?name=assets/[name].[hash].[ext]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: helpers.root('src', 'app'),
|
||||||
|
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
include: helpers.root('src', 'app'),
|
||||||
|
loader: 'raw-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// #enddocregion loaders
|
||||||
|
|
||||||
|
// #docregion plugins
|
||||||
|
plugins: [
|
||||||
|
// Workaround for angular/angular#11580
|
||||||
|
new webpack.ContextReplacementPlugin(
|
||||||
|
// The (\\|\/) piece accounts for path separators in *nix and Windows
|
||||||
|
/angular(\\|\/)core(\\|\/)@angular/,
|
||||||
|
helpers.root('./src'), // location of your src
|
||||||
|
{} // a map of your routes
|
||||||
|
),
|
||||||
|
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: ['app', 'vendor', 'polyfills']
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'src/index.html'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
// #enddocregion plugins
|
||||||
|
};
|
||||||
|
// #enddocregion
|
||||||
|
|
26
aio/content/examples/webpack/config/webpack.dev.js
Normal file
26
aio/content/examples/webpack/config/webpack.dev.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// #docregion
|
||||||
|
var webpackMerge = require('webpack-merge');
|
||||||
|
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
var commonConfig = require('./webpack.common.js');
|
||||||
|
var helpers = require('./helpers');
|
||||||
|
|
||||||
|
module.exports = webpackMerge(commonConfig, {
|
||||||
|
devtool: 'cheap-module-eval-source-map',
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: helpers.root('dist'),
|
||||||
|
publicPath: '/',
|
||||||
|
filename: '[name].js',
|
||||||
|
chunkFilename: '[id].chunk.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new ExtractTextPlugin('[name].css')
|
||||||
|
],
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
historyApiFallback: true,
|
||||||
|
stats: 'minimal'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #enddocregion
|
41
aio/content/examples/webpack/config/webpack.prod.js
Normal file
41
aio/content/examples/webpack/config/webpack.prod.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// #docregion
|
||||||
|
var webpack = require('webpack');
|
||||||
|
var webpackMerge = require('webpack-merge');
|
||||||
|
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
var commonConfig = require('./webpack.common.js');
|
||||||
|
var helpers = require('./helpers');
|
||||||
|
|
||||||
|
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
|
||||||
|
|
||||||
|
module.exports = webpackMerge(commonConfig, {
|
||||||
|
devtool: 'source-map',
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: helpers.root('dist'),
|
||||||
|
publicPath: '/',
|
||||||
|
filename: '[name].[hash].js',
|
||||||
|
chunkFilename: '[id].[hash].chunk.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
|
||||||
|
mangle: {
|
||||||
|
keep_fnames: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new ExtractTextPlugin('[name].[hash].css'),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
'ENV': JSON.stringify(ENV)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
htmlLoader: {
|
||||||
|
minimize: false // workaround for ng2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// #enddocregion
|
55
aio/content/examples/webpack/config/webpack.test.js
Normal file
55
aio/content/examples/webpack/config/webpack.test.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// #docregion
|
||||||
|
var webpack = require('webpack');
|
||||||
|
var helpers = require('./helpers');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js']
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
loader: 'awesome-typescript-loader',
|
||||||
|
options: { configFileName: helpers.root('src', 'tsconfig.json') }
|
||||||
|
} , 'angular2-template-loader'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
loader: 'html-loader'
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
||||||
|
loader: 'null-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: helpers.root('src', 'app'),
|
||||||
|
loader: 'null-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
include: helpers.root('src', 'app'),
|
||||||
|
loader: 'raw-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.ContextReplacementPlugin(
|
||||||
|
// The (\\|\/) piece accounts for path separators in *nix and Windows
|
||||||
|
/angular(\\|\/)core(\\|\/)@angular/,
|
||||||
|
helpers.root('./src'), // location of your src
|
||||||
|
{} // a map of your routes
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// #enddocregion
|
21
aio/content/examples/webpack/e2e-spec.ts
Normal file
21
aio/content/examples/webpack/e2e-spec.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use strict'; // necessary for es6 output in node
|
||||||
|
|
||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
|
describe('QuickStart E2E Tests', function () {
|
||||||
|
|
||||||
|
let expectedMsg = 'Hello from Angular App with Webpack';
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
browser.get('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should display: ${expectedMsg}`, function () {
|
||||||
|
expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an image', function () {
|
||||||
|
expect(element(by.css('img')).isPresent()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
5
aio/content/examples/webpack/example-config.json
Normal file
5
aio/content/examples/webpack/example-config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"build": "build:webpack",
|
||||||
|
"run": "serve:cli",
|
||||||
|
"projectType": "systemjs"
|
||||||
|
}
|
2
aio/content/examples/webpack/karma.webpack.conf.js
Normal file
2
aio/content/examples/webpack/karma.webpack.conf.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// #docregion
|
||||||
|
module.exports = require('./config/karma.conf.js');
|
49
aio/content/examples/webpack/package.webpack.json
Normal file
49
aio/content/examples/webpack/package.webpack.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "angular2-webpack",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A webpack starter for Angular",
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server --inline --progress --port 8080",
|
||||||
|
"test": "karma start",
|
||||||
|
"build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/common": "~4.2.0",
|
||||||
|
"@angular/compiler": "~4.2.0",
|
||||||
|
"@angular/core": "~4.2.0",
|
||||||
|
"@angular/forms": "~4.2.0",
|
||||||
|
"@angular/http": "~4.2.0",
|
||||||
|
"@angular/platform-browser": "~4.2.0",
|
||||||
|
"@angular/platform-browser-dynamic": "~4.2.0",
|
||||||
|
"@angular/router": "~4.2.0",
|
||||||
|
"core-js": "^2.4.1",
|
||||||
|
"rxjs": "5.0.1",
|
||||||
|
"zone.js": "^0.8.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^6.0.45",
|
||||||
|
"@types/jasmine": "2.5.36",
|
||||||
|
"angular2-template-loader": "^0.6.0",
|
||||||
|
"awesome-typescript-loader": "^3.0.4",
|
||||||
|
"css-loader": "^0.26.1",
|
||||||
|
"extract-text-webpack-plugin": "2.0.0-beta.5",
|
||||||
|
"file-loader": "^0.9.0",
|
||||||
|
"html-loader": "^0.4.3",
|
||||||
|
"html-webpack-plugin": "^2.16.1",
|
||||||
|
"jasmine-core": "^2.4.1",
|
||||||
|
"karma": "^1.2.0",
|
||||||
|
"karma-chrome-launcher": "^2.0.0",
|
||||||
|
"karma-jasmine": "^1.0.2",
|
||||||
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
|
"karma-webpack": "^2.0.1",
|
||||||
|
"null-loader": "^0.1.1",
|
||||||
|
"raw-loader": "^0.5.1",
|
||||||
|
"rimraf": "^2.5.2",
|
||||||
|
"style-loader": "^0.13.1",
|
||||||
|
"typescript": "~2.3.1",
|
||||||
|
"webpack": "2.2.1",
|
||||||
|
"webpack-dev-server": "2.4.1",
|
||||||
|
"webpack-merge": "^3.0.0"
|
||||||
|
}
|
||||||
|
}
|
9
aio/content/examples/webpack/src/app/app.component.css
Normal file
9
aio/content/examples/webpack/src/app/app.component.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* #docregion */
|
||||||
|
main {
|
||||||
|
padding: 1em;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 50px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* #enddocregion */
|
7
aio/content/examples/webpack/src/app/app.component.html
Normal file
7
aio/content/examples/webpack/src/app/app.component.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!-- #docregion -->
|
||||||
|
<main>
|
||||||
|
<h1>Hello from Angular App with Webpack</h1>
|
||||||
|
|
||||||
|
<img src="../assets/images/angular.png">
|
||||||
|
</main>
|
||||||
|
<!-- #enddocregion -->
|
16
aio/content/examples/webpack/src/app/app.component.spec.ts
Normal file
16
aio/content/examples/webpack/src/app/app.component.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// #docregion
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('App', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({ declarations: [AppComponent]});
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('should work', () => {
|
||||||
|
let fixture = TestBed.createComponent(AppComponent);
|
||||||
|
expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// #enddocregion
|
16
aio/content/examples/webpack/src/app/app.component.ts
Normal file
16
aio/content/examples/webpack/src/app/app.component.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
|
// #docregion component
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
// #enddocregion component
|
||||||
|
import '../assets/css/styles.css';
|
||||||
|
|
||||||
|
// #docregion component
|
||||||
|
@Component({
|
||||||
|
selector: 'my-app',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent { }
|
||||||
|
// #enddocregion
|
16
aio/content/examples/webpack/src/app/app.module.ts
Normal file
16
aio/content/examples/webpack/src/app/app.module.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// #docregion
|
||||||
|
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 { }
|
6
aio/content/examples/webpack/src/assets/css/styles.css
Normal file
6
aio/content/examples/webpack/src/assets/css/styles.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* #docregion */
|
||||||
|
body {
|
||||||
|
background: #0147A7;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
/* #enddocregion */
|
BIN
aio/content/examples/webpack/src/assets/images/angular.png
Normal file
BIN
aio/content/examples/webpack/src/assets/images/angular.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
14
aio/content/examples/webpack/src/index.html
Normal file
14
aio/content/examples/webpack/src/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!-- #docregion -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<base href="/">
|
||||||
|
<title>Angular With Webpack</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<my-app>Loading...</my-app>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<!-- #enddocregion -->
|
14
aio/content/examples/webpack/src/main.ts
Normal file
14
aio/content/examples/webpack/src/main.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// #docregion
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
|
||||||
|
// #docregion enable-prod
|
||||||
|
if (process.env.ENV === 'production') {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
// #enddocregion enable-prod
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
|
// #enddocregion
|
12
aio/content/examples/webpack/src/polyfills.ts
Normal file
12
aio/content/examples/webpack/src/polyfills.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// #docregion
|
||||||
|
import 'core-js/es6';
|
||||||
|
import 'core-js/es7/reflect';
|
||||||
|
require('zone.js/dist/zone');
|
||||||
|
|
||||||
|
if (process.env.ENV === 'production') {
|
||||||
|
// Production
|
||||||
|
} else {
|
||||||
|
// Development and test
|
||||||
|
Error['stackTraceLimit'] = Infinity;
|
||||||
|
require('zone.js/dist/long-stack-trace-zone');
|
||||||
|
}
|
13
aio/content/examples/webpack/src/tsconfig.1.json
Normal file
13
aio/content/examples/webpack/src/tsconfig.1.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"sourceMap": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"lib": ["es2015", "dom"],
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"suppressImplicitAnyIndexErrors": true
|
||||||
|
}
|
||||||
|
}
|
18
aio/content/examples/webpack/src/vendor.ts
Normal file
18
aio/content/examples/webpack/src/vendor.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// TODO(i): this no longer works. we need to review this example and if absolutely necessary rewrite it to use the
|
||||||
|
// rxjs-compat package
|
||||||
|
|
||||||
|
// #docregion
|
||||||
|
// Angular
|
||||||
|
import '@angular/platform-browser';
|
||||||
|
import '@angular/platform-browser-dynamic';
|
||||||
|
import '@angular/core';
|
||||||
|
import '@angular/common';
|
||||||
|
import '@angular/http';
|
||||||
|
import '@angular/router';
|
||||||
|
|
||||||
|
// RxJS
|
||||||
|
import 'rxjs';
|
||||||
|
|
||||||
|
// Other vendors for example jQuery, Lodash or Bootstrap
|
||||||
|
// You can import js, ts, css, sass, ...
|
||||||
|
// #enddocregion
|
3
aio/content/examples/webpack/webpack.config.js
Normal file
3
aio/content/examples/webpack/webpack.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// #docregion
|
||||||
|
module.exports = require('./config/webpack.dev.js');
|
||||||
|
// #enddocregion
|
12
aio/content/examples/webpack/zipper.json
Normal file
12
aio/content/examples/webpack/zipper.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"files":[
|
||||||
|
"!**/*.d.ts",
|
||||||
|
"!**/*.js",
|
||||||
|
"!**/*.[0-9].*",
|
||||||
|
"config/**/*",
|
||||||
|
"webpack.config.js",
|
||||||
|
"karma.webpack.conf.js"
|
||||||
|
],
|
||||||
|
"removeSystemJsConfig": true,
|
||||||
|
"type": "webpack"
|
||||||
|
}
|
@ -895,7 +895,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
### lowercase
|
### lowercase
|
||||||
|
|
||||||
<code-example hideCopy>
|
<code-example hideCopy>
|
||||||
<td>{{movie.title | lowercase}}</td>
|
<div>{{movie.title | lowercase}}</div>
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,9 +97,6 @@ You can control your app compilation by providing template compiler options in t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
### *enableResourceInlining*
|
|
||||||
This options tell the compiler to replace the `templateUrl` and `styleUrls` property in all `@Component` decorators with inlined contents in `template` and `styles` properties.
|
|
||||||
When enabled, the `.js` output of ngc will have no lazy-loaded `templateUrl` or `styleUrls`.
|
|
||||||
|
|
||||||
### *skipMetadataEmit*
|
### *skipMetadataEmit*
|
||||||
|
|
||||||
|
175
aio/content/guide/api-page-class.md
Normal file
175
aio/content/guide/api-page-class.md
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
<div class="breadcrumb">
|
||||||
|
<a href="#">API<a> / <a href="#">@core<a>
|
||||||
|
</div>
|
||||||
|
<header class="api-header">
|
||||||
|
<h1><label class="api-status-label experimental">experimental</label><label class="api-type-label class">class</label>Class Name</h1>
|
||||||
|
</header>
|
||||||
|
<div class="page-actions">
|
||||||
|
<a href="#"><label class="raised page-label"><i class="material-icons">mode_edit</i>suggest edits</label></a>
|
||||||
|
<a href="#"><label class="raised page-label"><i class="material-icons">code</i>view source</label></a>
|
||||||
|
</div>
|
||||||
|
<p>Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.</p>
|
||||||
|
<div class="api-body">
|
||||||
|
<section>
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<code-example language="ts" hidecopy="true" ng-version="5.2.0"><aio-code class="simple-code" ng-reflect-ng-class="[object Object]" ng-reflect-code="
|
||||||
|
class <a href="api/core/Compi" ng-reflect-hide-copy="true" ng-reflect-language="ts" ng-reflect-linenums="" ng-reflect-path="" ng-reflect-region="" ng-reflect-title=""><pre class="prettyprint lang-ts">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/core/Compiler" class="code-anchor"><span class="typ">Compiler</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#compileModuleSync"><span class="pln">compileModuleSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAsync"><span class="pln">compileModuleAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsSync"><span class="pln">compileModuleAndAllComponentsSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsAsync"><span class="pln">compileModuleAndAllComponentsAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#clearCache"><span class="pln">clearCache</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span></a><span class="pln">
|
||||||
|
</span><a class="code-anchor" href="api/core/Compiler#clearCacheFor"><span class="pln">clearCacheFor</span><span class="pun">(</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">any</span><span class="pun">>)</span></a><span class="pln">
|
||||||
|
</span><span class="pun">}</span></code>
|
||||||
|
</pre></aio-code></code-example>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Description</h2>
|
||||||
|
<p>The longer class description goes here which can include multiple paragraphs.</p>
|
||||||
|
</p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||||
|
<h3>Subclasses</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#">Subclass1</a></li>
|
||||||
|
<li><a href="#">Subclass2</a></li>
|
||||||
|
<li><a href="#">Subclass3</a></li>
|
||||||
|
</ul>
|
||||||
|
<h3>See Also</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#">Link1</a></li>
|
||||||
|
<li><a href="#">Link2</a></li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Constructor</h2>
|
||||||
|
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||||
|
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||||
|
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||||
|
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||||
|
</pre></aio-code></code-example>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Properties</h2>
|
||||||
|
<table class="is-full-width list-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Property</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code><strong>Property1</strong></code>
|
||||||
|
</td>
|
||||||
|
<td><label class="property-type-label type">Type</label></td>
|
||||||
|
<td>Description goes here</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code><strong>Property2</strong></code>
|
||||||
|
</td>
|
||||||
|
<td>Type</td>
|
||||||
|
<td>Description goes here</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code><strong>Property3</strong></code>
|
||||||
|
</td>
|
||||||
|
<td>Type</td>
|
||||||
|
<td>Description goes here</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
<section class="api-method">
|
||||||
|
<h2>Methods</h2>
|
||||||
|
<table class="is-full-width item-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Method1Name( )</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p>Description goes here</p>
|
||||||
|
<br>
|
||||||
|
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="is-full-width api-method item-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Method2Name( )</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p>Description goes here</p>
|
||||||
|
<hr>
|
||||||
|
<h5>Declaration</h5>
|
||||||
|
<code-example language="ts" hidecopy="true" ng-version="5.2.0">
|
||||||
|
<aio-code class="simple-code"><pre class="prettyprint lang-ts">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/animations/AnimationBuilder" class="code-anchor"><span class="typ">AnimationBuilder</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><a class="code-anchor" href="api/animations/AnimationBuilder#build"><span class="pln">build</span><span class="pun">(</span><span class="pln">animation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pun">[]):</span><span class="pln"> </span><span class="typ">AnimationFactory</span></a><span class="pln"></span><span class="pun">}</span></code></pre>
|
||||||
|
</aio-code>
|
||||||
|
</code-example>
|
||||||
|
<h6>Parameters</h6>
|
||||||
|
<h6>Returns</h6>
|
||||||
|
<p>Returns information and results goes here.</p>
|
||||||
|
<h6>Errors</h6>
|
||||||
|
<p>Error information goes here</p>
|
||||||
|
<hr>
|
||||||
|
<p>Further details provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p><hr>
|
||||||
|
<h6>Overloads</h6>
|
||||||
|
<table class="is-full-width">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||||
|
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||||
|
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||||
|
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||||
|
</pre></aio-code></code-example>
|
||||||
|
</td>
|
||||||
|
<td>Description goes here</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||||
|
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||||
|
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||||
|
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||||
|
</pre></aio-code></code-example>
|
||||||
|
</td>
|
||||||
|
<td>Description goes here</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h5>Example: Descriptive Title of Method Example</h5>
|
||||||
|
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Example: Descriptive Title of Combined Example Goes Here</h2>
|
||||||
|
<p>Intro description text about what the example is and how it can be used.</p>
|
||||||
|
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||||
|
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||||
|
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||||
|
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||||
|
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||||
|
</pre></aio-code></code-example>
|
||||||
|
<p>Further explanation provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
@ -8,10 +8,9 @@ A _component_ controls a patch of screen called a *view*. For example, individua
|
|||||||
* The list of heroes.
|
* The list of heroes.
|
||||||
* The hero editor.
|
* The hero editor.
|
||||||
|
|
||||||
You define a component's application logic—what it does to support the view—inside a class.
|
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
|
||||||
The class interacts with the view through an API of properties and methods.
|
|
||||||
|
|
||||||
For example, the `HeroListComponent` has a `heroes` property that holds an array of heroes. It also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list. The component acquires the heroes from a service, which is a TypeScript [parameter property[(http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor. The service is provided to the component through the dependency injection system.
|
For example, the `HeroListComponent` has a `heroes` property that returns an array of heroes that it acquires from a service. `HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
@ -40,7 +39,8 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
|
|||||||
|
|
||||||
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
|
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
|
||||||
|
|
||||||
* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular that the component's constructor requires a `HeroService` instance
|
||||||
|
in order to get the list of heroes to display.
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
@ -88,8 +88,7 @@ For example, import Angular's `Component` decorator from the `@angular/core` lib
|
|||||||
|
|
||||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||||
|
|
||||||
You also import NgModules from Angular _libraries_ using JavaScript import statements.
|
You also import NgModules from Angular _libraries_ using JavaScript import statements:
|
||||||
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library:
|
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
||||||
|
|
||||||
|
@ -60,29 +60,11 @@ The process of `HeroService` injection looks something like this:
|
|||||||
|
|
||||||
### Providing services
|
### Providing services
|
||||||
|
|
||||||
You must register at least one *provider* of any service you are going to use. A service can register providers itself, making it available everywhere, or you can register providers with specific modules or components. You register providers in the metadata of the service (in the `@Injectable` decorator), or in the `@NgModule` or `@Component` metadata
|
You must register at least one *provider* of any service you are going to use. You can register providers in modules or in components.
|
||||||
|
|
||||||
* By default, the Angular CLI command `ng generate service` registers a provider with the root injector for your service by including provider metadata in the `@Injectable` decorator. The tutorial uses this method to register the provider of HeroService class definition:
|
* When you add providers to the [root module](guide/architecture-modules), the same instance of a service is available to all components in your app.
|
||||||
|
|
||||||
```
|
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers"></code-example>
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects into any class that asks for it. Registering the provider in the `@Injectable` metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.
|
|
||||||
|
|
||||||
* When you register a provider with a [specific NgModule](guide/architecture-modules), the same instance of a service is available to all components in that NgModule. To register at this level, use the `providers` property of the `@NgModule` decorator:
|
|
||||||
|
|
||||||
```
|
|
||||||
@NgModule({
|
|
||||||
providers: [
|
|
||||||
BackendService,
|
|
||||||
Logger
|
|
||||||
],
|
|
||||||
...
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
* When you register a provider at the component level, you get a new instance of the
|
* When you register a provider at the component level, you get a new instance of the
|
||||||
service with each new instance of that component. At the component level, register a service provider in the `providers` property of the `@Component` metadata:
|
service with each new instance of that component. At the component level, register a service provider in the `providers` property of the `@Component` metadata:
|
||||||
|
@ -164,7 +164,7 @@ They are _not inherited_ by any components nested within the template nor by any
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
The CLI defines an empty `styles` array when you create the component with the `--inline-style` flag.
|
The CLI defines an empty `styles` array when you create the component with the `--inline-styles` flag.
|
||||||
|
|
||||||
<code-example language="sh" class="code-shell">
|
<code-example language="sh" class="code-shell">
|
||||||
ng generate component hero-app --inline-style
|
ng generate component hero-app --inline-style
|
||||||
@ -189,7 +189,7 @@ They are _not inherited_ by any components nested within the template nor by any
|
|||||||
|
|
||||||
<div class="l-sub-section">
|
<div class="l-sub-section">
|
||||||
|
|
||||||
You can specify more than one styles file or even a combination of `styles` and `styleUrls`.
|
You can specify more than one styles file or even a combination of `style` and `styleUrls`.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -216,9 +216,10 @@ You can also write `<link>` tags into the component's HTML template.
|
|||||||
|
|
||||||
<div class="alert is-critical">
|
<div class="alert is-critical">
|
||||||
|
|
||||||
When building with the CLI, be sure to include the linked style file among the assets to be copied to the server as described in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-asset-configuration).
|
The link tag's `href` URL must be relative to the
|
||||||
|
_**application root**_, not relative to the component file.
|
||||||
|
|
||||||
Once included, the CLI will include the stylesheet, whether the link tag's href URL is relative to the application root or the component file.
|
When building with the CLI, be sure to include the linked style file among the assets to be copied to the server as described in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-asset-configuration).
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -279,14 +280,12 @@ To control how this encapsulation happens on a *per
|
|||||||
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
||||||
Choose from the following modes:
|
Choose from the following modes:
|
||||||
|
|
||||||
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
|
* `Native` view encapsulation uses the browser's native shadow DOM implementation (see
|
||||||
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||||
on the [MDN](https://developer.mozilla.org) site)
|
on the [MDN](https://developer.mozilla.org) site)
|
||||||
to attach a shadow DOM to the component's host element, and then puts the component
|
to attach a shadow DOM to the component's host element, and then puts the component
|
||||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||||
|
|
||||||
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
|
|
||||||
|
|
||||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||||
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
|
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
|
||||||
@ -301,8 +300,8 @@ To set the components encapsulation mode, use the `encapsulation` property in th
|
|||||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false">
|
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
`Native` view encapsulation only works on browsers that have native support
|
||||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
for shadow DOM (see [Shadow DOM v0](http://caniuse.com/#feat=shadowdom) on the
|
||||||
[Can I use](http://caniuse.com) site). The support is still limited,
|
[Can I use](http://caniuse.com) site). The support is still limited,
|
||||||
which is why `Emulated` view encapsulation is the default mode and recommended
|
which is why `Emulated` view encapsulation is the default mode and recommended
|
||||||
in most cases.
|
in most cases.
|
||||||
|
@ -152,7 +152,7 @@ Install `source-map-explorer`:
|
|||||||
Build your app for production _including the source maps_
|
Build your app for production _including the source maps_
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
ng build --prod --source-map
|
ng build --prod --sourcemaps
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
List the generated bundles in the `dist/` folder.
|
List the generated bundles in the `dist/` folder.
|
||||||
|
@ -31,8 +31,6 @@ Here are a few essential commands for guide page authors.
|
|||||||
|
|
||||||
1. http://localhost:4200/ — browse to the app running locally.
|
1. http://localhost:4200/ — browse to the app running locally.
|
||||||
|
|
||||||
You can combine `yarn docs-watch` and `yarn start` into one command with `yarn serve-and-sync`.
|
|
||||||
|
|
||||||
## Guide pages
|
## Guide pages
|
||||||
|
|
||||||
All but a few guide pages are [markdown](https://daringfireball.net/projects/markdown/syntax "markdown") files with an `.md` extension.
|
All but a few guide pages are [markdown](https://daringfireball.net/projects/markdown/syntax "markdown") files with an `.md` extension.
|
||||||
|
@ -92,7 +92,7 @@ built-in validators—this time, in function form. See below:
|
|||||||
|
|
||||||
{@a reactive-component-class}
|
{@a reactive-component-class}
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Note that:
|
Note that:
|
||||||
@ -148,7 +148,7 @@ at which point the form uses the last value emitted for validation.
|
|||||||
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
|
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
|
||||||
to the `FormControl`.
|
to the `FormControl`.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### Adding to template-driven forms
|
### Adding to template-driven forms
|
||||||
@ -208,80 +208,5 @@ set the color of each form control's border.
|
|||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
## Cross field validation
|
|
||||||
This section shows how to perform cross field validation. It assumes some basic knowledge of creating custom validators.
|
|
||||||
|
|
||||||
<div class="l-sub-section">
|
|
||||||
|
|
||||||
If you haven't created custom validators before, start by reviewing the [custom validators section](guide/form-validation#custom-validators).
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
In the following section, we will make sure that our heroes do not reveal their true identities by filling out the Hero Form. We will do that by validating that the hero names and alter egos do not match.
|
|
||||||
|
|
||||||
### Adding to reactive forms
|
|
||||||
|
|
||||||
The form has the following structure:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const heroForm = new FormGroup({
|
|
||||||
'name': new FormControl(),
|
|
||||||
'alterEgo': new FormControl(),
|
|
||||||
'power': new FormControl()
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Notice that the name and alterEgo are sibling controls. To evaluate both controls in a single custom validator, we should perform the validation in a common ancestor control: the `FormGroup`. That way, we can query the `FormGroup` for the child controls which will allow us to compare their values.
|
|
||||||
|
|
||||||
To add a validator to the `FormGroup`, pass the new validator in as the second argument on creation.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const heroForm = new FormGroup({
|
|
||||||
'name': new FormControl(),
|
|
||||||
'alterEgo': new FormControl(),
|
|
||||||
'power': new FormControl()
|
|
||||||
}, { validators: identityRevealedValidator });
|
|
||||||
```
|
|
||||||
|
|
||||||
The validator code is as follows:
|
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" title="shared/identity-revealed.directive.ts" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise.
|
|
||||||
|
|
||||||
First we retrieve the child controls by calling the `FormGroup`'s [get](api/forms/AbstractControl#get) method. Then we simply compare the values of the `name` and `alterEgo` controls.
|
|
||||||
|
|
||||||
If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object.
|
|
||||||
|
|
||||||
Next, to provide better user experience, we show an appropriate error message when the form is invalid.
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" title="reactive/hero-form-template.component.html" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Note that we check if:
|
|
||||||
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
|
||||||
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
|
||||||
|
|
||||||
### Adding to template driven forms
|
|
||||||
First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms).
|
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" title="shared/identity-revealed.directive.ts" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag.
|
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" title="template/hero-form-template.component.html" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
To provide better user experience, we show an appropriate error message when the form is invalid.
|
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" title="template/hero-form-template.component.html" linenums="false">
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Note that we check if:
|
|
||||||
- the form has the cross validation error returned by the `identityRevealed` validator,
|
|
||||||
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
|
||||||
|
|
||||||
This completes the cross validation example. We managed to:
|
|
||||||
- validate the form based on the values of two sibling controls,
|
|
||||||
- show a descriptive error message after the user interacted with the form and the validation failed.
|
|
||||||
|
|
||||||
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
|
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
|
||||||
|
@ -152,8 +152,7 @@ nothing to distinguish it from any component you've written before.
|
|||||||
Understanding this component requires only the Angular concepts covered in previous pages.
|
Understanding this component requires only the Angular concepts covered in previous pages.
|
||||||
|
|
||||||
* The code imports the Angular core library and the `Hero` model you just created.
|
* The code imports the Angular core library and the `Hero` model you just created.
|
||||||
* The `@Component` selector value of "app-hero-form" means you can drop this form in a parent
|
* The `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `<hero-form>` tag.
|
||||||
template with a `<app-hero-form>` tag.
|
|
||||||
* The `templateUrl` property points to a separate file for the template HTML.
|
* The `templateUrl` property points to a separate file for the template HTML.
|
||||||
* You defined dummy data for `model` and `powers`, as befits a demo.
|
* You defined dummy data for `model` and `powers`, as befits a demo.
|
||||||
|
|
||||||
|
@ -114,23 +114,19 @@ The following class types can be declared:
|
|||||||
|
|
||||||
A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
||||||
|
|
||||||
{@a cli}
|
|
||||||
|
|
||||||
## CLI
|
## CLI
|
||||||
|
|
||||||
The [Angular CLI](https://cli.angular.io/) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](guide/glossary#workspace) or [project](guide/glossary#project), and to run [schematics](guide/glossary#schematic) that add and modify code for initial generic versions of various elements. The tool supports all stages of the development cycle, including building, testing, bundling, and deployment.
|
The [Angular CLI](https://cli.angular.io/) is a command-line tool that can create a project, add files, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
|
||||||
|
|
||||||
* To begin using the CLI for a new project, see [Getting Started](guide/quickstart) guide.
|
Learn more in the [Getting Started](guide/quickstart) guide.
|
||||||
* To learn more about the full capabilities of the CLI, see the [Angular CLI documentation].(https://github.com/angular/angular-cli/wiki).
|
|
||||||
|
|
||||||
{@a component}
|
{@a component}
|
||||||
|
|
||||||
## Component
|
## Component
|
||||||
|
|
||||||
A class with the `@Component` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template). Together, the component and template define a [view](guide/glossary#view).
|
A class with the `@Component` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template).
|
||||||
|
|
||||||
A component is a special type of [directive](guide/glossary#directive).
|
A component is a special type of [directive](guide/glossary#directive) that represents a [view](guide/glossary#view).The `@Component` decorator extends the `@Directive` decorator with template-oriented features.
|
||||||
The `@Component` decorator extends the `@Directive` decorator with template-oriented features.
|
|
||||||
|
|
||||||
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
||||||
|
|
||||||
@ -212,8 +208,7 @@ See [Class decorator](guide/glossary#class-decorator), [Class field decorator](g
|
|||||||
|
|
||||||
A design pattern and mechanism for creating and delivering parts of an application (dependencies) to other parts of an application that require them.
|
A design pattern and mechanism for creating and delivering parts of an application (dependencies) to other parts of an application that require them.
|
||||||
|
|
||||||
In Angular, dependencies are typically services, but can also be values, such as strings or functions.
|
In Angular, dependencies are typically services, but can also be values, such as strings or functions. An [injector](guide/glossary#injector) for an app (created automatically during bootstrap) creates dependencies when needed, using a registered [provider](guide/glossary#provider) of the service or value. Different providers can provide different implementations of the same service.
|
||||||
An [injector](guide/glossary#injector) for an app (created automatically during bootstrap) instantiates dependencies when needed, using a configured [provider](guide/glossary#provider) of the service or value.
|
|
||||||
|
|
||||||
Learn more in the [Dependency Injection](guide/dependency-injection) guide.
|
Learn more in the [Dependency Injection](guide/dependency-injection) guide.
|
||||||
|
|
||||||
@ -285,7 +280,7 @@ Compare [Custom element](guide/glossary#custom-element).
|
|||||||
|
|
||||||
## Entry point
|
## Entry point
|
||||||
|
|
||||||
A JavaScript symbol that makes parts of an npm package available for import by other code.
|
A JavaScript ID that makes parts of an NPM package available for import by other code.
|
||||||
The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`.
|
The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`.
|
||||||
|
|
||||||
Within Angular, use [NgModules](guide/glossary#ngmodule) to achieve the same result.
|
Within Angular, use [NgModules](guide/glossary#ngmodule) to achieve the same result.
|
||||||
@ -315,17 +310,7 @@ Both a [service](guide/glossary#service) and a [component](guide/glossary#compon
|
|||||||
|
|
||||||
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
|
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
|
||||||
that can find a named dependency in its cache or create a dependency
|
that can find a named dependency in its cache or create a dependency
|
||||||
using a configured [provider](guide/glossary#provider).
|
with a registered [provider](guide/glossary#provider). Injectors are created for NgModules automatically as part of the bootstrap process, and inherited through the component hierarchy.
|
||||||
Injectors are created for NgModules automatically as part of the bootstrap process
|
|
||||||
and are inherited through the component hierarchy.
|
|
||||||
|
|
||||||
* An injector provides a singleton instance of a dependency, and can inject this same instance in multiple components.
|
|
||||||
|
|
||||||
* A hierarchy of injectors at the NgModule and component level can provide different instances of a dependency to their own components and child components.
|
|
||||||
|
|
||||||
* You can configure injectors with different providers that can provide different implementations of the same dependency.
|
|
||||||
|
|
||||||
Learn more about the injector hierarchy in the [Dependency Injection guide](guide/hierarchical-dependency-injection).
|
|
||||||
|
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
@ -388,17 +373,6 @@ Lazy loading speeds up application load time by splitting the application into m
|
|||||||
For example, dependencies can be lazy-loaded as needed&emdash;as opposed to "eager-loaded" modules that are required by the root module, and are thus loaded on launch.
|
For example, dependencies can be lazy-loaded as needed&emdash;as opposed to "eager-loaded" modules that are required by the root module, and are thus loaded on launch.
|
||||||
Similarly, the [router](guide/glossary#router) can load child views only when the parent view is activated, and you can build custom elements that can be loaded into an Angular app when needed.
|
Similarly, the [router](guide/glossary#router) can load child views only when the parent view is activated, and you can build custom elements that can be loaded into an Angular app when needed.
|
||||||
|
|
||||||
{@a library}
|
|
||||||
|
|
||||||
## Library
|
|
||||||
|
|
||||||
In Angular, a [project](guide/glossary#project) that provides functionality that can be included in other Angular apps. A library is not a complete Angular app, and it cannot run independently.
|
|
||||||
|
|
||||||
* Library developers can use the [CLI](guide/glossary#cli) to `generate` scaffolding for a new library in an existing [workspace](guide/glossary#workspace), and can publish a library as an `npm` package.
|
|
||||||
|
|
||||||
* App developers can use the [CLI](guide/glossary#cli) to `add` a published library for use with an app in the same [workspace](guide/glossary#workspace).
|
|
||||||
|
|
||||||
|
|
||||||
## Lifecycle hook
|
## Lifecycle hook
|
||||||
|
|
||||||
An interface that allows you to tap into the lifecycle of [directives](guide/glossary#directive) and [components](guide/glossary#component) as they are created, updated, and destroyed.
|
An interface that allows you to tap into the lifecycle of [directives](guide/glossary#directive) and [components](guide/glossary#component) as they are created, updated, and destroyed.
|
||||||
@ -428,7 +402,7 @@ In general, a module collects a block of code dedicated to a single purpose. Ang
|
|||||||
|
|
||||||
In JavaScript (ECMAScript), each file is a module and all objects defined in the file belong to that module. Objects can exported, making them public, and public objects can be imported for use by other modules.
|
In JavaScript (ECMAScript), each file is a module and all objects defined in the file belong to that module. Objects can exported, making them public, and public objects can be imported for use by other modules.
|
||||||
|
|
||||||
Angular ships as a collection of JavaScript modules, or libraries. Each Angular library name begins with the `@angular` prefix. Install them with the npm package manager and import parts of them with JavaScript `import` declarations.
|
Angular ships as a collection of JavaScript modules, or libraries. Each Angular library name begins with the `@angular` prefix. Install them with the NPM package manager and import parts of them with JavaScript `import` declarations.
|
||||||
|
|
||||||
Compare the Angular [NgModule](guide/glossary#ngmodule).
|
Compare the Angular [NgModule](guide/glossary#ngmodule).
|
||||||
|
|
||||||
@ -496,13 +470,8 @@ To learn more, see the [pipes](guide/pipes) page.
|
|||||||
|
|
||||||
## Polyfill
|
## Polyfill
|
||||||
|
|
||||||
An [npm package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. See the [Browser Support](guide/browser-support) guide for polyfills that support particular functionality for particular platforms.
|
An [NPM package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. See the [Browser Support](guide/browser-support) guide for polyfills that support particular functionality for particular platforms.
|
||||||
|
|
||||||
{@a project}
|
|
||||||
|
|
||||||
## Project
|
|
||||||
|
|
||||||
In Angular, a folder within a [workspace](guide/glossary#workspace) that contains an Angular app or [library](guide/glossary#library). A workspace can contain multiple projects. All apps in a workspace can use libraries in the same workspace.
|
|
||||||
|
|
||||||
## Provider
|
## Provider
|
||||||
|
|
||||||
@ -562,24 +531,9 @@ For more information, see the [Routing & Navigation](guide/router) page.
|
|||||||
|
|
||||||
{@a S}
|
{@a S}
|
||||||
|
|
||||||
{@a schematic}
|
|
||||||
|
|
||||||
## Schematic
|
|
||||||
|
|
||||||
A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code.
|
|
||||||
|
|
||||||
The Angular [CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects.
|
|
||||||
|
|
||||||
* Angular provides a set of schematics for use with the CLI.
|
|
||||||
For details, see [Angular CLI documentation].(https://github.com/angular/angular-cli/wiki).
|
|
||||||
|
|
||||||
* Library developers can create schematics that enable the CLI to generate their published libraries.
|
|
||||||
For more information, see https://www.npmjs.com/package/@angular-devkit/schematics.
|
|
||||||
|
|
||||||
|
|
||||||
## Scoped package
|
## Scoped package
|
||||||
|
|
||||||
A way to group related npm packages.
|
A way to group related NPM packages.
|
||||||
NgModules are delivered within *scoped packages* whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/http`, and `@angular/router`.
|
NgModules are delivered within *scoped packages* whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/http`, and `@angular/router`.
|
||||||
|
|
||||||
Import a scoped package in the same way that you import a normal package.
|
Import a scoped package in the same way that you import a normal package.
|
||||||
@ -723,12 +677,6 @@ The view hierarchy does not imply a component hierarchy. Views that are embedded
|
|||||||
|
|
||||||
See [Custom element](guide/glossary#custom-element)
|
See [Custom element](guide/glossary#custom-element)
|
||||||
|
|
||||||
{@a workspace}
|
|
||||||
|
|
||||||
## Workspace
|
|
||||||
|
|
||||||
In Angular, a folder that contains [projects](guide/glossary#project) (that is, apps and libraries).
|
|
||||||
The [CLI](guide/glossary#cli) `new` command creates a workspace to contain projects. Commands such as `add` and `generate`, that create or operate on apps and libraries, must be executed from within a workspace folder.
|
|
||||||
|
|
||||||
{@a X}
|
{@a X}
|
||||||
|
|
||||||
|
@ -1034,7 +1034,7 @@ Call `request.flush()` with an error message, as seen in the following example.
|
|||||||
|
|
||||||
<code-example
|
<code-example
|
||||||
path="http/src/testing/http-client.spec.ts"
|
path="http/src/testing/http-client.spec.ts"
|
||||||
region="404"
|
region="network-error"
|
||||||
linenums="false">
|
linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ configure services in root and feature modules respectively.
|
|||||||
|
|
||||||
Angular doesn't recognize these names but Angular developers do.
|
Angular doesn't recognize these names but Angular developers do.
|
||||||
Follow this convention when you write similar modules with configurable service providers.
|
Follow this convention when you write similar modules with configurable service providers.
|
||||||
|
<!--KW--I don't understand how Angular doesn't understand these methods...-->
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -233,8 +233,9 @@ When you import an NgModule,
|
|||||||
Angular adds the module's service providers (the contents of its `providers` list)
|
Angular adds the module's service providers (the contents of its `providers` list)
|
||||||
to the application root injector.
|
to the application root injector.
|
||||||
|
|
||||||
This makes the provider visible to every class in the application that knows the provider's lookup token, or name.
|
This makes the provider visible to every class in the application that knows the provider's lookup token, or knows its name.
|
||||||
|
|
||||||
|
This is by design.
|
||||||
Extensibility through NgModule imports is a primary goal of the NgModule system.
|
Extensibility through NgModule imports is a primary goal of the NgModule system.
|
||||||
Merging NgModule providers into the application injector
|
Merging NgModule providers into the application injector
|
||||||
makes it easy for a module library to enrich the entire application with new services.
|
makes it easy for a module library to enrich the entire application with new services.
|
||||||
@ -246,8 +247,6 @@ If the `HeroModule` provides the `HeroService` and the root `AppModule` imports
|
|||||||
any class that knows the `HeroService` _type_ can inject that service,
|
any class that knows the `HeroService` _type_ can inject that service,
|
||||||
not just the classes declared in the `HeroModule`.
|
not just the classes declared in the `HeroModule`.
|
||||||
|
|
||||||
To limit access to a service, consider lazy loading the NgModule that provides that service. See [How do I restrict service scope to a module?](guide/ngmodule-faq#service-scope) for more information.
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{@a q-lazy-loaded-module-provider-visibility}
|
{@a q-lazy-loaded-module-provider-visibility}
|
||||||
@ -289,7 +288,6 @@ The `AppModule` always wins.
|
|||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{@a service-scope}
|
|
||||||
|
|
||||||
## How do I restrict service scope to a module?
|
## How do I restrict service scope to a module?
|
||||||
|
|
||||||
@ -337,8 +335,6 @@ You can embed the child components in the top component's template.
|
|||||||
Alternatively, make the top component a routing host by giving it a `<router-outlet>`.
|
Alternatively, make the top component a routing host by giving it a `<router-outlet>`.
|
||||||
Define child routes and let the router load module components into that outlet.
|
Define child routes and let the router load module components into that outlet.
|
||||||
|
|
||||||
Though you can limit access to a service by providing it in a lazy loaded module or providing it in a component, providing services in a component can lead to multiple instances of those services. Thus, the lazy loading is preferable.
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{@a q-root-component-or-module}
|
{@a q-root-component-or-module}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
||||||
Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket.
|
Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket.
|
||||||
|
|
||||||
Once data arrives, you could push their raw `toString` values directly to the view,
|
Once data arrive, you could push their raw `toString` values directly to the view,
|
||||||
but that rarely makes for a good user experience.
|
but that rarely makes for a good user experience.
|
||||||
For example, in most use cases, users prefer to see a date in a simple format like
|
For example, in most use cases, users prefer to see a date in a simple format like
|
||||||
<samp>April 15, 1988</samp> rather than the raw string format
|
<samp>April 15, 1988</samp> rather than the raw string format
|
||||||
|
@ -23,7 +23,6 @@ Unless otherwise noted, patterns use a limited glob format:
|
|||||||
|
|
||||||
* `**` matches 0 or more path segments.
|
* `**` matches 0 or more path segments.
|
||||||
* `*` matches 0 or more characters excluding `/`.
|
* `*` matches 0 or more characters excluding `/`.
|
||||||
* `?` matches exactly one character excluding `/`.
|
|
||||||
* The `!` prefix marks the pattern as being negative, meaning that only files that don't match the pattern will be included.
|
* The `!` prefix marks the pattern as being negative, meaning that only files that don't match the pattern will be included.
|
||||||
|
|
||||||
Example patterns:
|
Example patterns:
|
||||||
@ -107,7 +106,7 @@ This section describes the resources to cache, broken up into three groups.
|
|||||||
* `versionedFiles` has been deprecated. As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead.
|
* `versionedFiles` has been deprecated. As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead.
|
||||||
|
|
||||||
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.<br>
|
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.<br>
|
||||||
_(Negative glob patterns are not supported and `?` will be matched literally; i.e. it will not match any character other than `?`.)_
|
_(Negative glob patterns are not supported.)_
|
||||||
|
|
||||||
## `dataGroups`
|
## `dataGroups`
|
||||||
|
|
||||||
@ -134,7 +133,7 @@ Similar to `assetGroups`, every data group has a `name` which uniquely identifie
|
|||||||
|
|
||||||
### `urls`
|
### `urls`
|
||||||
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.<br>
|
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.<br>
|
||||||
_(Negative glob patterns are not supported and `?` will be matched literally; i.e. it will not match any character other than `?`.)_
|
_(Negative glob patterns are not supported.)_
|
||||||
|
|
||||||
### `version`
|
### `version`
|
||||||
Occasionally APIs change formats in a way that is not backward-compatible. A new version of the app may not be compatible with the old API format and thus may not be compatible with existing cached resources from that API.
|
Occasionally APIs change formats in a way that is not backward-compatible. A new version of the app may not be compatible with the old API format and thus may not be compatible with existing cached resources from that API.
|
||||||
|
@ -933,18 +933,29 @@ As always, strive for consistency.
|
|||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 05-02}
|
{@a 02-06}
|
||||||
|
|
||||||
### Component selectors
|
### Directive selectors
|
||||||
|
|
||||||
#### Style 05-02
|
#### Style 02-06
|
||||||
|
|
||||||
|
|
||||||
<div class="s-rule do">
|
<div class="s-rule do">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components.
|
**Do** Use lower camel case for naming the selectors of directives.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-why">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -955,40 +966,16 @@ As always, strive for consistency.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/).
|
**Why?** The Angular HTML parser is case sensitive and recognizes lower camel case.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts">
|
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<code-tabs>
|
|
||||||
|
|
||||||
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
|
|
||||||
|
|
||||||
</code-pane>
|
|
||||||
|
|
||||||
<code-pane title="app/app.component.html" path="styleguide/src/05-02/app/app.component.html">
|
|
||||||
|
|
||||||
</code-pane>
|
|
||||||
|
|
||||||
</code-tabs>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 02-07}
|
{@a 02-07}
|
||||||
|
|
||||||
### Component custom prefix
|
### Custom prefix for components
|
||||||
|
|
||||||
#### Style 02-07
|
#### Style 02-07
|
||||||
|
|
||||||
@ -1091,51 +1078,11 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
|
||||||
|
|
||||||
{@a 02-06}
|
|
||||||
|
|
||||||
### Directive selectors
|
|
||||||
|
|
||||||
#### Style 02-06
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-rule do">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Do** Use lower camel case for naming the selectors of directives.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-why">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-why-last">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** The Angular HTML parser is case sensitive and recognizes lower camel case.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
|
||||||
|
|
||||||
{@a 02-08}
|
{@a 02-08}
|
||||||
|
|
||||||
### Directive custom prefix
|
### Custom prefix for directives
|
||||||
|
|
||||||
#### Style 02-08
|
#### Style 02-08
|
||||||
|
|
||||||
@ -3109,9 +3056,9 @@ module are referenced across the entire application.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Consider** _not_ providing services in shared modules. Services are usually
|
**Avoid** providing services in shared modules. Services are usually
|
||||||
singletons that are provided once for the entire application or
|
singletons that are provided once for the entire application or
|
||||||
in a particular feature module. There are exceptions, however. For example, in the sample code that follows, notice that the `SharedModule` provides `FilterTextService`. This is acceptable here because the service is stateless;that is, the consumers of the service aren't impacted by new instances.
|
in a particular feature module.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -3763,6 +3710,59 @@ A typical *lazy loaded folder* contains a *routing component*, its child compone
|
|||||||
|
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
|
{@a 05-02}
|
||||||
|
|
||||||
|
### Component selector names
|
||||||
|
|
||||||
|
#### Style 05-02
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-rule do">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-why-last">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/).
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="app/app.component.html" path="styleguide/src/05-02/app/app.component.html">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 05-03}
|
{@a 05-03}
|
||||||
|
|
||||||
### Components as elements
|
### Components as elements
|
||||||
|
@ -398,7 +398,7 @@ But a component is more than just its class.
|
|||||||
A component interacts with the DOM and with other components.
|
A component interacts with the DOM and with other components.
|
||||||
The _class-only_ tests can tell you about class behavior.
|
The _class-only_ tests can tell you about class behavior.
|
||||||
They cannot tell you if the component is going to render properly,
|
They cannot tell you if the component is going to render properly,
|
||||||
respond to user input and gestures, or integrate with its parent and child components.
|
respond to user input and gestures, or integrate with its parent and and child components.
|
||||||
|
|
||||||
None of the _class-only_ tests above can answer key questions about how the
|
None of the _class-only_ tests above can answer key questions about how the
|
||||||
components actually behave on screen.
|
components actually behave on screen.
|
||||||
|
@ -132,7 +132,7 @@ QuickStart identifies two *typings*, or `d.ts`, files:
|
|||||||
* [jasmine](http://jasmine.github.io/) typings for the Jasmine test framework.
|
* [jasmine](http://jasmine.github.io/) typings for the Jasmine test framework.
|
||||||
|
|
||||||
* [node](https://www.npmjs.com/package/@types/node) for code that references objects in the *Node.js®* environment;
|
* [node](https://www.npmjs.com/package/@types/node) for code that references objects in the *Node.js®* environment;
|
||||||
|
you can view an example in the [webpack](guide/webpack) page.
|
||||||
|
|
||||||
QuickStart doesn't require these typings but many of the samples do.
|
QuickStart doesn't require these typings but many of the samples do.
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ even when the Universal web server is capable of handling those requests.
|
|||||||
You'll have to change the services to make requests with absolute URLs when running on the server
|
You'll have to change the services to make requests with absolute URLs when running on the server
|
||||||
and with relative URLs when running in the browser.
|
and with relative URLs when running in the browser.
|
||||||
|
|
||||||
One solution is to provide the server's runtime origin under the Angular [`APP_BASE_HREF` token](api/common/APP_BASE_HREF),
|
One solution is to provide the server's runtime origin under the Angular [`APP_BASE_REF` token](api/common/APP_BASE_HREF),
|
||||||
inject it into the service, and prepend the origin to the request URL.
|
inject it into the service, and prepend the origin to the request URL.
|
||||||
|
|
||||||
Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token.
|
Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token.
|
||||||
|
@ -1,352 +0,0 @@
|
|||||||
# Upgrading for Performance
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
|
||||||
|
|
||||||
_Angular_ is the name for the Angular of today and tomorrow.<br />
|
|
||||||
_AngularJS_ is the name for all 1.x versions of Angular.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
This guide describes some of the built-in tools for efficiently migrating AngularJS projects over to
|
|
||||||
the Angular platform, one piece at a time. It is very similar to
|
|
||||||
[Upgrading from AngularJS](guide/upgrade) with the exception that this one uses the {@link
|
|
||||||
downgradeModule downgradeModule()} helper function instead of the {@link UpgradeModule
|
|
||||||
UpgradeModule} class. This affects how the app is bootstrapped and how change detection is
|
|
||||||
propagated between the two frameworks. It allows you to upgrade incrementally while improving the
|
|
||||||
speed of your hybrid apps and leveraging the latest of Angular in AngularJS apps early in the
|
|
||||||
process of upgrading.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Preparation
|
|
||||||
|
|
||||||
Before discussing how you can use `downgradeModule()` to create hybrid apps, there are things that
|
|
||||||
you can do to ease the upgrade process even before you begin upgrading. Because the steps are the
|
|
||||||
same regardless of how you upgrade, refer to the [Preparation](guide/upgrade#preparation) section of
|
|
||||||
[Upgrading from AngularJS](guide/upgrade).
|
|
||||||
|
|
||||||
|
|
||||||
## Upgrading with `ngUpgrade`
|
|
||||||
|
|
||||||
With the `ngUpgrade` library in Angular you can upgrade an existing AngularJS app incrementally by
|
|
||||||
building a hybrid app where you can run both frameworks side-by-side. In these hybrid apps you can
|
|
||||||
mix and match AngularJS and Angular components and services and have them interoperate seamlessly.
|
|
||||||
That means you don't have to do the upgrade work all at once as there is a natural coexistence
|
|
||||||
between the two frameworks during the transition period.
|
|
||||||
|
|
||||||
|
|
||||||
### How `ngUpgrade` Works
|
|
||||||
|
|
||||||
Regardless of whether you choose `downgradeModule()` or `UpgradeModule`, the basic principles of
|
|
||||||
upgrading, the mental model behind hybrid apps, and how you use the {@link upgrade/static
|
|
||||||
upgrade/static} utilities remain the same. For more information, see the
|
|
||||||
[How `ngUpgrade` Works](guide/upgrade#how-ngupgrade-works) section of
|
|
||||||
[Upgrading from AngularJS](guide/upgrade).
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
|
||||||
|
|
||||||
The [Change Detection](guide/upgrade#change-detection) section of
|
|
||||||
[Upgrading from AngularJS](guide/upgrade) only applies to apps that use `UpgradeModule`. Though
|
|
||||||
you handle change detection differently with `downgradeModule()`, which is the focus of this
|
|
||||||
guide, reading the [Change Detection](guide/upgrade#change-detection) section provides helpful
|
|
||||||
context for what follows.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
#### Change Detection with `downgradeModule()`
|
|
||||||
|
|
||||||
As mentioned before, one of the key differences between `downgradeModule()` and `UpgradeModule` has
|
|
||||||
to do with change detection and how it is propagated between the two frameworks.
|
|
||||||
|
|
||||||
With `UpgradeModule`, the two change detection systems are tied together more tightly. Whenever
|
|
||||||
something happens in the AngularJS part of the app, change detection is automatically triggered on
|
|
||||||
the Angular part and vice versa. This is convenient as it ensures that neither framework misses an
|
|
||||||
important change. Most of the time, though, these extra change detection runs are unnecessary.
|
|
||||||
|
|
||||||
`downgradeModule()`, on the other side, avoids explicitly triggering change detection unless it
|
|
||||||
knows the other part of the app is interested in the changes. For example, if a downgraded component
|
|
||||||
defines an `@Input()`, chances are that the app needs to be aware when that value changes. Thus,
|
|
||||||
`downgradeComponent()` automatically triggers change detection on that component.
|
|
||||||
|
|
||||||
In most cases, though, the changes made locally in a particular component are of no interest to the
|
|
||||||
rest of the app. For example, if the user clicks a button that submits a form, the component usually
|
|
||||||
handles the result of this action. That being said, there _are_ cases where you want to propagate
|
|
||||||
changes to some other part of the app that may be controlled by the other framework. In such cases,
|
|
||||||
you are responsible for notifying the interested parties by manually triggering change detection.
|
|
||||||
|
|
||||||
If you want a particular piece of code to trigger change detection in the AngularJS part of the app,
|
|
||||||
you need to wrap it in
|
|
||||||
[scope.$apply()](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply). Similarly, for
|
|
||||||
triggering change detection in Angular you would use {@link NgZone#run ngZone.run()}.
|
|
||||||
|
|
||||||
In many cases, a few extra change detection runs may not matter much. However, on larger or
|
|
||||||
change-detection-heavy apps they can have a noticeable impact. By giving you more fine-grained
|
|
||||||
control over the change detection propagation, `downgradeModule()` allows you to achieve better
|
|
||||||
performance for your hybrid apps.
|
|
||||||
|
|
||||||
|
|
||||||
## Using `downgradeModule()`
|
|
||||||
|
|
||||||
Both AngularJS and Angular have their own concept of modules to help organize an app into cohesive
|
|
||||||
blocks of functionality.
|
|
||||||
|
|
||||||
Their details are quite different in architecture and implementation. In AngularJS, you create a
|
|
||||||
module by specifying its name and dependencies with
|
|
||||||
[angular.module()](https://docs.angularjs.org/api/ng/function/angular.module). Then you can add
|
|
||||||
assets using its various methods. In Angular, you create a class adorned with an {@link NgModule
|
|
||||||
NgModule} decorator that describes assets in metadata.
|
|
||||||
|
|
||||||
In a hybrid app you run both frameworks at the same time. This means that you need at least one
|
|
||||||
module each from both AngularJS and Angular.
|
|
||||||
|
|
||||||
For the most part, you specify the modules in the same way you would for a regular app. Then, you
|
|
||||||
use the `upgrade/static` helpers to let the two frameworks know about assets they can use from each
|
|
||||||
other. This is known as "upgrading" and "downgrading".
|
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
|
||||||
|
|
||||||
<b>Definitions:</b>
|
|
||||||
|
|
||||||
- _Upgrading_: The act of making an AngularJS asset, such as a component or service, available to
|
|
||||||
the Angular part of the app.
|
|
||||||
- _Downgrading_: The act of making an Angular asset, such as a component or service, available to
|
|
||||||
the AngularJS part of the app.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
An important part of inter-linking dependencies is linking the two main modules together. This is
|
|
||||||
where `downgradeModule()` comes in. Use it to create an AngularJS module—one that you can use
|
|
||||||
as a dependency in your main AngularJS module—that will bootstrap your main Angular module and
|
|
||||||
kick off the Angular part of the hybrid app. In a sense, it "downgrades" an Angular module to an
|
|
||||||
AngularJS module.
|
|
||||||
|
|
||||||
There are a few things to note, though:
|
|
||||||
|
|
||||||
1. You don't pass the Angular module directly to `downgradeModule()`. All `downgradeModule()` needs
|
|
||||||
is a "recipe", for example, a factory function, to create an instance for your module.
|
|
||||||
|
|
||||||
2. The Angular module is not instantiated until the app actually needs it.
|
|
||||||
|
|
||||||
The following is an example of how you can use `downgradeModule()` to link the two modules.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// Import `downgradeModule()`.
|
|
||||||
import { downgradeModule } from '@angular/upgrade/static';
|
|
||||||
|
|
||||||
// Use it to downgrade the Angular module to an AngularJS module.
|
|
||||||
const downgradedModule = downgradeModule(MainAngularModuleFactory);
|
|
||||||
|
|
||||||
// Use the downgraded module as a dependency to the main AngularJS module.
|
|
||||||
angular.module('mainAngularJsModule', [
|
|
||||||
downgradedModule
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Specifying a factory for the Angular module
|
|
||||||
|
|
||||||
As mentioned earlier, `downgradeModule()` needs to know how to instantiate the Angular module. It
|
|
||||||
needs a recipe. You define that recipe by providing a factory function that can create an instance
|
|
||||||
of the Angular module. `downgradeModule()` accepts two types of factory functions:
|
|
||||||
|
|
||||||
1. `NgModuleFactory`
|
|
||||||
2. `(extraProviders: StaticProvider[]) => Promise<NgModuleRef>`
|
|
||||||
|
|
||||||
When you pass an `NgModuleFactory`, `downgradeModule()` uses it to instantiate the module using
|
|
||||||
{@link platformBrowser platformBrowser}'s {@link PlatformRef#bootstrapModuleFactory
|
|
||||||
bootstrapModuleFactory()}, which is compatible with ahead-of-time (AOT) compilation. AOT compilation
|
|
||||||
helps make your apps load faster. For more about AOT and how to create an `NgModuleFactory`, see the
|
|
||||||
[Ahead-of-Time Compilation](guide/aot-compiler) guide.
|
|
||||||
|
|
||||||
Alternatively, you can pass a plain function, which is expected to return a promise resolving to an
|
|
||||||
{@link NgModuleRef NgModuleRef} (i.e. an instance of your Angular module). The function is called
|
|
||||||
with an array of extra {@link StaticProvider Providers} that are expected to be available on the
|
|
||||||
returned `NgModuleRef`'s {@link Injector Injector}. For example, if you are using {@link
|
|
||||||
platformBrowser platformBrowser} or {@link platformBrowserDynamic platformBrowserDynamic}, you can
|
|
||||||
pass the `extraProviders` array to them:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const bootstrapFn = (extraProviders: StaticProvider[]) => {
|
|
||||||
const platformRef = platformBrowserDynamic(extraProviders);
|
|
||||||
return platformRef.bootstrapModule(MainAngularModule);
|
|
||||||
};
|
|
||||||
// or
|
|
||||||
const bootstrapFn = (extraProviders: StaticProvider[]) => {
|
|
||||||
const platformRef = platformBrowser(extraProviders);
|
|
||||||
return platformRef.bootstrapModuleFactory(MainAngularModuleFactory);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Using an `NgModuleFactory` requires less boilerplate and is a good default option as it supports AOT
|
|
||||||
out-of-the-box. Using a custom function requires slightly more code, but gives you greater
|
|
||||||
flexibility.
|
|
||||||
|
|
||||||
|
|
||||||
#### Instantiating the Angular module on-demand
|
|
||||||
|
|
||||||
Another key difference between `downgradeModule()` and `UpgradeModule` is that the latter requires
|
|
||||||
you to instantiate both the AngularJS and Angular modules up-front. This means that you have to pay
|
|
||||||
the cost of instantiating the Angular part of the app, even if you don't use any Angular assets
|
|
||||||
until later. `downgradeModule()` is again less aggressive. It will only instantiate the Angular part
|
|
||||||
when it is required for the first time; that is, as soon as it needs to create a downgraded
|
|
||||||
component.
|
|
||||||
|
|
||||||
You could go a step further and not even download the code for the Angular part of the app to the
|
|
||||||
user's browser until it is needed. This is especially useful when you use Angular on parts of the
|
|
||||||
hybrid app that are not necessary for the initial rendering or that the user doesn't reach.
|
|
||||||
|
|
||||||
|
|
||||||
A few examples are:
|
|
||||||
|
|
||||||
- You use Angular on specific routes only and you don't need it until/if a user visits such a route.
|
|
||||||
- You use Angular for features that are only visible to specific types of users; for example,
|
|
||||||
logged-in users, administrators, or VIP members. You don't need to load Angular until a user is
|
|
||||||
authenticated.
|
|
||||||
- You use Angular for a feature that is not critical for the initial rendering of the app and you
|
|
||||||
can afford a small delay in favor of better initial load performance.
|
|
||||||
|
|
||||||
|
|
||||||
### Bootstrapping with `downgradeModule()`
|
|
||||||
|
|
||||||
As you might have guessed, you don't need to change anything in the way you bootstrap your existing
|
|
||||||
AngularJS app. Unlike `UpgradeModule`—which requires some extra steps—
|
|
||||||
`downgradeModule()` is able to take care of bootstrapping the Angular module, as long as you provide
|
|
||||||
the recipe.
|
|
||||||
|
|
||||||
In order to start using any `upgrade/static` APIs, you still need to load the Angular framework as
|
|
||||||
you would in a normal Angular app. You can see how this can be done with SystemJS by following the
|
|
||||||
instructions in the [Setup](guide/setup) guide, selectively copying code from the
|
|
||||||
[QuickStart github repository](https://github.com/angular/quickstart).
|
|
||||||
|
|
||||||
You also need to install the `@angular/upgrade` package via `npm install @angular/upgrade --save`
|
|
||||||
and add a mapping for the `@angular/upgrade/static` package:
|
|
||||||
|
|
||||||
<code-example title="system.config.js">
|
|
||||||
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Next, create an `app.module.ts` file and add the following `NgModule` class:
|
|
||||||
|
|
||||||
<code-example title="app.module.ts">
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
BrowserModule
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class MainAngularModule {
|
|
||||||
// Empty placeholder method to satisfy the `Compiler`.
|
|
||||||
ngDoBootstrap() {}
|
|
||||||
}
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app
|
|
||||||
must have. It also defines an empty `ngDoBootstrap()` method, to prevent the {@link Compiler
|
|
||||||
Compiler} from returning errors. This is necessary because the module will not have a `bootstrap`
|
|
||||||
declaration on its `NgModule` decorator.
|
|
||||||
|
|
||||||
<div class="alert is-important">
|
|
||||||
|
|
||||||
You do not add a `bootstrap` declaration to the `NgModule` decorator since AngularJS owns the root
|
|
||||||
template of the app and `ngUpgrade` bootstraps the necessary components.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
You can now link the AngularJS and Angular modules together using `downgradeModule()`.
|
|
||||||
|
|
||||||
<code-example title="app.module.ts">
|
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
||||||
import { downgradeModule } from '@angular/upgrade/static';
|
|
||||||
|
|
||||||
const bootstrapFn = (extraProviders: StaticProvider[]) => {
|
|
||||||
const platformRef = platformBrowserDynamic(extraProviders);
|
|
||||||
return platformRef.bootstrapModule(MainAngularModule);
|
|
||||||
};
|
|
||||||
const downgradedModule = downgradeModule(bootstrapFn);
|
|
||||||
|
|
||||||
angular.module('mainAngularJsModule', [
|
|
||||||
downgradedModule
|
|
||||||
]);
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
The existing AngularJS code works as before _and_ you are ready to start adding Angular code.
|
|
||||||
|
|
||||||
|
|
||||||
### Using Components and Injectables
|
|
||||||
|
|
||||||
The differences between `downgradeModule()` and `UpgradeModule` end here. The rest of the
|
|
||||||
`upgrade/static` APIs and concepts work in the exact same way for both types of hybrid apps.
|
|
||||||
See [Upgrading from AngularJS](guide/upgrade) to learn about:
|
|
||||||
|
|
||||||
- [Using Angular Components from AngularJS Code](guide/upgrade#using-angular-components-from-angularjs-code).
|
|
||||||
- [Using AngularJS Component Directives from Angular Code](guide/upgrade#using-angularjs-component-directives-from-angular-code).
|
|
||||||
- [Projecting AngularJS Content into Angular Components](guide/upgrade#projecting-angularjs-content-into-angular-components).
|
|
||||||
- [Transcluding Angular Content into AngularJS Component Directives](guide/upgrade#transcluding-angular-content-into-angularjs-component-directives).
|
|
||||||
- [Making AngularJS Dependencies Injectable to Angular](guide/upgrade#making-angularjs-dependencies-injectable-to-angular).
|
|
||||||
- [Making Angular Dependencies Injectable to AngularJS](guide/upgrade#making-angular-dependencies-injectable-to-angularjs).
|
|
||||||
|
|
||||||
<div class="alert is-important">
|
|
||||||
|
|
||||||
While it is possible to downgrade injectables, downgraded injectables will not be available until
|
|
||||||
the Angular module is instantiated. In order to be safe, you need to ensure that the downgraded
|
|
||||||
injectables are not used anywhere _outside_ the part of the app that is controlled by Angular.
|
|
||||||
|
|
||||||
For example, it is _OK_ to use a downgraded service in an upgraded component that is only used
|
|
||||||
from Angular components, but it is _not OK_ to use it in an AngularJS component that may be used
|
|
||||||
independently of Angular.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## Using ahead-of-time compilation with hybrid apps
|
|
||||||
|
|
||||||
You can take advantage of ahead-of-time (AOT) compilation in hybrid apps just like in any other
|
|
||||||
Angular app. The setup for a hybrid app is mostly the same as described in the
|
|
||||||
[Ahead-of-Time Compilation](guide/aot-compiler) guide save for differences in `index.html` and
|
|
||||||
`main-aot.ts`.
|
|
||||||
|
|
||||||
AOT needs to load any AngularJS files that are in the `<script>` tags in the AngularJS `index.html`.
|
|
||||||
An easy way to copy them is to add each to the `copy-dist-files.js`file.
|
|
||||||
|
|
||||||
You also need to pass the generated `MainAngularModuleFactory` to `downgradeModule()` instead of the
|
|
||||||
custom bootstrap function:
|
|
||||||
|
|
||||||
<code-example title="app/main-aot.ts">
|
|
||||||
import { downgradeModule } from '@angular/upgrade/static';
|
|
||||||
import { MainAngularModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
|
||||||
|
|
||||||
const downgradedModule = downgradeModule(MainAngularModuleNgFactory);
|
|
||||||
|
|
||||||
angular.module('mainAngularJsModule', [
|
|
||||||
downgradedModule
|
|
||||||
]);
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
And that is all you need to do to get the full benefit of AOT for hybrid Angular apps.
|
|
||||||
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
This page covered how to use the {@link upgrade/static upgrade/static} package to incrementally
|
|
||||||
upgrade existing AngularJS apps at your own pace and without impeding further development of the app
|
|
||||||
for the duration of the upgrade process.
|
|
||||||
|
|
||||||
Specifically, this guide showed how you can achieve better performance and greater flexibility in
|
|
||||||
your hybrid apps by using {@link downgradeModule downgradeModule()} instead of {@link UpgradeModule
|
|
||||||
UpgradeModule}.
|
|
||||||
|
|
||||||
To summarize, the key differentiating factors of `downgradeModule()` are:
|
|
||||||
|
|
||||||
1. It allows instantiating or even loading the Angular part lazily, which improves the initial
|
|
||||||
loading time. In some cases this may waive the cost of running a second framework altogether.
|
|
||||||
2. It improves performance by avoiding unnecessary change detection runs while giving the developer
|
|
||||||
greater ability to customize.
|
|
||||||
3. It does not require you to change how you bootstrap your AngularJS app.
|
|
||||||
|
|
||||||
Using `downgradeModule()` is a good option for hybrid apps when you want to keep the AngularJS and
|
|
||||||
Angular parts less coupled. You can still mix and match components and services from both
|
|
||||||
frameworks, but you might need to manually propagate change detection. In return,
|
|
||||||
`downgradeModule()` offers more control and better performance.
|
|
@ -1,7 +1,7 @@
|
|||||||
# Upgrading from AngularJS to Angular
|
# Upgrading from AngularJS to Angular
|
||||||
|
|
||||||
_Angular_ is the name for the Angular of today and tomorrow.<br />
|
_Angular_ is the name for the Angular of today and tomorrow.
|
||||||
_AngularJS_ is the name for all 1.x versions of Angular.
|
_AngularJS_ is the name for all v1.x versions of Angular.
|
||||||
|
|
||||||
AngularJS apps are great.
|
AngularJS apps are great.
|
||||||
Always consider the business case before moving to Angular.
|
Always consider the business case before moving to Angular.
|
||||||
@ -195,7 +195,7 @@ transition period.
|
|||||||
|
|
||||||
### How ngUpgrade Works
|
### How ngUpgrade Works
|
||||||
|
|
||||||
One of the primary tools provided by ngUpgrade is called the `UpgradeModule`.
|
The primary tool provided by ngUpgrade is called the `UpgradeModule`.
|
||||||
This is a module that contains utilities for bootstrapping and managing hybrid
|
This is a module that contains utilities for bootstrapping and managing hybrid
|
||||||
applications that support both Angular and AngularJS code.
|
applications that support both Angular and AngularJS code.
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ frameworks in how it actually works.
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
Even accounting for these differences you can still have dependency injection
|
Even accounting for these differences you can still have dependency injection
|
||||||
interoperability. `upgrade/static` resolves the differences and makes
|
interoperability. The `UpgradeModule` resolves the differences and makes
|
||||||
everything work seamlessly:
|
everything work seamlessly:
|
||||||
|
|
||||||
* You can make AngularJS services available for injection to Angular code
|
* You can make AngularJS services available for injection to Angular code
|
||||||
@ -569,7 +569,7 @@ So, you can write an Angular component and then use it from AngularJS
|
|||||||
code. This is useful when you start to migrate from lower-level
|
code. This is useful when you start to migrate from lower-level
|
||||||
components and work your way up. But in some cases it is more convenient
|
components and work your way up. But in some cases it is more convenient
|
||||||
to do things in the opposite order: To start with higher-level components
|
to do things in the opposite order: To start with higher-level components
|
||||||
and work your way down. This too can be done using the `upgrade/static`.
|
and work your way down. This too can be done using the `UpgradeModule`.
|
||||||
You can *upgrade* AngularJS component directives and then use them from
|
You can *upgrade* AngularJS component directives and then use them from
|
||||||
Angular.
|
Angular.
|
||||||
|
|
||||||
@ -710,7 +710,7 @@ and then provide the input and output using Angular template syntax:
|
|||||||
When you are using a downgraded Angular component from an AngularJS
|
When you are using a downgraded Angular component from an AngularJS
|
||||||
template, the need may arise to *transclude* some content into it. This
|
template, the need may arise to *transclude* some content into it. This
|
||||||
is also possible. While there is no such thing as transclusion in Angular,
|
is also possible. While there is no such thing as transclusion in Angular,
|
||||||
there is a very similar concept called *content projection*. `upgrade/static`
|
there is a very similar concept called *content projection*. The `UpgradeModule`
|
||||||
is able to make these two features interoperate.
|
is able to make these two features interoperate.
|
||||||
|
|
||||||
Angular components that support content projection make use of an `<ng-content>`
|
Angular components that support content projection make use of an `<ng-content>`
|
||||||
|
@ -69,7 +69,7 @@ DOM event object in the `$event` variable which this code passes as a parameter
|
|||||||
|
|
||||||
|
|
||||||
The properties of an `$event` object vary depending on the type of DOM event. For example,
|
The properties of an `$event` object vary depending on the type of DOM event. For example,
|
||||||
a mouse event includes different information than an input box editing event.
|
a mouse event includes different information than a input box editing event.
|
||||||
|
|
||||||
All [standard DOM event objects](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
All [standard DOM event objects](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||||
have a `target` property, a reference to the element that raised the event.
|
have a `target` property, a reference to the element that raised the event.
|
||||||
|
801
aio/content/guide/webpack.md
Normal file
801
aio/content/guide/webpack.md
Normal file
@ -0,0 +1,801 @@
|
|||||||
|
# Webpack: An Introduction
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h4 {font-size: 17px !important; text-transform: none !important;}
|
||||||
|
.syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; }
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[**Webpack**](https://webpack.github.io/) is a popular module bundler,
|
||||||
|
a tool for bundling application source code in convenient _chunks_
|
||||||
|
and for loading that code from a server into a browser.
|
||||||
|
|
||||||
|
It's an excellent alternative to the *SystemJS* approach used elsewhere in the documentation.
|
||||||
|
This guide offers a taste of Webpack and explains how to use it with Angular applications.
|
||||||
|
|
||||||
|
|
||||||
|
{@a top}
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
|
||||||
|
# Contents
|
||||||
|
|
||||||
|
* [What is Webpack?](guide/webpack#what-is-webpack)
|
||||||
|
|
||||||
|
* [Entries and outputs](guide/webpack#entries-outputs)
|
||||||
|
* [Multiple bundles](guide/webpack#multiple-bundles)
|
||||||
|
* [Loaders](guide/webpack#loaders)
|
||||||
|
* [Plugins](guide/webpack#plugins)
|
||||||
|
|
||||||
|
* [Configuring Webpack](guide/webpack#configure-webpack)
|
||||||
|
|
||||||
|
* [Polyfills](guide/webpack#polyfills)
|
||||||
|
* [Common configuration](guide/webpack#common-configuration)
|
||||||
|
* [Inside `webpack.common.js`](guide/webpack#inside-webpack-commonjs)
|
||||||
|
|
||||||
|
* [entry](guide/webpack#common-entries)
|
||||||
|
* [resolve extension-less imports](guide/webpack#common-resolves)
|
||||||
|
* [`module.rules`](guide/webpack#common-rules)
|
||||||
|
* [Plugins](guide/webpack#plugins)
|
||||||
|
* [`CommonsChunkPlugin`](guide/webpack#commons-chunk-plugin)
|
||||||
|
* [`HtmlWebpackPlugin`](guide/webpack#html-webpack-plugin)
|
||||||
|
|
||||||
|
* [Environment specific configuration](guide/webpack#environment-configuration)
|
||||||
|
* [Development configuration](guide/webpack#development-configuration)
|
||||||
|
* [Production configuration](guide/webpack#production-configuration)
|
||||||
|
* [Test configuration](guide/webpack#test-configuration)
|
||||||
|
|
||||||
|
* [Trying it out](guide/webpack#try)
|
||||||
|
* [Highlights](guide/webpack#highlights)
|
||||||
|
* [Conclusion](guide/webpack#conclusion)
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
You can also <a href="generated/zips/webpack/webpack.zip" target="_blank">download the final result.</a>
|
||||||
|
|
||||||
|
{@a what-is-webpack}
|
||||||
|
|
||||||
|
## What is Webpack?
|
||||||
|
|
||||||
|
Webpack is a powerful module bundler.
|
||||||
|
A _bundle_ is a JavaScript file that incorporates _assets_ that *belong* together and
|
||||||
|
should be served to the client in a response to a single file request.
|
||||||
|
A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.
|
||||||
|
|
||||||
|
Webpack roams over your application source code,
|
||||||
|
looking for `import` statements, building a dependency graph, and emitting one or more _bundles_.
|
||||||
|
With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.
|
||||||
|
|
||||||
|
You determine what Webpack does and how it does it with a JavaScript configuration file, `webpack.config.js`.
|
||||||
|
|
||||||
|
|
||||||
|
{@a entries-outputs}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Entries and outputs
|
||||||
|
|
||||||
|
You supply Webpack with one or more *entry* files and let it find and incorporate the dependencies that radiate from those entries.
|
||||||
|
The one entry point file in this example is the application's root file, `src/main.ts`:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" region="one-entry" title="webpack.config.js (single entry)" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Webpack inspects that file and traverses its `import` dependencies recursively.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/src/app/app.component.ts" region="component" title="src/main.ts" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
It sees that you're importing `@angular/core` so it adds that to its dependency list for potential inclusion in the bundle.
|
||||||
|
It opens the `@angular/core` file and follows _its_ network of `import` statements until it has built the complete dependency graph from `main.ts` down.
|
||||||
|
|
||||||
|
Then it **outputs** these files to the `app.js` _bundle file_ designated in configuration:
|
||||||
|
|
||||||
|
<code-example name="webpack.config.js (single output)" language="javascript">
|
||||||
|
output: {
|
||||||
|
filename: 'app.js'
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
This `app.js` output bundle is a single JavaScript file that contains the application source and its dependencies.
|
||||||
|
You'll load it later with a `<script>` tag in the `index.html`.
|
||||||
|
|
||||||
|
|
||||||
|
{@a multiple-bundles}
|
||||||
|
|
||||||
|
|
||||||
|
#### Multiple bundles
|
||||||
|
You probably don't want one giant bundle of everything.
|
||||||
|
It's preferable to separate the volatile application app code from comparatively stable vendor code modules.
|
||||||
|
|
||||||
|
Change the configuration so that it has two entry points, `main.ts` and `vendor.ts`:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="javascript">
|
||||||
|
entry: {
|
||||||
|
app: 'src/app.ts',
|
||||||
|
vendor: 'src/vendor.ts'
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
filename: '[name].js'
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
Webpack constructs two separate dependency graphs
|
||||||
|
and emits *two* bundle files, one called `app.js` containing only the application code and
|
||||||
|
another called `vendor.js` with all the vendor dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The `[name]` in the output name is a *placeholder* that a Webpack plugin replaces with the entry names,
|
||||||
|
`app` and `vendor`. Plugins are [covered later](guide/webpack#commons-chunk-plugin) in the guide.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To tell Webpack what belongs in the vendor bundle,
|
||||||
|
add a `vendor.ts` file that only imports the application's third-party modules:
|
||||||
|
|
||||||
|
<code-example path="webpack/src/vendor.ts" title="src/vendor.ts" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a loaders}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Loaders
|
||||||
|
|
||||||
|
Webpack can bundle any kind of file: JavaScript, TypeScript, CSS, SASS, LESS, images, HTML, fonts, whatever.
|
||||||
|
Webpack _itself_ only understands JavaScript files.
|
||||||
|
Teach it to transform non-JavaScript file into their JavaScript equivalents with *loaders*.
|
||||||
|
Configure loaders for TypeScript and CSS as follows.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="javascript">
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
loader: 'awesome-typescript-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
loaders: 'style-loader!css-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
When Webpack encounters `import` statements like the following,
|
||||||
|
it applies the `test` RegEx patterns.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="typescript">
|
||||||
|
import { AppComponent } from './app.component.ts';
|
||||||
|
|
||||||
|
import 'uiframework/dist/uiframework.css';
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
When a pattern matches the filename, Webpack processes the file with the associated loader.
|
||||||
|
|
||||||
|
The first `import` file matches the `.ts` pattern so Webpack processes it with the `awesome-typescript-loader`.
|
||||||
|
The imported file doesn't match the second pattern so its loader is ignored.
|
||||||
|
|
||||||
|
The second `import` matches the second `.css` pattern for which you have *two* loaders chained by the (!) character.
|
||||||
|
Webpack applies chained loaders *right to left*. So it applies
|
||||||
|
the `css` loader first to flatten CSS `@import` and `url(...)` statements.
|
||||||
|
Then it applies the `style` loader to append the css inside `<style>` elements on the page.
|
||||||
|
|
||||||
|
|
||||||
|
{@a plugins}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Plugins
|
||||||
|
|
||||||
|
Webpack has a build pipeline with well-defined phases.
|
||||||
|
Tap into that pipeline with plugins such as the `uglify` minification plugin:
|
||||||
|
|
||||||
|
<code-example language="javascript">
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.UglifyJsPlugin()
|
||||||
|
]
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a configure-webpack}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Configuring Webpack
|
||||||
|
|
||||||
|
After that brief orientation, you are ready to build your own Webpack configuration for Angular apps.
|
||||||
|
|
||||||
|
Begin by setting up the development environment.
|
||||||
|
|
||||||
|
Create a new project folder.
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
mkdir angular-webpack
|
||||||
|
cd angular-webpack
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Add these files:
|
||||||
|
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="package.json" path="webpack/package.webpack.json">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/tsconfig.json" path="webpack/src/tsconfig.1.json">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="webpack.config.js" path="webpack/webpack.config.js">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="karma.conf.js" path="webpack/karma.webpack.conf.js">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="config/helpers.js" path="webpack/config/helpers.js">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Many of these files should be familiar from other Angular documentation guides,
|
||||||
|
especially the [Typescript configuration](guide/typescript-configuration) and
|
||||||
|
[npm packages](guide/npm-packages) guides.
|
||||||
|
|
||||||
|
Webpack, the plugins, and the loaders are also installed as packages.
|
||||||
|
They are listed in the updated `packages.json`.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Open a terminal window and install the npm packages.
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
npm install
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a polyfills}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Polyfills
|
||||||
|
|
||||||
|
You'll need polyfills to run an Angular application in most browsers as explained
|
||||||
|
in the [Browser Support](guide/browser-support) guide.
|
||||||
|
|
||||||
|
Polyfills should be bundled separately from the application and vendor bundles.
|
||||||
|
Add a `polyfills.ts` like this one to the `src/` folder.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/src/polyfills.ts" title="src/polyfills.ts" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="callout is-critical">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<header>
|
||||||
|
Loading polyfills
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Load `zone.js` early within `polyfills.ts`, immediately after the other ES6 and metadata shims.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Because this bundle file will load first, `polyfills.ts` is also a good place to configure the browser environment
|
||||||
|
for production or development.
|
||||||
|
|
||||||
|
|
||||||
|
{@a common-configuration}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Common configuration
|
||||||
|
|
||||||
|
Developers typically have separate configurations for development, production, and test environments.
|
||||||
|
All three have a lot of configuration in common.
|
||||||
|
|
||||||
|
Gather the common configuration in a file called `webpack.common.js`.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" title="config/webpack.common.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a inside-webpack-commonjs}
|
||||||
|
|
||||||
|
|
||||||
|
### Inside _webpack.common.js_
|
||||||
|
Webpack is a NodeJS-based tool that reads configuration from a JavaScript commonjs module file.
|
||||||
|
|
||||||
|
The configuration imports dependencies with `require` statements
|
||||||
|
and exports several objects as properties of a `module.exports` object.
|
||||||
|
|
||||||
|
* [`entry`](guide/webpack#common-entries)—the entry-point files that define the bundles.
|
||||||
|
* [`resolve`](guide/webpack#common-resolves)—how to resolve file names when they lack extensions.
|
||||||
|
* [`module.rules`](guide/webpack#common-rules)— `module` is an object with `rules` for deciding how files are loaded.
|
||||||
|
* [`plugins`](guide/webpack#common-plugins)—creates instances of the plugins.
|
||||||
|
|
||||||
|
|
||||||
|
{@a common-entries}
|
||||||
|
|
||||||
|
|
||||||
|
#### _entry_
|
||||||
|
|
||||||
|
The first export is the `entry` object:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" region="entries" title="config/webpack.common.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This `entry` object defines the three bundles:
|
||||||
|
|
||||||
|
* `polyfills`—the polyfills needed to run Angular applications in most modern browsers.
|
||||||
|
* `vendor`—the third-party dependencies such as Angular, lodash, and bootstrap.css.
|
||||||
|
* `app`—the application code.
|
||||||
|
|
||||||
|
|
||||||
|
{@a common-resolves}
|
||||||
|
|
||||||
|
|
||||||
|
#### _resolve_ extension-less imports
|
||||||
|
|
||||||
|
The app will `import` dozens if not hundreds of JavaScript and TypeScript files.
|
||||||
|
You could write `import` statements with explicit extensions like this example:
|
||||||
|
|
||||||
|
<code-example language="typescript">
|
||||||
|
import { AppComponent } from './app.component.ts';
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
But most `import` statements don't mention the extension at all.
|
||||||
|
Tell Webpack to resolve extension-less file requests by looking for matching files with
|
||||||
|
`.ts` extension or `.js` extension (for regular JavaScript files and pre-compiled TypeScript files).
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" region="resolve" title="config/webpack.common.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
If Webpack should resolve extension-less files for styles and HTML,
|
||||||
|
add `.css` and `.html` to the list.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a common-rules}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### _module.rules_
|
||||||
|
Rules tell Webpack which loaders to use for each file, or module:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" region="loaders" title="config/webpack.common.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* `awesome-typescript-loader`—a loader to transpile the Typescript code to ES5, guided by the `tsconfig.json` file.
|
||||||
|
* `angular2-template-loader`—loads angular components' template and styles.
|
||||||
|
* `html-loader`—for component templates.
|
||||||
|
* images/fonts—Images and fonts are bundled as well.
|
||||||
|
* CSS—the first pattern matches application-wide styles; the second handles
|
||||||
|
component-scoped styles (the ones specified in a component's `styleUrls` metadata property).
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The first pattern is for the application-wide styles. It excludes `.css` files within the `src/app` directory
|
||||||
|
where the component-scoped styles sit. The `ExtractTextPlugin` (described below) applies the `style` and `css`
|
||||||
|
loaders to these files.
|
||||||
|
|
||||||
|
The second pattern filters for component-scoped styles and loads them as strings via the `raw-loader`,
|
||||||
|
which is what Angular expects to do with styles specified in a `styleUrls` metadata property.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Multiple loaders can be chained using the array notation.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a common-plugins}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### _plugins_
|
||||||
|
Finally, create instances of three plugins:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.common.js" region="plugins" title="config/webpack.common.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a commons-chunk-plugin}
|
||||||
|
|
||||||
|
|
||||||
|
#### *CommonsChunkPlugin*
|
||||||
|
|
||||||
|
The `app.js` bundle should contain only application code. All vendor code belongs in the `vendor.js` bundle.
|
||||||
|
|
||||||
|
Of course the application code imports vendor code.
|
||||||
|
On its own, Webpack is not smart enough to keep the vendor code out of the `app.js` bundle.
|
||||||
|
The `CommonsChunkPlugin` does that job.
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The `CommonsChunkPlugin` identifies the hierarchy among three _chunks_: `app` -> `vendor` -> `polyfills`.
|
||||||
|
Where Webpack finds that `app` has shared dependencies with `vendor`, it removes them from `app`.
|
||||||
|
It would remove `polyfills` from `vendor` if they shared dependencies, which they don't.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a html-webpack-plugin}
|
||||||
|
|
||||||
|
|
||||||
|
#### _HtmlWebpackPlugin_
|
||||||
|
|
||||||
|
Webpack generates a number of js and CSS files.
|
||||||
|
You _could_ insert them into the `index.html` _manually_. That would be tedious and error-prone.
|
||||||
|
Webpack can inject those scripts and links for you with the `HtmlWebpackPlugin`.
|
||||||
|
|
||||||
|
|
||||||
|
{@a environment-configuration}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Environment-specific configuration
|
||||||
|
|
||||||
|
The `webpack.common.js` configuration file does most of the heavy lifting.
|
||||||
|
Create separate, environment-specific configuration files that build on `webpack.common`
|
||||||
|
by merging into it the peculiarities particular to the target environments.
|
||||||
|
|
||||||
|
These files tend to be short and simple.
|
||||||
|
|
||||||
|
|
||||||
|
{@a development-configuration}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Development configuration
|
||||||
|
|
||||||
|
Here is the `webpack.dev.js` development configuration file.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.dev.js" title="config/webpack.dev.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The development build relies on the Webpack development server, configured near the bottom of the file.
|
||||||
|
|
||||||
|
Although you tell Webpack to put output bundles in the `dist` folder,
|
||||||
|
the dev server keeps all bundles in memory; it doesn't write them to disk.
|
||||||
|
You won't find any files in the `dist` folder, at least not any generated from *this development build*.
|
||||||
|
|
||||||
|
|
||||||
|
The `HtmlWebpackPlugin`, added in `webpack.common.js`, uses the `publicPath` and the `filename` settings to generate
|
||||||
|
appropriate `<script>` and `<link>` tags into the `index.html`.
|
||||||
|
|
||||||
|
The CSS styles are buried inside the Javascript bundles by default. The `ExtractTextPlugin` extracts them into
|
||||||
|
external `.css` files that the `HtmlWebpackPlugin` inscribes as `<link>` tags into the `index.html`.
|
||||||
|
|
||||||
|
Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
|
||||||
|
other configuration options in this file.
|
||||||
|
|
||||||
|
Grab the app code at the end of this guide and try:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
npm start
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a production-configuration}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Production configuration
|
||||||
|
|
||||||
|
Configuration of a *production* build resembles *development* configuration with a few key changes.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.prod.js" title="config/webpack.prod.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
You'll deploy the application and its dependencies to a real production server.
|
||||||
|
You won't deploy the artifacts needed only in development.
|
||||||
|
|
||||||
|
Put the production output bundle files in the `dist` folder.
|
||||||
|
|
||||||
|
Webpack generates file names with cache-busting hash.
|
||||||
|
Thanks to the `HtmlWebpackPlugin`, you don't have to update the `index.html` file when the hash changes.
|
||||||
|
|
||||||
|
There are additional plugins:
|
||||||
|
|
||||||
|
* *`NoEmitOnErrorsPlugin`—stops the build if there is an error.
|
||||||
|
* *`UglifyJsPlugin`—minifies the bundles.
|
||||||
|
* *`ExtractTextPlugin`—extracts embedded css as external files, adding cache-busting hash to the filename.
|
||||||
|
* *`DefinePlugin`—use to define environment variables that you can reference within the application.
|
||||||
|
* *`LoaderOptionsPlugins`—to override options of certain loaders.
|
||||||
|
|
||||||
|
Thanks to the `DefinePlugin` and the `ENV` variable defined at top, you can enable Angular production mode like this:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/src/main.ts" region="enable-prod" title="src/main.ts" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Grab the app code at the end of this guide and try:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a test-configuration}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Test configuration
|
||||||
|
|
||||||
|
You don't need much configuration to run unit tests.
|
||||||
|
You don't need the loaders and plugins that you declared for your development and production builds.
|
||||||
|
You probably don't need to load and process the application-wide styles files for unit tests and doing so would slow you down;
|
||||||
|
you'll use the `null` loader for those CSS files.
|
||||||
|
|
||||||
|
You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need.
|
||||||
|
But it might be simpler to start over with a completely fresh configuration.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/webpack.test.js" title="config/webpack.test.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reconfigure [Karma](https://karma-runner.github.io/1.0/index.html) to use Webpack to run the tests:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/karma.conf.js" title="config/karma.conf.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
You don't precompile the TypeScript; Webpack transpiles the Typescript files on the fly, in memory, and feeds the emitted JS directly to Karma.
|
||||||
|
There are no temporary files on disk.
|
||||||
|
|
||||||
|
The `karma-test-shim` tells Karma what files to pre-load and
|
||||||
|
primes the Angular test framework with test versions of the providers that every app expects to be pre-loaded.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="webpack/config/karma-test-shim.js" title="config/karma-test-shim.js" linenums="false">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Notice that you do _not_ load the application code explicitly.
|
||||||
|
You tell Webpack to find and load the test files (the files ending in `.spec.ts`).
|
||||||
|
Each spec file imports all—and only—the application source code that it tests.
|
||||||
|
Webpack loads just _those_ specific application files and ignores the other files that you aren't testing.
|
||||||
|
|
||||||
|
|
||||||
|
Grab the app code at the end of this guide and try:
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
npm test
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
{@a try}
|
||||||
|
|
||||||
|
## Trying it out
|
||||||
|
|
||||||
|
Here is the source code for a small application that bundles with the
|
||||||
|
Webpack techniques covered in this guide.
|
||||||
|
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="src/index.html" path="webpack/src/index.html">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/main.ts" path="webpack/src/main.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/assets/css/styles.css" path="webpack/src/assets/css/styles.css">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="src/app/app.component.ts" path="webpack/src/app/app.component.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/app/app.component.html" path="webpack/src/app/app.component.html">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/app/app.component.css" path="webpack/src/app/app.component.css">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/app/app.component.spec.ts" path="webpack/src/app/app.component.spec.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/app/app.module.ts" path="webpack/src/app/app.module.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The <code>app.component.html</code> displays this downloadable Angular logo
|
||||||
|
<a href="assets/images/logos/angular/angular.png">
|
||||||
|
<img src="assets/images/logos/angular/angular.png" height="40px" title="download Angular logo"></a>.
|
||||||
|
Create a folder called `images` under the project's `assets` folder, then right-click (Cmd+click on Mac)
|
||||||
|
on the image and download it to that folder.
|
||||||
|
|
||||||
|
|
||||||
|
{@a bundle-ts}
|
||||||
|
|
||||||
|
|
||||||
|
Here again are the TypeScript entry-point files that define the `polyfills` and `vendor` bundles.
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="src/polyfills.ts" path="webpack/src/polyfills.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="src/vendor.ts" path="webpack/src/vendor.ts">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
{@a highlights}
|
||||||
|
|
||||||
|
<h3 class="no-toc">Highlights</h3>
|
||||||
|
|
||||||
|
* There are no `<script>` or `<link>` tags in the `index.html`.
|
||||||
|
The `HtmlWebpackPlugin` inserts them dynamically at runtime.
|
||||||
|
|
||||||
|
* The `AppComponent` in `app.component.ts` imports the application-wide css with a simple `import` statement.
|
||||||
|
|
||||||
|
* The `AppComponent` itself has its own html template and css file. WebPack loads them with calls to `require()`.
|
||||||
|
Webpack stashes those component-scoped files in the `app.js` bundle too.
|
||||||
|
You don't see those calls in the source code;
|
||||||
|
they're added behind the scenes by the `angular2-template-loader` plug-in.
|
||||||
|
|
||||||
|
* The `vendor.ts` consists of vendor dependency `import` statements that drive the `vendor.js` bundle.
|
||||||
|
The application imports these modules too; they'd be duplicated in the `app.js` bundle
|
||||||
|
if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `app.js`.
|
||||||
|
{@a conclusion}
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You've learned just enough Webpack to configurate development, test and production builds
|
||||||
|
for a small Angular application.
|
||||||
|
|
||||||
|
_You could always do more_. Search the web for expert advice and expand your Webpack knowledge.
|
||||||
|
|
||||||
|
[Back to top](guide/webpack#top)
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
@ -12,19 +12,5 @@
|
|||||||
"message": "Watch ng-conf live stream <br/>Apr 18th-20th, 2018",
|
"message": "Watch ng-conf live stream <br/>Apr 18th-20th, 2018",
|
||||||
"imageUrl": "generated/images/marketing/home/ng-conf.png",
|
"imageUrl": "generated/images/marketing/home/ng-conf.png",
|
||||||
"linkUrl": "https://www.ng-conf.org/livestream/"
|
"linkUrl": "https://www.ng-conf.org/livestream/"
|
||||||
},
|
|
||||||
{
|
|
||||||
"startDate": "2018-06-01",
|
|
||||||
"endDate": "2018-08-15",
|
|
||||||
"message": "Join us for Angular Mix<br/>October 10th-12th, 2018",
|
|
||||||
"imageUrl": "generated/images/marketing/home/angular-mix.png",
|
|
||||||
"linkUrl": "https://angularmix.com/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"startDate": "2018-08-15",
|
|
||||||
"endDate": "2018-11-06",
|
|
||||||
"message": "Join us for Angular Connect<br/>November 6th-7th, 2018",
|
|
||||||
"imageUrl": "generated/images/marketing/home/angular-connect.png",
|
|
||||||
"linkUrl": "https://angularconnect.com/"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -360,7 +360,7 @@
|
|||||||
"picture": "jorgeucano.jpg",
|
"picture": "jorgeucano.jpg",
|
||||||
"twitter": "jorgeucano",
|
"twitter": "jorgeucano",
|
||||||
"website": "https://medium.com/@jorgeucano",
|
"website": "https://medium.com/@jorgeucano",
|
||||||
"bio": "Jorge is a Full Stack Developer in ByteDefault, a professor for several courses related to JavaScript, a speaker, and an author of technical articles and the book \"Entendiendo Angular.\" He is a Google Developer Expert in web technologies (nominated by Google) and a NativeScript Developer Expert (nominated by Telerik).",
|
"bio": "Jorge is a Fulll Stack Developer in ByteDefault ... Professor in several courses related to javascript , speaker, and writer of technical articles and a book ‘Entendiendo Angular’, Google Developer Expert in web technologies nominate by Google, Nativescript Developer Expert nominated by Telerik.",
|
||||||
"group": "GDE"
|
"group": "GDE"
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -378,8 +378,8 @@
|
|||||||
"picture": "michaelprentice.jpg",
|
"picture": "michaelprentice.jpg",
|
||||||
"twitter": "splaktar",
|
"twitter": "splaktar",
|
||||||
"website": "https://www.DevIntent.com",
|
"website": "https://www.DevIntent.com",
|
||||||
"bio": "Lead for AngularJS Material. Owner and consultant at DevIntent. Ex-Angular GDE. Founder of the Google Developers Group (GDG) community on the Space Coast of Florida, USA.",
|
"bio": "Owner and consultant at DevIntent. Active open-source contributor and leader. Passionate advocate, coach, and consultant for LEAN and Agile teams. Google Developer Expert (GDE) in Angular. Founder and organizer for the Google Developers Group (GDG) community on the Space Coast of Florida, USA.",
|
||||||
"group": "Angular"
|
"group": "GDE"
|
||||||
},
|
},
|
||||||
|
|
||||||
"mikebrocchi": {
|
"mikebrocchi": {
|
||||||
@ -645,13 +645,5 @@
|
|||||||
"website": "https://kmaida.io/",
|
"website": "https://kmaida.io/",
|
||||||
"bio": "Kim is an an Angular consultant, developer, speaker, writer, and Google Developer Expert. She is passionate about learning from and sharing knowledge with other developers through blogging, speaking, workshops, and open source.",
|
"bio": "Kim is an an Angular consultant, developer, speaker, writer, and Google Developer Expert. She is passionate about learning from and sharing knowledge with other developers through blogging, speaking, workshops, and open source.",
|
||||||
"group": "GDE"
|
"group": "GDE"
|
||||||
},
|
|
||||||
|
|
||||||
"elanaolson": {
|
|
||||||
"name": "Elana Olson",
|
|
||||||
"picture": "elanaolson.jpg",
|
|
||||||
"twitter": "elanathellama",
|
|
||||||
"bio": "Elana is a Developer Relations intern on the Angular team at Google. She is working on migration paths from AngularJS to Angular and would love to chat about your experience with upgrading.",
|
|
||||||
"group": "Angular"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,12 +175,6 @@
|
|||||||
"rev": true,
|
"rev": true,
|
||||||
"title": "Angular IDE by Webclipse",
|
"title": "Angular IDE by Webclipse",
|
||||||
"url": "https://www.genuitec.com/products/angular-ide"
|
"url": "https://www.genuitec.com/products/angular-ide"
|
||||||
},
|
|
||||||
"amexio-canvas": {
|
|
||||||
"desc": "Amexio Canvas is Drag and Drop Environment to create Fully Responsive Web and Smart Device HTML5/Angular Apps. Code will be auto generated and hot deployed by the Canvas for live testing. Out of the box 50+ Material Design Theme support. Commit your code to GitHub public or private repository.",
|
|
||||||
"rev": true,
|
|
||||||
"title": "Amexio Canvas Web Based Drag and Drop IDE by MetaMagic",
|
|
||||||
"url": "https://amexio.tech/"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -490,13 +484,6 @@
|
|||||||
"rev": true,
|
"rev": true,
|
||||||
"title": "Angular-Buch (German)",
|
"title": "Angular-Buch (German)",
|
||||||
"url": "https://angular-buch.com/"
|
"url": "https://angular-buch.com/"
|
||||||
},
|
|
||||||
"wishtack-guide-angular": {
|
|
||||||
"desc": "The free, open-source and up-to-date Angular guide. This pragmatic guide is focused on best practices and will drive you from scratch to cloud.",
|
|
||||||
"logo": "https://raw.githubusercontent.com/wishtack/gitbook-guide-angular/master/.gitbook/assets/wishtack-logo-with-text.png",
|
|
||||||
"rev": true,
|
|
||||||
"title": "The Angular Guide by Wishtack (Français)",
|
|
||||||
"url": "https://guide-angular.wishtack.io/"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -612,12 +599,6 @@
|
|||||||
"title": "Ultimate Angular",
|
"title": "Ultimate Angular",
|
||||||
"url": "https://ultimateangular.com/"
|
"url": "https://ultimateangular.com/"
|
||||||
},
|
},
|
||||||
"willh-angular-zero": {
|
|
||||||
"desc": "Online video course in Chinese for newbies who need to learning from the scratch in Chinese. It's covering Angular, Angular CLI, TypeScript, VSCode, and some must known knowledge of Angular development.",
|
|
||||||
"rev": true,
|
|
||||||
"title": "Angular in Action: Start From Scratch (正體中文)",
|
|
||||||
"url": "https://www.udemy.com/angular-zero/?couponCode=ANGULAR.IO"
|
|
||||||
},
|
|
||||||
"angular-firebase": {
|
"angular-firebase": {
|
||||||
"desc": "Video lessons covering progressive web apps with Angular, Firebase, RxJS, and related APIs.",
|
"desc": "Video lessons covering progressive web apps with Angular, Firebase, RxJS, and related APIs.",
|
||||||
"rev": true,
|
"rev": true,
|
||||||
@ -641,12 +622,6 @@
|
|||||||
"title": "Angular Academy (Canada)",
|
"title": "Angular Academy (Canada)",
|
||||||
"url": "http://www.angularacademy.ca"
|
"url": "http://www.angularacademy.ca"
|
||||||
},
|
},
|
||||||
"at": {
|
|
||||||
"desc": "Angular Training teaches Angular on-site all over the world. Also provides consulting and mentoring.",
|
|
||||||
"rev": true,
|
|
||||||
"title": "Angular Training",
|
|
||||||
"url": "http://www.angulartraining.com"
|
|
||||||
},
|
|
||||||
"-KLIBo_lm-WrK1Sjtt-2": {
|
"-KLIBo_lm-WrK1Sjtt-2": {
|
||||||
"desc": "Basic and Advanced training across Europe in German",
|
"desc": "Basic and Advanced training across Europe in German",
|
||||||
"rev": true,
|
"rev": true,
|
||||||
@ -678,8 +653,8 @@
|
|||||||
"url": "http://ninja-squad.com/formations/formation-angular2"
|
"url": "http://ninja-squad.com/formations/formation-angular2"
|
||||||
},
|
},
|
||||||
"a2b": {
|
"a2b": {
|
||||||
"desc": "Angular Boot Camp covers introductory through advanced Angular topics. It includes extensive workshop sessions, with hands-on help from our experienced developer-trainers. We take developers or teams from the beginnings of Angular understanding through a working knowledge of all essential Angular features.",
|
"desc": "Angular Boot Camp covers introductory and intermediate content. It includes extensive workshop session, with hands-on help from our experienced developer-trainers. At the end of this class, student are usually able to use AngularJS to make an end-to-end, working application.",
|
||||||
"logo": "https://angularbootcamp.com/images/angular-boot-camp-logo.svg",
|
"logo": "",
|
||||||
"rev": true,
|
"rev": true,
|
||||||
"title": "Angular Boot Camp",
|
"title": "Angular Boot Camp",
|
||||||
"url": "https://angularbootcamp.com"
|
"url": "https://angularbootcamp.com"
|
||||||
|
@ -61,6 +61,12 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"url": "guide/webpack",
|
||||||
|
"title": "Webpack: An Introduction",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"url": "guide/quickstart",
|
"url": "guide/quickstart",
|
||||||
"title": "Getting Started",
|
"title": "Getting Started",
|
||||||
@ -514,11 +520,6 @@
|
|||||||
"title": "Upgrading Instructions",
|
"title": "Upgrading Instructions",
|
||||||
"tooltip": "Incrementally upgrade an AngularJS application to Angular."
|
"tooltip": "Incrementally upgrade an AngularJS application to Angular."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"url": "guide/upgrade-performance",
|
|
||||||
"title": "Upgrading for Performance",
|
|
||||||
"tooltip": "Upgrade from AngularJS to Angular in a more flexible way."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"url": "guide/ajs-quick-reference",
|
"url": "guide/ajs-quick-reference",
|
||||||
"title": "AngularJS-Angular Concepts",
|
"title": "AngularJS-Angular Concepts",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user