Compare commits
182 Commits
Author | SHA1 | Date | |
---|---|---|---|
cb339b87f3 | |||
fdcf877f83 | |||
5b5b9897c9 | |||
0e7365724e | |||
4ef1a3cd97 | |||
38b5ed05ea | |||
642c015f23 | |||
0977d95802 | |||
d374787db6 | |||
a634deb885 | |||
bcbd7ed8f0 | |||
f7de2be3f3 | |||
1e97d511c7 | |||
7e1e00c21e | |||
481f4b7412 | |||
4bc0084e5a | |||
b6864494a1 | |||
0021437ee1 | |||
d91ecd2c8b | |||
d0018e6bf6 | |||
587ca854cc | |||
8b9f03d9fa | |||
40f1f94fe0 | |||
2270467d60 | |||
8efda5b353 | |||
7b7f2d9c1b | |||
c469e25cf2 | |||
a21cde2960 | |||
9b774348b3 | |||
ce219ccfa2 | |||
53bbb01047 | |||
c6741bf36a | |||
cc06bf50f3 | |||
21e78ad022 | |||
05e855092b | |||
2817764433 | |||
145639d0f8 | |||
3eb327b67b | |||
be6af26dc1 | |||
637e81e9bb | |||
abc3cbb33f | |||
27eb8f2723 | |||
81671cea9a | |||
843fc7df9f | |||
cfe4732e41 | |||
48cabb44c7 | |||
9d0db2fe4b | |||
069146e7f3 | |||
fc895ba189 | |||
9a51528072 | |||
7fc38d4947 | |||
b1f84ec78f | |||
f351e8a5b1 | |||
ff2c342356 | |||
01b05b3f7c | |||
3b78f9eb0f | |||
f6ca619343 | |||
ab69c31fc5 | |||
38de40c9ec | |||
53352c40c3 | |||
dd3cab6eb1 | |||
ea1a3d3603 | |||
cf1b436010 | |||
cdcbb53a2d | |||
db2db6e7f5 | |||
1df6b16263 | |||
f4871212b7 | |||
2a23eca917 | |||
b5da4c6676 | |||
b8c2f3b93f | |||
75cf86e70f | |||
bf25165354 | |||
a2ba4448da | |||
ac6b2b4dc3 | |||
b6dffa9763 | |||
54b57def58 | |||
e2b3cc8118 | |||
5e701a2c88 | |||
27a3df146d | |||
8cce7efbb2 | |||
d225c3a6e3 | |||
b23582d57e | |||
d3c6e512a3 | |||
a873fab10c | |||
ecef0dd65e | |||
1cc74eaece | |||
e2b3be87cb | |||
3ca6c928f9 | |||
5933d16f3e | |||
0f839bcfd0 | |||
edda94edfa | |||
b5e36eaa3e | |||
08a1f51704 | |||
9690e36f78 | |||
68e741227b | |||
50a2327520 | |||
b07346c8e3 | |||
8e95849751 | |||
cd143f67af | |||
dd85351162 | |||
c1c68889de | |||
866f4be782 | |||
80e4019c83 | |||
d9f3316021 | |||
424a3b95aa | |||
7e883c2319 | |||
6a7fd70ddf | |||
73f9db53c2 | |||
2bf526bbfb | |||
8bd7d5befc | |||
aa163bea93 | |||
2f73c554c9 | |||
fb2d15fda1 | |||
018507fa02 | |||
95bb72d322 | |||
ce6e6c3f81 | |||
e4b1bdbfa0 | |||
6477c9e04a | |||
3f380b3b78 | |||
c4c0e9dbc5 | |||
4ddf57c58d | |||
624f01c311 | |||
6a713521e3 | |||
57a5ba3438 | |||
1b6fb5bc19 | |||
bd9da268c1 | |||
1e58a2194f | |||
da81c9cb54 | |||
ef6d26d4fa | |||
13bc1cd853 | |||
1fa1379318 | |||
d9efacc07e | |||
47f5b5f2d4 | |||
019fe77f64 | |||
a0e3a8e0f7 | |||
8908156eae | |||
2ee265fb1f | |||
116512b06d | |||
1d841973eb | |||
3694e1a38c | |||
88d8813ccc | |||
49bfb63442 | |||
48848c9ca4 | |||
a1f1ea993d | |||
be8a403bc9 | |||
c378402af4 | |||
91ce8c17ff | |||
786be967fd | |||
e88d5e0df2 | |||
f39f01e00b | |||
ce750e6f5b | |||
beba944843 | |||
50981cbb1f | |||
76e40eed35 | |||
d491a20f3b | |||
74c202a5cd | |||
483e8d28ec | |||
a6fd118f79 | |||
fe6e76c1e7 | |||
de560019f2 | |||
52ed53d071 | |||
5b72d4d676 | |||
c1aa1bf872 | |||
dad1bc7ca3 | |||
2109c30afe | |||
874919a25b | |||
c64e666755 | |||
1da403d8f3 | |||
60c5ebd46a | |||
b71d1987cd | |||
e6325eb9ef | |||
114519ab6a | |||
a9a095d44a | |||
5f9d574d4d | |||
baeb446392 | |||
0d1bfdc505 | |||
fa130e9445 | |||
194710fc1d | |||
6ae5e2b32a | |||
d85d396c26 | |||
1a25144297 | |||
449da8c18e |
@ -1,4 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
aio/content
|
||||
aio/node_modules
|
||||
aio/tools/examples/shared/node_modules
|
||||
integration/bazel
|
||||
|
2
.bazelrc
@ -33,7 +33,7 @@ test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test
|
||||
# eventually a surprising failure with auto-discovery of the C++ toolchain in
|
||||
# MacOS High Sierra.
|
||||
# See https://github.com/bazelbuild/bazel/issues/4603
|
||||
build --symlink_prefix=dist/
|
||||
build --symlink_prefix=/
|
||||
|
||||
# Performance: avoid stat'ing input files
|
||||
build --watchfs
|
||||
|
@ -2,6 +2,10 @@
|
||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Save downloaded repositories in a location that can be cached by CircleCI. This helps us
|
||||
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
|
||||
build --repository_cache=/home/circleci/bazel_repository_cache
|
||||
|
||||
# Don't be spammy in the logs
|
||||
# TODO(gmagolan): Hide progress again once build performance improves
|
||||
# Presently, CircleCI can timeout during bazel test ... with the following
|
||||
|
@ -11,16 +11,43 @@
|
||||
# needed for jobs that run tests without Bazel. Bazel runs tests with browsers that will be
|
||||
# fetched by the Webtesting rules. Therefore for jobs that run tests with Bazel, we don't need a
|
||||
# docker image with browsers pre-installed.
|
||||
# **NOTE**: If you change the version of the docker images, also change the `cache_key` suffix.
|
||||
# **NOTE 1**: If you change the version of the `*-browsers` docker image, make sure the
|
||||
# `CI_CHROMEDRIVER_VERSION_ARG` env var (in `.circleci/env.sh`) points to a ChromeDriver
|
||||
# version that is compatible with the Chrome version in the image.
|
||||
# **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix.
|
||||
var_1: &default_docker_image circleci/node:10.12
|
||||
var_2: &browsers_docker_image circleci/node:10.12-browsers
|
||||
var_3: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-10.12
|
||||
# We don't want to include the current branch name in the cache key because that would prevent
|
||||
# PRs from being able to restore the cache since the branch names are always different for PRs.
|
||||
# The cache key should only consist of dynamic values that change whenever something in the
|
||||
# cache changes. For example:
|
||||
# 1) yarn lock file changes --> cached "node_modules" are different.
|
||||
# 2) bazel repository definitions change --> cached bazel repositories are different.
|
||||
# **NOTE 1 **: If you change the cache key prefix, also sync the restore_cache fallback to match.
|
||||
# **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
|
||||
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
|
||||
var_3: &cache_key v3-angular-node-10.12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
|
||||
|
||||
# Define common ENV vars
|
||||
var_4: &define_env_vars
|
||||
# Initializes the CI environment by setting up common environment variables.
|
||||
var_4: &init_environment
|
||||
run:
|
||||
name: Define environment variables
|
||||
command: ./.circleci/env.sh
|
||||
name: Initializing environment (setting up variables, overwriting Yarn)
|
||||
# Overwrite the yarn installed in the docker container with our own version.
|
||||
command: |
|
||||
./.circleci/env.sh
|
||||
ourYarn=$(realpath ./third_party/github.com/yarnpkg/yarn/releases/download/v1.13.0/bin/yarn.js)
|
||||
sudo chmod a+x $ourYarn
|
||||
sudo ln -fs $ourYarn /usr/local/bin/yarn
|
||||
echo "Yarn version: $(yarn --version)"
|
||||
|
||||
# Add GitHub to known hosts.
|
||||
mkdir -p ~/.ssh
|
||||
echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts
|
||||
|
||||
# use git+ssh instead of https
|
||||
git config --global url."ssh://git@github.com".insteadOf "https://github.com" || true
|
||||
git config --global gc.auto 0 || true
|
||||
|
||||
|
||||
var_5: &setup_bazel_remote_execution
|
||||
run:
|
||||
@ -40,29 +67,97 @@ var_6: &job_defaults
|
||||
# Similar to travis behavior, but not quite the same.
|
||||
# See https://discuss.circleci.com/t/1662
|
||||
var_7: &post_checkout
|
||||
post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
|
||||
run:
|
||||
name: Post checkout step
|
||||
command: >
|
||||
if [[ -n "${CIRCLE_PR_NUMBER}" ]]; then
|
||||
# Fetch the head and merge commits for this PR.
|
||||
git fetch origin +refs/pull/$CIRCLE_PR_NUMBER/head:pr/$CIRCLE_PR_NUMBER/head
|
||||
git fetch origin +refs/pull/$CIRCLE_PR_NUMBER/merge:pr/$CIRCLE_PR_NUMBER/merge
|
||||
# Checkout the merged PR for testing as CircleCI will just use the PR head otherwise.
|
||||
git checkout -qf pr/$CIRCLE_PR_NUMBER/merge
|
||||
# Reset the merge commit into its PR head.
|
||||
git reset pr/$CIRCLE_PR_NUMBER/head
|
||||
# Commit the merge changes into the head of the PR.
|
||||
# This way we keep the last commit message.
|
||||
git config user.name "angular-ci"
|
||||
git config user.email "angular-ci"
|
||||
git commit . --amend --no-edit
|
||||
fi
|
||||
|
||||
var_8: &yarn_install
|
||||
run:
|
||||
name: Running Yarn install
|
||||
command: yarn install --frozen-lockfile --non-interactive
|
||||
command: |
|
||||
# Yarn's requests sometimes take more than 10mins to complete.
|
||||
# Print something to stdout, to prevent CircleCI from failing due to not output.
|
||||
while true; do sleep 60; echo "[`date`] Keeping alive..."; done &
|
||||
KEEP_ALIVE_PID=$!
|
||||
yarn install --frozen-lockfile --non-interactive
|
||||
kill $KEEP_ALIVE_PID
|
||||
|
||||
var_9: &setup_circleci_bazel_config
|
||||
run:
|
||||
name: Setting up CircleCI bazel configuration
|
||||
command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
|
||||
var_10: &restore_cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- *cache_key
|
||||
# This fallback should be the cache_key without variables.
|
||||
- v3-angular-node-10.12-
|
||||
|
||||
# Branch filter that can be specified for jobs that should only run on publish branches
|
||||
# (e.g. master or the patch branch)
|
||||
var_12: &publish_branches_filter
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
# e.g. 7.0.x, 7.1.x, etc.
|
||||
- /\d+\.\d+\.x/
|
||||
|
||||
# Workspace initially persisted by the `install` job, and then enhanced by `test_aio` and
|
||||
# `build-npm-packages`.
|
||||
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
|
||||
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
|
||||
var_13: &attach_workspace
|
||||
attach_workspace:
|
||||
at: ~/
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
setup:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout
|
||||
- *post_checkout
|
||||
# This cache is saved in the build-npm-packages so that Bazel cache is also included.
|
||||
- *restore_cache
|
||||
- *init_environment
|
||||
- *yarn_install
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
# Make the bazel directories and add a file to them if they don't exist already so that
|
||||
# persist_to_workspace does not fail.
|
||||
- run: |
|
||||
if [ ! -d ~/bazel_repository_cache ]; then
|
||||
mkdir ~/bazel_repository_cache
|
||||
touch ~/bazel_repository_cache/MARKER
|
||||
fi
|
||||
# Persist any changes at this point to be reused by further jobs.
|
||||
# **NOTE 1 **: Folders persisted here should be kept in sync with `var_13: &attach_workspace`.
|
||||
# **NOTE 2 **: To add new content to the workspace, always persist on the same root.
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- ./ng
|
||||
- ./bazel_repository_cache
|
||||
|
||||
lint:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
|
||||
- run: 'yarn bazel:format -mode=check ||
|
||||
(echo "BUILD files not formatted. Please run ''yarn bazel:format''" ; exit 1)'
|
||||
@ -70,19 +165,15 @@ jobs:
|
||||
- run: 'yarn bazel:lint ||
|
||||
(echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)'
|
||||
|
||||
- run: ./node_modules/.bin/gulp lint
|
||||
- run: yarn gulp lint
|
||||
|
||||
test:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
|
||||
# Setup remote execution and run RBE-compatible tests.
|
||||
- *setup_bazel_remote_execution
|
||||
@ -91,24 +182,14 @@ jobs:
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local
|
||||
|
||||
- save_cache:
|
||||
key: *cache_key
|
||||
paths:
|
||||
- "node_modules"
|
||||
- "~/bazel_repository_cache"
|
||||
|
||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||
test_ivy_aot:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
|
||||
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
||||
@ -141,11 +222,8 @@ jobs:
|
||||
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio
|
||||
- run: yarn --cwd aio build --progress=false
|
||||
# Lint the code
|
||||
@ -157,9 +235,9 @@ jobs:
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio payload-size
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --watch=false
|
||||
- run: yarn --cwd aio test --progress=false --watch=false
|
||||
# Run e2e tests
|
||||
- run: yarn --cwd aio e2e
|
||||
- run: yarn --cwd aio e2e --configuration=ci
|
||||
# Run unit tests for Firebase redirects
|
||||
- run: yarn --cwd aio redirects-test
|
||||
|
||||
@ -169,11 +247,8 @@ jobs:
|
||||
# Needed because before deploying the deploy-production script runs the PWA score tests.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Deploy angular.io to production (if necessary)
|
||||
- run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')"
|
||||
- run: yarn --cwd aio deploy-production
|
||||
@ -184,33 +259,31 @@ jobs:
|
||||
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio (with local Angular packages)
|
||||
- run: yarn --cwd aio build-local --progress=false
|
||||
# Run PWA-score tests
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --watch=false
|
||||
- run: yarn --cwd aio test --progress=false --watch=false
|
||||
# Run e2e tests
|
||||
- run: yarn --cwd aio e2e
|
||||
- run: yarn --cwd aio e2e --configuration=ci
|
||||
|
||||
test_aio_local_ivy:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio with Ivy (using local Angular packages)
|
||||
- run: yarn --cwd aio build-with-ivy --progress=false
|
||||
|
||||
test_aio_tools:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Install
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd aio extract-cli-command-docs
|
||||
@ -225,15 +298,8 @@ jobs:
|
||||
- image: *browsers_docker_image
|
||||
parallelism: 3
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
# Install root
|
||||
- *yarn_install
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Install aio
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
# Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
|
||||
@ -241,18 +307,30 @@ jobs:
|
||||
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
|
||||
- run: yarn --cwd aio example-e2e --setup --local --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
|
||||
|
||||
test_docs_examples_ivy:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the example e2e tests depend on Chrome.
|
||||
- image: *browsers_docker_image
|
||||
parallelism: 3
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Install aio
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
# Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
|
||||
# Since the parallelism is set to "3", there will be three parallel CircleCI containers
|
||||
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
|
||||
- run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
|
||||
|
||||
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
|
||||
aio_preview:
|
||||
<<: *job_defaults
|
||||
environment:
|
||||
AIO_SNAPSHOT_ARTIFACT_PATH: &aio_preview_artifact_path 'aio/tmp/snapshot.tgz'
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT
|
||||
- store_artifacts:
|
||||
path: *aio_preview_artifact_path
|
||||
@ -268,45 +346,64 @@ jobs:
|
||||
# Needed because the test-preview script runs e2e tests and the PWA score test with Chrome.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- run: yarn install --cwd aio --frozen-lockfile --non-interactive
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
- run:
|
||||
name: Wait for preview and run tests
|
||||
command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE
|
||||
|
||||
# This job exists only for backwards-compatibility with old scripts and tests
|
||||
# that rely on the pre-Bazel dist/packages-dist layout.
|
||||
# It duplicates some work with the job above: we build the bazel packages
|
||||
# twice. Even though we have a remote cache, these jobs will typically run in
|
||||
# parallel so up-to-date outputs will not be available at the time the build
|
||||
|
||||
# The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and
|
||||
# tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh).
|
||||
# Having multiple jobs that independently build in this manner duplicates some work; we build
|
||||
# the bazel packages more than once. Even though we have a remote cache, these jobs will
|
||||
# typically run in parallel so up-to-date outputs will not be available at the time the build
|
||||
# starts.
|
||||
# No new jobs should depend on this one.
|
||||
build-packages-dist:
|
||||
|
||||
# Build the view engine npm packages. No new jobs should depend on this.
|
||||
build-npm-packages:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
|
||||
- run: scripts/build-packages-dist.sh
|
||||
|
||||
# Save the npm packages from //packages/... for other workflow jobs to read
|
||||
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
|
||||
- persist_to_workspace:
|
||||
root: dist
|
||||
root: ~/
|
||||
paths:
|
||||
- packages-dist
|
||||
- packages-dist-ivy-aot
|
||||
- ng/dist/packages-dist
|
||||
|
||||
# Save dependencies and bazel repository cache to use on subsequent runs.
|
||||
- save_cache:
|
||||
key: *cache_key
|
||||
paths:
|
||||
- "node_modules"
|
||||
- "aio/node_modules"
|
||||
- "~/bazel_repository_cache"
|
||||
|
||||
# Build the ivy npm packages.
|
||||
build-ivy-npm-packages:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- *setup_circleci_bazel_config
|
||||
- *setup_bazel_remote_execution
|
||||
|
||||
- run: scripts/build-ivy-npm-packages.sh
|
||||
|
||||
# Save the npm packages from //packages/... for other workflow jobs to read
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- ng/dist/packages-dist-ivy-aot
|
||||
|
||||
# We run the integration tests outside of Bazel for now.
|
||||
# They are a separate workflow job so that they can be easily re-run.
|
||||
@ -325,13 +422,8 @@ jobs:
|
||||
# on a 4G worker so we use a larger machine here too.
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Runs the integration tests in parallel across multiple CircleCI container instances. The
|
||||
# amount of container nodes for this job is controlled by the "parallelism" option.
|
||||
- run: ./integration/run_tests.sh ${CIRCLE_NODE_INDEX} ${CIRCLE_NODE_TOTAL}
|
||||
@ -341,9 +433,8 @@ jobs:
|
||||
publish_snapshot:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# See below - ideally this job should not trigger for non-upstream builds.
|
||||
# But since it does, we have to check this condition.
|
||||
- run:
|
||||
@ -354,8 +445,6 @@ jobs:
|
||||
|| "$CI_REPO_OWNER" != "angular"
|
||||
|| "$CI_REPO_NAME" != "angular"
|
||||
]] && circleci step halt || true'
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
# CircleCI has a config setting to force SSH for all github connections
|
||||
# This is not compatible with our mechanism of using a Personal Access Token
|
||||
# Clear the global setting
|
||||
@ -372,35 +461,18 @@ jobs:
|
||||
# which does not load the browser through the Bazel webtesting rules.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run:
|
||||
name: Run tests against the deployed apps
|
||||
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE
|
||||
- run:
|
||||
name: Notify caretaker about failure
|
||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL'
|
||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL'
|
||||
when: on_fail
|
||||
|
||||
legacy-unit-tests-local:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- run: yarn tsc -p packages
|
||||
- run: yarn tsc -p packages/examples
|
||||
- run: yarn tsc -p modules
|
||||
- run: yarn karma start ./karma-js.conf.js --single-run --browsers=ChromeNoSandbox
|
||||
|
||||
legacy-unit-tests-saucelabs:
|
||||
<<: *job_defaults
|
||||
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
|
||||
@ -408,12 +480,8 @@ jobs:
|
||||
# and therefore the tunnel and Karma need to process a lot of file requests and tests.
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run:
|
||||
name: Preparing environment for running tests on Saucelabs.
|
||||
command: |
|
||||
@ -424,7 +492,6 @@ jobs:
|
||||
command: ./scripts/saucelabs/start-tunnel.sh
|
||||
background: true
|
||||
- run: yarn tsc -p packages
|
||||
- run: yarn tsc -p packages/examples
|
||||
- run: yarn tsc -p modules
|
||||
# Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests
|
||||
# too early without Saucelabs not being ready.
|
||||
@ -432,43 +499,11 @@ jobs:
|
||||
- run: yarn karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS}
|
||||
- run: ./scripts/saucelabs/stop-tunnel.sh
|
||||
|
||||
legacy-e2e-tests:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
# Build the e2e tests using the existing Bazel "packages-dist" output that has been
|
||||
# attached to this job. This avoids multiple rebuilds across various CI jobs.
|
||||
- run: ./scripts/build-e2e-tests.sh --use-existing-packages-dist
|
||||
- run:
|
||||
name: Starting servers for e2e tests
|
||||
command: yarn gulp serve serve-examples
|
||||
background: true
|
||||
- run: NODE_PATH=$NODE_PATH:./dist/all yarn protractor ./protractor-e2e.conf.js --bundles=true
|
||||
- run: NODE_PATH=$NODE_PATH:./dist/all yarn protractor ./protractor-examples-e2e.conf.js --bundles=true
|
||||
- run: NODE_PATH=$NODE_PATH:./dist/all yarn protractor ./protractor-perf.conf.js --bundles=true --dryrun
|
||||
|
||||
legacy-misc-tests:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
- run: yarn gulp check-cycle
|
||||
# TODO: disabled because the Bazel packages-dist does not seem to have map files for
|
||||
# the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966
|
||||
@ -478,32 +513,46 @@ workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- lint
|
||||
- test
|
||||
- test_ivy_aot
|
||||
- build-packages-dist
|
||||
- test_aio
|
||||
- legacy-unit-tests-local
|
||||
- legacy-unit-tests-saucelabs
|
||||
- setup
|
||||
- lint:
|
||||
requires:
|
||||
- setup
|
||||
- test:
|
||||
requires:
|
||||
- setup
|
||||
- test_ivy_aot:
|
||||
requires:
|
||||
- setup
|
||||
- build-npm-packages:
|
||||
requires:
|
||||
- setup
|
||||
- test_aio:
|
||||
requires:
|
||||
- setup
|
||||
- deploy_aio:
|
||||
requires:
|
||||
- test_aio
|
||||
- legacy-e2e-tests:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- legacy-misc-tests:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- build-npm-packages
|
||||
- test_aio_local:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- build-npm-packages
|
||||
# - test_aio_local_ivy:
|
||||
# requires:
|
||||
# - build-npm-packages
|
||||
- test_aio_tools:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- build-npm-packages
|
||||
- test_docs_examples:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- build-npm-packages
|
||||
# - test_docs_examples_ivy:
|
||||
# requires:
|
||||
# - build-npm-packages
|
||||
- aio_preview:
|
||||
requires:
|
||||
- setup
|
||||
# Only run on PR builds. (There can be no previews for non-PR builds.)
|
||||
filters:
|
||||
branches:
|
||||
@ -513,7 +562,7 @@ workflows:
|
||||
- aio_preview
|
||||
- integration_test:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- build-npm-packages
|
||||
- publish_snapshot:
|
||||
# Note: no filters on this job because we want it to run for all upstream branches
|
||||
# We'd really like to filter out pull requests here, but not yet available:
|
||||
@ -526,21 +575,36 @@ workflows:
|
||||
- integration_test
|
||||
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
|
||||
- test_aio_local
|
||||
# - test_aio_local_ivy
|
||||
- test_docs_examples
|
||||
# - test_docs_examples_ivy
|
||||
# Get the artifacts to publish from the build-packages-dist job
|
||||
# since the publishing script expects the legacy outputs layout.
|
||||
- build-packages-dist
|
||||
- legacy-e2e-tests
|
||||
- build-npm-packages
|
||||
- legacy-misc-tests
|
||||
- legacy-unit-tests-local
|
||||
- legacy-unit-tests-saucelabs
|
||||
|
||||
saucelabs_tests:
|
||||
jobs:
|
||||
- setup
|
||||
- legacy-unit-tests-saucelabs:
|
||||
requires:
|
||||
- setup
|
||||
triggers:
|
||||
- schedule:
|
||||
# Runs the Saucelabs legacy tests every hour. We still want to run Saucelabs
|
||||
# frequently as the caretaker needs up-to-date results when merging PRs or creating
|
||||
# a new release. Also we primarily moved the Saucelabs job into a cronjob that doesn't
|
||||
# run for PRs, in order to ensure that PRs are not affected by Saucelabs flakiness or
|
||||
# incidents. This is still guaranteed (even if we run the job every hour).
|
||||
cron: "0 * * * *"
|
||||
filters: *publish_branches_filter
|
||||
|
||||
aio_monitoring:
|
||||
jobs:
|
||||
- aio_monitoring
|
||||
triggers:
|
||||
- schedule:
|
||||
# Runs AIO monitoring job at 00:00AM every day.
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
|
@ -15,7 +15,7 @@
|
||||
#
|
||||
# Usage: `setPublicVar <name> <value>`
|
||||
function setPublicVar() {
|
||||
setSecretVar $1 $2;
|
||||
setSecretVar $1 "$2";
|
||||
echo "$1=$2";
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Variables
|
||||
readonly envHelpersPath="`dirname $0`/env-helpers.inc.sh";
|
||||
readonly getCommitRangePath="`dirname $0`/get-commit-range.js";
|
||||
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
|
||||
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
|
||||
readonly getCommitRangePath="$projectDir/.circleci/get-commit-range.js";
|
||||
|
||||
# Load helpers and make them available everywhere (through `$BASH_ENV`).
|
||||
source $envHelpersPath;
|
||||
@ -14,10 +15,15 @@ echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
####################################################################################################
|
||||
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
|
||||
####################################################################################################
|
||||
setPublicVar PROJECT_ROOT "$(pwd)";
|
||||
setPublicVar PROJECT_ROOT "$projectDir";
|
||||
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
|
||||
# This is the branch being built; e.g. `pull/12345` for PR builds.
|
||||
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
||||
# ChromeDriver version compatible with the Chrome version included in the docker image used in
|
||||
# `.circleci/config.yml`. See http://chromedriver.chromium.org/downloads for a list of versions.
|
||||
# This variable is intended to be passed as an arg to the `webdriver-manager update` command (e.g.
|
||||
# `"postinstall": "webdriver-manager update $CI_CHROMEDRIVER_VERSION_ARG"`).
|
||||
setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 2.45";
|
||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||
# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available (or can be
|
||||
# retrieved via `get-compare-url.js`), i.e. on push builds (a.k.a. non-PR, non-scheduled builds and
|
||||
@ -33,8 +39,6 @@ setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
####################################################################################################
|
||||
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
|
||||
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
|
||||
# Defined in https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||
setSecretVar CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL "$SLACK_CARETAKER_WEBHOOK_URL";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
|
7
.github/CODEOWNERS
vendored
@ -54,6 +54,7 @@
|
||||
# kara - Kara Erickson
|
||||
# kyliau - Keen Yee Liau
|
||||
# matsko - Matias Niemelä
|
||||
# mgechev - Minko Gechev
|
||||
# mhevery - Misko Hevery
|
||||
# ocombe - Olivier Combe
|
||||
# petebacondarwin - Pete Bacon Darwin
|
||||
@ -113,6 +114,7 @@
|
||||
# - alexeagle
|
||||
# - kyliau
|
||||
# - IgorMinar
|
||||
# - mgechev
|
||||
|
||||
|
||||
# ===========================================================
|
||||
@ -122,6 +124,7 @@
|
||||
# - alexeagle
|
||||
# - filipesilva
|
||||
# - hansl
|
||||
# - mgechev
|
||||
|
||||
|
||||
# ===========================================================
|
||||
@ -310,6 +313,8 @@
|
||||
# ===========================================================
|
||||
#
|
||||
# - alexeagle
|
||||
# - filipesilva
|
||||
# - gkalpak
|
||||
# - IgorMinar
|
||||
|
||||
|
||||
@ -726,6 +731,7 @@ testing/** @angular/fw-test
|
||||
# ================================================
|
||||
|
||||
/aio/content/marketing/** @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/bios/** @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/marketing/** @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/navigation.json @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/license.md @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -741,6 +747,7 @@ testing/** @angular/fw-test
|
||||
/.circleci/** @angular/fw-dev-infra
|
||||
/.github/** @angular/fw-dev-infra
|
||||
/docs/BAZEL.md @angular/fw-dev-infra
|
||||
/packages/* @angular/fw-dev-infra
|
||||
/scripts/** @angular/fw-dev-infra
|
||||
/third_party/** @angular/fw-dev-infra
|
||||
/tools/** @angular/fw-dev-infra
|
||||
|
7
.github/angular-robot.yml
vendored
@ -56,9 +56,9 @@ merge:
|
||||
- "**/.gitkeep"
|
||||
- "**/yarn.lock"
|
||||
- "**/package.json"
|
||||
- "**/third_party/**"
|
||||
- "**/tsconfig-build.json"
|
||||
- "**/tsconfig.json"
|
||||
- "**/rollup.config.js"
|
||||
- "**/BUILD.bazel"
|
||||
- "**/*.md"
|
||||
- "packages/**/integrationtest/**"
|
||||
@ -103,6 +103,11 @@ merge:
|
||||
requiredStatuses:
|
||||
- "ci/circleci: build"
|
||||
- "ci/circleci: lint"
|
||||
- "ci/circleci: publish_snapshot"
|
||||
- "ci/angular: size"
|
||||
- "cla/google"
|
||||
- "google3"
|
||||
|
||||
|
||||
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
|
||||
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
|
||||
|
50
CHANGELOG.md
@ -1,3 +1,53 @@
|
||||
<a name="7.2.7"></a>
|
||||
## [7.2.7](https://github.com/angular/angular/compare/7.2.6...7.2.7) (2019-02-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** pin browser repositories using [@npm](https://github.com/npm)_bazel_karma//:browser_repositories.bzl in bazel schematics ([#28896](https://github.com/angular/angular/issues/28896)) ([b686449](https://github.com/angular/angular/commit/b686449))
|
||||
* **core:** traverse and sanitize content of unsafe elements ([#28804](https://github.com/angular/angular/issues/28804)) ([fdcf877](https://github.com/angular/angular/commit/fdcf877)), closes [#25879](https://github.com/angular/angular/issues/25879) [#25879](https://github.com/angular/angular/issues/25879) [#26007](https://github.com/angular/angular/issues/26007) [#28427](https://github.com/angular/angular/issues/28427)
|
||||
* **language-service:** Fix completions for input/output with alias ([#28904](https://github.com/angular/angular/issues/28904)) ([d0018e6](https://github.com/angular/angular/commit/d0018e6)), closes [#27959](https://github.com/angular/angular/issues/27959)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.6"></a>
|
||||
## [7.2.6](https://github.com/angular/angular/compare/7.2.5...7.2.6) (2019-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** incorrect bundled metadata for static class member call expressions ([#28762](https://github.com/angular/angular/issues/28762)) ([ab69c31](https://github.com/angular/angular/commit/ab69c31)), closes [/github.com/angular/angular/blob/master/packages/core/src/change_detection/differs/keyvalue_differs.ts#L121](https://github.com//github.com/angular/angular/blob/master/packages/core/src/change_detection/differs/keyvalue_differs.ts/issues/L121) [#28741](https://github.com/angular/angular/issues/28741)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.5"></a>
|
||||
## [7.2.5](https://github.com/angular/angular/compare/7.2.4...7.2.5) (2019-02-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** diagnostics should respect "newLine" compiler option ([#28550](https://github.com/angular/angular/issues/28550)) ([ce750e6](https://github.com/angular/angular/commit/ce750e6))
|
||||
* **router:** redirect to root url when returned as UrlTree from guard ([#28271](https://github.com/angular/angular/issues/28271)) ([1e58a21](https://github.com/angular/angular/commit/1e58a21)), closes [#27845](https://github.com/angular/angular/issues/27845)
|
||||
* **router:** set href when routerLink is used on an 'area' element ([#28441](https://github.com/angular/angular/issues/28441)) ([d491a20](https://github.com/angular/angular/commit/d491a20)), closes [#28401](https://github.com/angular/angular/issues/28401)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.4"></a>
|
||||
## [7.2.4](https://github.com/angular/angular/compare/7.2.3...7.2.4) (2019-02-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** Bazel builder resolves with require.resolve() ([#28478](https://github.com/angular/angular/issues/28478)) ([d85d396](https://github.com/angular/angular/commit/d85d396))
|
||||
* **bazel:** fix integration test for bazel-schematics ([#28460](https://github.com/angular/angular/issues/28460)) ([449da8c](https://github.com/angular/angular/commit/449da8c))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* pngcrush all pngs ([#28479](https://github.com/angular/angular/issues/28479)) ([1a25144](https://github.com/angular/angular/commit/1a25144)), closes [#18243](https://github.com/angular/angular/issues/18243)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.3"></a>
|
||||
## [7.2.3](https://github.com/angular/angular/compare/7.2.2...7.2.3) (2019-01-30)
|
||||
|
||||
|
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014-2018 Google, Inc. http://angular.io
|
||||
Copyright (c) 2010-2019 Google LLC. http://angular.io/license
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
121
WORKSPACE
@ -1,17 +1,6 @@
|
||||
workspace(name = "angular")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load(
|
||||
"//packages/bazel:package.bzl",
|
||||
"rules_angular_dependencies",
|
||||
"rules_angular_dev_dependencies",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "b7a62250a3a73277ade0ce306d22f122365b513f5402222403e507f2f997d421",
|
||||
url = "https://github.com/bazelbuild/rules_go/releases/download/0.16.3/rules_go-0.16.3.tar.gz",
|
||||
)
|
||||
|
||||
# Uncomment for local bazel rules development
|
||||
#local_repository(
|
||||
@ -19,47 +8,29 @@ http_archive(
|
||||
# path = "../rules_nodejs",
|
||||
#)
|
||||
#local_repository(
|
||||
# name = "build_bazel_rules_typescript",
|
||||
# name = "npm_bazel_typescript",
|
||||
# path = "../rules_typescript",
|
||||
#)
|
||||
|
||||
# Angular Bazel users will call this function
|
||||
rules_angular_dependencies()
|
||||
|
||||
# Install transitive deps of rules_nodejs
|
||||
load("@build_bazel_rules_nodejs//:package.bzl", "rules_nodejs_dependencies")
|
||||
|
||||
rules_nodejs_dependencies()
|
||||
|
||||
# These are the dependencies only for us
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
# Install transitive deps of rules_typescript
|
||||
load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies")
|
||||
|
||||
rules_typescript_dependencies()
|
||||
|
||||
#
|
||||
# Point Bazel to WORKSPACEs that live in subdirectories
|
||||
#
|
||||
# Fetch rules_nodejs so we can install our npm dependencies
|
||||
http_archive(
|
||||
name = "rxjs",
|
||||
sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403",
|
||||
strip_prefix = "package/src",
|
||||
url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz",
|
||||
name = "build_bazel_rules_nodejs",
|
||||
sha256 = "1416d03823fed624b49a0abbd9979f7c63bbedfd37890ddecedd2fe25cccebc6",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.18.6/rules_nodejs-0.18.6.tar.gz"],
|
||||
)
|
||||
|
||||
# Point to the integration test workspace just so that Bazel doesn't descend into it
|
||||
# when expanding the //... pattern
|
||||
# Use a mock @npm repository while we are building angular from source
|
||||
# downstream. Angular will get its npm dependencies with in @ngdeps which
|
||||
# is setup in ng_setup_workspace().
|
||||
# TODO(gregmagolan): remove @ngdeps once angular is no longer build from source
|
||||
# downstream and have build use @npm for npm dependencies
|
||||
local_repository(
|
||||
name = "bazel_integration_test",
|
||||
path = "integration/bazel",
|
||||
name = "npm",
|
||||
path = "tools/npm_workspace",
|
||||
)
|
||||
|
||||
#
|
||||
# Load and install our dependencies downloaded above.
|
||||
#
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
||||
# Check the bazel version and download npm dependencies
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||
|
||||
# Bazel version must be at least v0.21.0 because:
|
||||
# - 0.21.0 Using --incompatible_strict_action_env flag fixes cache when running `yarn bazel`
|
||||
@ -72,48 +43,56 @@ Try running `yarn bazel` instead.
|
||||
|
||||
""")
|
||||
|
||||
# Setup the Node.js toolchain
|
||||
node_repositories(
|
||||
node_version = "10.9.0",
|
||||
package_json = ["//:package.json"],
|
||||
preserve_symlinks = True,
|
||||
yarn_version = "1.12.1",
|
||||
vendored_yarn = "@angular//third_party/github.com/yarnpkg/yarn/releases/download:v1.13.0",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "npm",
|
||||
path = "tools/npm_workspace",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains()
|
||||
|
||||
load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories")
|
||||
|
||||
web_test_repositories()
|
||||
|
||||
browser_repositories(
|
||||
chromium = True,
|
||||
firefox = True,
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
|
||||
|
||||
ts_setup_workspace()
|
||||
|
||||
load("@angular//:index.bzl", "ng_setup_workspace")
|
||||
# Setup the angular toolchain which installs npm dependencies into @ngdeps
|
||||
load("//tools:ng_setup_workspace.bzl", "ng_setup_workspace")
|
||||
|
||||
ng_setup_workspace()
|
||||
|
||||
##################################
|
||||
# Skylark documentation generation
|
||||
# Install all bazel dependencies of the @ngdeps npm packages
|
||||
load("@ngdeps//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
|
||||
|
||||
install_bazel_dependencies()
|
||||
|
||||
# Load angular dependencies
|
||||
load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
|
||||
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
# Load karma dependencies
|
||||
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
|
||||
|
||||
rules_karma_dependencies()
|
||||
|
||||
# Setup the rules_webtesting toolchain
|
||||
load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories")
|
||||
|
||||
web_test_repositories()
|
||||
|
||||
# Temporary work-around for https://github.com/angular/angular/issues/28681
|
||||
# TODO(gregmagolan): go back to @io_bazel_rules_webtesting browser_repositories
|
||||
load("@npm_bazel_karma//:browser_repositories.bzl", "browser_repositories")
|
||||
|
||||
browser_repositories()
|
||||
|
||||
# Setup the rules_typescript tooolchain
|
||||
load("@npm_bazel_typescript//:defs.bzl", "ts_setup_workspace")
|
||||
|
||||
ts_setup_workspace()
|
||||
|
||||
# Setup the rules_sass toolchain
|
||||
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
|
||||
|
||||
sass_repositories()
|
||||
|
||||
# Setup the skydoc toolchain
|
||||
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
|
||||
|
||||
skydoc_repositories()
|
||||
|
2
aio/.gitignore
vendored
@ -26,11 +26,13 @@
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.firebase/
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
debug.log
|
||||
firebase-debug.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
|
@ -104,6 +104,9 @@
|
||||
},
|
||||
"archive": {
|
||||
"browserTarget": "site:build:archive"
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -166,6 +169,11 @@
|
||||
"options": {
|
||||
"protractorConfig": "tests/e2e/protractor.conf.js",
|
||||
"devServerTarget": "site:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"devServerTarget": "site:serve:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
|
6
aio/content/examples/.gitignore
vendored
@ -57,7 +57,9 @@ dist/
|
||||
|
||||
# aot
|
||||
**/*.ngsummary.json
|
||||
upgrade-module/tsconfig-aot.json
|
||||
!rollup-config.js
|
||||
upgrade-module/rollup-config.js
|
||||
aot-compiler/**/*.d.ts
|
||||
aot-compiler/**/*.factory.d.ts
|
||||
upgrade-phonecat-2-hybrid/aot/**/*
|
||||
@ -84,5 +86,9 @@ upgrade-phonecat-2-hybrid/aot/**/*
|
||||
*stackblitz.no-link.html
|
||||
|
||||
# ngUpgrade testing
|
||||
upgrade-phonecat-1-typescript/tsconfig-aot.json
|
||||
upgrade-phonecat-1-typescript/rollup-config.js
|
||||
upgrade-phonecat-3-final/tsconfig-aot.json
|
||||
upgrade-phonecat-3-final/rollup-config.js
|
||||
!upgrade-phonecat-*/**/karma.conf.js
|
||||
!upgrade-phonecat-*/**/karma-test-shim.js
|
||||
|
@ -20,7 +20,7 @@ export class AppComponent {
|
||||
movies: IMovie[] = [];
|
||||
showImage = true;
|
||||
title = 'AngularJS to Angular Quick Ref Cookbook';
|
||||
toggleImage(event: UIEvent) {
|
||||
toggleImage(event?: UIEvent) {
|
||||
this.showImage = !this.showImage;
|
||||
this.eventType = (event && event.type) || 'not provided';
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
import { Injectable, Pipe, PipeTransform } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
@Injectable()
|
||||
// #docregion date-pipe
|
||||
@Pipe({name: 'date', pure: true})
|
||||
export class StringSafeDatePipe extends DatePipe implements PipeTransform {
|
||||
transform(value: any, format: string): string {
|
||||
value = typeof value === 'string' ?
|
||||
Date.parse(value) : value;
|
||||
return super.transform(value, format);
|
||||
}
|
||||
}
|
||||
// #enddocregion date-pipe
|
@ -19,6 +19,7 @@ import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component';
|
||||
import { HeroListAutoComponent } from './hero-list-auto.component';
|
||||
import { HomeComponent } from './home.component';
|
||||
import { AboutComponent } from './about.component';
|
||||
import { InsertRemoveComponent } from './insert-remove.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -56,6 +57,7 @@ import { AboutComponent } from './about.component';
|
||||
HeroListAutoCalcPageComponent,
|
||||
HeroListAutoComponent,
|
||||
HomeComponent,
|
||||
InsertRemoveComponent,
|
||||
AboutComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
|
@ -2,7 +2,7 @@
|
||||
<h1>My First Attribute Directive</h1>
|
||||
<!-- #docregion applied -->
|
||||
<p appHighlight>Highlight me!</p>
|
||||
<!-- #enddocregion applied, -->
|
||||
<!-- #enddocregion applied -->
|
||||
|
||||
<!-- #docregion color-1 -->
|
||||
<p appHighlight highlightColor="yellow">Highlighted in yellow</p>
|
||||
@ -11,4 +11,4 @@
|
||||
|
||||
<!-- #docregion color-2 -->
|
||||
<p appHighlight [highlightColor]="color">Highlighted with parent component's color</p>
|
||||
<!-- #enddocregion color-2 -->
|
||||
<!-- #enddocregion color-2 -->
|
@ -0,0 +1,3 @@
|
||||
<!-- #docregion unsupported -->
|
||||
<p app:Highlight>This is invalid</p>
|
||||
<!-- #enddocregion unsupported -->
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"e2e": [
|
||||
{
|
||||
"cmd": "yarn",
|
||||
"args": [
|
||||
"e2e",
|
||||
"--no-webdriver-update"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -19,20 +19,20 @@ const DifferentParent = Parent;
|
||||
// #enddocregion provide-the-parent
|
||||
// The `parentType` defaults to `Parent` when omitting the second parameter.
|
||||
// #docregion provide-the-parent
|
||||
const provideParent =
|
||||
export function provideParent
|
||||
// #enddocregion provide-parent, provide-the-parent
|
||||
// #docregion provide-parent
|
||||
(component: any, parentType?: any) => {
|
||||
(component: any, parentType?: any) {
|
||||
return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
|
||||
};
|
||||
}
|
||||
// #enddocregion provide-parent
|
||||
|
||||
// Simpler syntax version that always provides the component in the name of `Parent`.
|
||||
const provideTheParent =
|
||||
export function provideTheParent
|
||||
// #docregion provide-the-parent
|
||||
(component: any) => {
|
||||
(component: any) {
|
||||
return { provide: Parent, useExisting: forwardRef(() => component) };
|
||||
};
|
||||
}
|
||||
// #enddocregion provide-the-parent
|
||||
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"e2e": [
|
||||
{
|
||||
"cmd": "yarn",
|
||||
"args": [
|
||||
"e2e",
|
||||
"--no-webdriver-update"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -28,10 +28,7 @@ let checkLogForMessage = (message: string) => {
|
||||
expect(page.logList.getText()).toContain(message);
|
||||
};
|
||||
|
||||
// TODO(i): temorarily disable these tests because angular-in-memory-web-api is not compatible with rxjs v6 yet
|
||||
// and we don't have the backwards compatibility package yet.
|
||||
// Reenable after rxjs v6 compatibility package is out or angular-in-memory-web-api is compatible with rxjs v6
|
||||
xdescribe('Http Tests', function() {
|
||||
describe('Http Tests', function() {
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
@ -1,3 +1,12 @@
|
||||
{
|
||||
"projectType": "i18n"
|
||||
}
|
||||
"projectType": "i18n",
|
||||
"e2e": [
|
||||
{
|
||||
"cmd": "yarn",
|
||||
"args": [
|
||||
"e2e",
|
||||
"--no-webdriver-update"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -50,9 +50,10 @@
|
||||
|
||||
<div (keyup)="0">
|
||||
<h4>Template context: template reference variables (#customerInput):</h4>
|
||||
<label>Type something:
|
||||
<!-- #docregion template-reference-variable -->
|
||||
<input #customerInput>{{customerInput.value}}</label>
|
||||
<label>Type something:
|
||||
<input #customerInput>{{customerInput.value}}
|
||||
</label>
|
||||
<!-- #enddocregion template-reference-variable -->
|
||||
</div>
|
||||
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 14 KiB |
@ -13,8 +13,8 @@ import { AppComponent } from './app.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { TitleComponent } from './title.component';
|
||||
import { HighlightDirective } from './highlight.directive.1';
|
||||
import { TitleComponent } from './title.component.1';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
/* Routing Module */
|
||||
|
@ -1,10 +0,0 @@
|
||||
// #docregion
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({ name: 'awesome' })
|
||||
/** Precede the input string with the word "Awesome " */
|
||||
export class AwesomePipe implements PipeTransform {
|
||||
transform(phrase: string) {
|
||||
return phrase ? 'Awesome ' + phrase : '';
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
// #docplaster
|
||||
// Same directive name and selector as
|
||||
// HighlightDirective in parent AppModule
|
||||
// It selects for both input boxes and 'highlight' attr
|
||||
// and it highlights in blue instead of gold
|
||||
|
||||
// #docregion
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
|
||||
// Highlight the host element or any InputElement in blue
|
||||
@Directive({ selector: '[highlight], input' })
|
||||
export class ContactHighlightDirective {
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement.style.backgroundColor = 'powderblue';
|
||||
// #enddocregion
|
||||
console.log(`* Contact highlight called for ${el.nativeElement.tagName}`);
|
||||
// #docregion
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
|
||||
// Same directive name and selector as
|
||||
// HighlightDirective in parent AppRootModule
|
||||
// It selects for both input boxes and 'highlight' attr
|
||||
// and it highlights in beige instead of yellow
|
||||
@Directive({ selector: '[highlight]' })
|
||||
export class HighlightDirective {
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement.style.backgroundColor = 'beige';
|
||||
console.log(`* Hero highlight called for ${el.nativeElement.tagName}`);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import { UserService } from './user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-title',
|
||||
templateUrl: './title.component.html'
|
||||
templateUrl: './title.component.1.html'
|
||||
})
|
||||
export class TitleComponent {
|
||||
title = 'Angular Modules';
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"server": {
|
||||
"baseDir": "src",
|
||||
"routes": {
|
||||
"/node_modules": "node_modules"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `<h1>Hello {{name}}</h1>`
|
||||
})
|
||||
export class AppComponent { name = 'Angular'; }
|
@ -1,11 +0,0 @@
|
||||
// #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 { }
|
@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular Quickstart</title>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {color:#369;font-family: Arial,Helvetica,sans-serif;}
|
||||
</style>
|
||||
|
||||
<!-- Polyfills -->
|
||||
<!-- #docregion polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<!-- #enddocregion polyfills -->
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- #docregion my-app-->
|
||||
<my-app>Loading AppComponent content here ...</my-app>
|
||||
<!-- #enddocregion my-app-->
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,5 +0,0 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [ "es2015", "dom" ],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"description": "QuickStart",
|
||||
"files": [
|
||||
"src/app/app.component.ts",
|
||||
"src/app/app.module.ts",
|
||||
"src/main.ts",
|
||||
"src/index.html"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["quickstart"]
|
||||
}
|
@ -4,7 +4,7 @@ import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-crisis-list',
|
||||
templateUrl: './crisis-list.component.html',
|
||||
styleUrls: ['./crisis-list.component.css']
|
||||
templateUrl: './crisis-list.component.1.html',
|
||||
styleUrls: ['./crisis-list.component.1.css']
|
||||
})
|
||||
export class CrisisListComponent { }
|
@ -4,7 +4,7 @@ import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list',
|
||||
templateUrl: './hero-list.component.html',
|
||||
styleUrls: ['./hero-list.component.css']
|
||||
templateUrl: './hero-list.component.1.html',
|
||||
styleUrls: ['./hero-list.component.1.css']
|
||||
})
|
||||
export class HeroListComponent { }
|
@ -1,17 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('QuickStart E2E Tests', function () {
|
||||
|
||||
let expectedMsg = 'Hello Angular';
|
||||
|
||||
beforeEach(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it(`should display: ${expectedMsg}`, function () {
|
||||
expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
|
||||
});
|
||||
|
||||
});
|
@ -152,7 +152,7 @@
|
||||
<div [ngSwitch]="hero?.emotion">
|
||||
<app-happy-hero *ngSwitchCase="'happy'" [hero]="hero"></app-happy-hero>
|
||||
<app-sad-hero *ngSwitchCase="'sad'" [hero]="hero"></app-sad-hero>
|
||||
<app-confused-hero *ngSwitchCase="'app-confused'" [hero]="hero"></app-confused-hero>
|
||||
<app-confused-hero *ngSwitchCase="'confused'" [hero]="hero"></app-confused-hero>
|
||||
<app-unknown-hero *ngSwitchDefault [hero]="hero"></app-unknown-hero>
|
||||
</div>
|
||||
<!-- #enddocregion built-in, ngswitch -->
|
||||
|
@ -1,3 +1,2 @@
|
||||
// #docregion
|
||||
export * from './spinner.component';
|
||||
export * from './spinner.service';
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
|
||||
import { SpinnerService } from './spinner.service';
|
||||
|
||||
@Component({
|
||||
selector: 'toh-spinner',
|
||||
template: '<div>spinner</div>'
|
||||
})
|
||||
|
||||
export class SpinnerComponent implements OnDestroy, OnInit {
|
||||
constructor(private spinnerService: SpinnerService) { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
ngOnDestroy() { }
|
||||
}
|
@ -1,3 +1,2 @@
|
||||
// #docregion
|
||||
export * from './toast.component';
|
||||
export * from './toast.service';
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { ToastService } from './toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'toh-toast',
|
||||
template: '<div>toast</div>'
|
||||
})
|
||||
export class ToastComponent implements OnInit {
|
||||
constructor(toastService: ToastService) { }
|
||||
|
||||
ngOnInit() { }
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { ToastService } from '../../core';
|
||||
|
||||
@Component({
|
||||
selector: 'toh-toast',
|
||||
template: '<div>toast</div>'
|
||||
})
|
||||
export class ToastComponent implements OnInit {
|
||||
constructor(toastService: ToastService) { }
|
||||
|
||||
ngOnInit() { }
|
||||
}
|
@ -32,8 +32,6 @@
|
||||
height: 56px;
|
||||
padding: 0 16px 0 72px;
|
||||
padding-left: 8px;
|
||||
background-color: #673AB7;
|
||||
background: #0033FF;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/*#docregion*/
|
||||
.spinner {
|
||||
position: absolute;
|
||||
left: 7em;
|
||||
top: 20em;
|
||||
position: absolute;
|
||||
|
@ -32,8 +32,6 @@
|
||||
height: 56px;
|
||||
padding: 0 16px 0 72px;
|
||||
padding-left: 8px;
|
||||
background-color: #673AB7;
|
||||
background: #0033FF;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
|
@ -4,4 +4,7 @@ import { Component } from '@angular/core';
|
||||
selector: 'sg-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent { }
|
||||
export class AppComponent {
|
||||
|
||||
doSomething() {}
|
||||
}
|
||||
|
@ -4,4 +4,7 @@ import { Component } from '@angular/core';
|
||||
selector: 'sg-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent { }
|
||||
export class AppComponent {
|
||||
|
||||
onSavedTheDay(event$: any) { }
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ export class AppComponent implements AfterViewInit, OnInit {
|
||||
|
||||
currentHero: Hero;
|
||||
|
||||
deleteHero(hero: Hero) {
|
||||
deleteHero(hero?: Hero) {
|
||||
this.alert(`Delete ${hero ? hero.name : 'the hero'}.`);
|
||||
}
|
||||
|
||||
@ -105,18 +105,18 @@ export class AppComponent implements AfterViewInit, OnInit {
|
||||
|
||||
get nullHero(): Hero { return null; }
|
||||
|
||||
onClickMe(event: KeyboardEvent) {
|
||||
onClickMe(event?: KeyboardEvent) {
|
||||
let evtMsg = event ? ' Event target class is ' + (<HTMLElement>event.target).className : '';
|
||||
this.alert('Click me.' + evtMsg);
|
||||
}
|
||||
|
||||
onSave(event: KeyboardEvent) {
|
||||
onSave(event?: KeyboardEvent) {
|
||||
let evtMsg = event ? ' Event target is ' + (<HTMLElement>event.target).textContent : '';
|
||||
this.alert('Saved.' + evtMsg);
|
||||
if (event) { event.stopPropagation(); }
|
||||
}
|
||||
|
||||
onSubmit() {/* referenced but not used */}
|
||||
onSubmit(data: any) {/* referenced but not used */}
|
||||
|
||||
product = {
|
||||
name: 'frimfram',
|
||||
|
@ -97,7 +97,7 @@ export class HeroService {
|
||||
/** POST: add a new hero to the server */
|
||||
addHero (hero: Hero): Observable<Hero> {
|
||||
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
|
||||
tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)),
|
||||
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
|
||||
catchError(this.handleError<Hero>('addHero'))
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Introduction to modules
|
||||
|
||||
Angular apps are modular and Angular has its own modularity system called *NgModules*.
|
||||
Angular apps are modular and Angular has its own modularity system called *NgModules*.
|
||||
NgModules are containers for a cohesive block of code dedicated to an application domain, a workflow, or a closely related set of capabilities. They can contain components, service providers, and other code files whose scope is defined by the containing NgModule. They can import functionality that is exported from other NgModules, and export selected functionality for use by other NgModules.
|
||||
|
||||
Every Angular app has at least one NgModule class, [the *root module*](guide/bootstrapping), which is conventionally named `AppModule` and resides in a file named `app.module.ts`. You launch your app by *bootstrapping* the root NgModule.
|
||||
@ -27,7 +27,7 @@ Here's a simple root NgModule definition.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `export` property of `AppComponent` is included here for illustration; it isn't actually necessary in this example. A root NgModule has no reason to *export* anything because other modules don't need to *import* the root NgModule.
|
||||
`AppComponent` is included in the `exports` list here for illustration; it isn't actually necessary in this example. A root NgModule has no reason to *export* anything because other modules don't need to *import* the root NgModule.
|
||||
|
||||
</div>
|
||||
|
||||
@ -89,7 +89,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>
|
||||
|
||||
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>
|
||||
|
@ -41,6 +41,10 @@ when the user hovers over that element. You can apply it like this:
|
||||
|
||||
{@a write-directive}
|
||||
|
||||
Please note that directives _do not_ support namespaces.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" linenums="false" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||
|
||||
### Write the directive code
|
||||
|
||||
Create the directive class file in a terminal window with the CLI command [`ng generate directive`](cli/generate).
|
||||
|
@ -52,16 +52,16 @@ When all dependencies are in place, `AppComponent` displays the user information
|
||||
|
||||
## Limit service scope to a component subtree
|
||||
|
||||
An Angular application has multiple injectors, arranged in a tree hierarchy that parallels the component tree.
|
||||
Each injector creates a singleton instance of a dependency.
|
||||
An Angular application has multiple injectors, arranged in a tree hierarchy that parallels the component tree.
|
||||
Each injector creates a singleton instance of a dependency.
|
||||
That same instance is injected wherever that injector provides that service.
|
||||
A particular service can be provided and created at any level of the injector hierarchy,
|
||||
which means that there can be multiple instances of a service if it is provided by multiple injectors.
|
||||
|
||||
Dependencies provided by the root injector can be injected into *any* component *anywhere* in the application.
|
||||
In some cases, you might want to restrict service availability to a particular region of the application.
|
||||
Dependencies provided by the root injector can be injected into *any* component *anywhere* in the application.
|
||||
In some cases, you might want to restrict service availability to a particular region of the application.
|
||||
For instance, you might want to let users explicitly opt in to use a service,
|
||||
rather than letting the root injector provide it automatically.
|
||||
rather than letting the root injector provide it automatically.
|
||||
|
||||
You can limit the scope of an injected service to a *branch* of the application hierarchy
|
||||
by providing that service *at the sub-root component for that branch*.
|
||||
@ -146,34 +146,34 @@ and confirm that the three `HeroBioComponent` instances have their own cached he
|
||||
When a class requires a dependency, that dependency is added to the constructor as a parameter.
|
||||
When Angular needs to instantiate the class, it calls upon the DI framework to supply the dependency.
|
||||
By default, the DI framework searches for a provider in the injector hierarchy,
|
||||
starting at the component's local injector of the component, and if necessary bubbling up
|
||||
starting at the component's local injector of the component, and if necessary bubbling up
|
||||
through the injector tree until it reaches the root injector.
|
||||
|
||||
* The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor.
|
||||
* The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor.
|
||||
|
||||
* If no provider is found in the root injector, the DI framework returns null to the constructor.
|
||||
* If no provider is found in the root injector, the DI framework throws an error.
|
||||
|
||||
There are a number of options for modifying the default search behavior, using _parameter decorators_
|
||||
on the service-valued parameters of a class constructor.
|
||||
on the service-valued parameters of a class constructor.
|
||||
|
||||
{@a optional}
|
||||
|
||||
### Make a dependency `@Optional` and limit search with `@Host`
|
||||
|
||||
Dependencies can be registered at any level in the component hierarchy.
|
||||
When a component requests a dependency, Angular starts with that component's injector
|
||||
and walks up the injector tree until it finds the first suitable provider.
|
||||
Dependencies can be registered at any level in the component hierarchy.
|
||||
When a component requests a dependency, Angular starts with that component's injector
|
||||
and walks up the injector tree until it finds the first suitable provider.
|
||||
Angular throws an error if it can't find the dependency during that walk.
|
||||
|
||||
In some cases, you need to limit the search or accommodate a missing dependency.
|
||||
You can modify Angular's search behavior with the `@Host` and `@Optional` qualifying
|
||||
decorators on a service-valued parameter of the component's constructor.
|
||||
decorators on a service-valued parameter of the component's constructor.
|
||||
|
||||
* The `@Optional` property decorator tells Angular to return null when it can't find the dependency.
|
||||
|
||||
* The `@Host` property decorator stops the upward search at the *host component*.
|
||||
The host component is typically the component requesting the dependency.
|
||||
However, when this component is projected into a *parent* component,
|
||||
* The `@Host` property decorator stops the upward search at the *host component*.
|
||||
The host component is typically the component requesting the dependency.
|
||||
However, when this component is projected into a *parent* component,
|
||||
that parent component becomes the host. The following example covers this second case.
|
||||
|
||||
These decorators can be used individually or together, as shown in the example.
|
||||
@ -238,8 +238,8 @@ Here's `HeroBiosAndContactsComponent` in action.
|
||||
|
||||
|
||||
If you comment out the `@Host()` decorator, Angular walks up the injector ancestor tree
|
||||
until it finds the logger at the `AppComponent` level.
|
||||
The logger logic kicks in and the hero display updates
|
||||
until it finds the logger at the `AppComponent` level.
|
||||
The logger logic kicks in and the hero display updates
|
||||
with the "!!!" marker to indicate that the logger was found.
|
||||
|
||||
<figure>
|
||||
@ -254,7 +254,7 @@ the app throws an exception when it cannot find the required logger at the host
|
||||
|
||||
### Supply a custom provider with `@Inject`
|
||||
|
||||
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
|
||||
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/storage.service.ts" header="src/app/storage.service.ts">
|
||||
|
||||
@ -262,6 +262,8 @@ Using a custom provider allows you to provide a concrete implementation for impl
|
||||
|
||||
The `factory` function returns the `localStorage` property that is attached to the browser window object. The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency. This custom provider can now be overridden during testing with a mock API of `localStorage` instead of interactive with real browser APIs.
|
||||
|
||||
{@a skip}
|
||||
|
||||
### Modify the provider search with `@Self` and `@SkipSelf`
|
||||
|
||||
Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency.
|
||||
@ -291,7 +293,7 @@ The directive sets the background to a highlight color when the user mouses over
|
||||
DOM element to which the directive is applied.
|
||||
|
||||
Angular sets the constructor's `el` parameter to the injected `ElementRef`.
|
||||
(An `ElementRef` is a wrapper around a DOM element,
|
||||
(An `ElementRef` is a wrapper around a DOM element,
|
||||
whose `nativeElement` property exposes the DOM element for the directive to manipulate.)
|
||||
|
||||
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
|
||||
@ -332,7 +334,7 @@ Angular asks the injector for the service associated with `LoggerService`
|
||||
and assigns the returned value to the `logger` parameter.
|
||||
|
||||
If the injector has already cached an instance of the service associated with the token,
|
||||
it provides that instance.
|
||||
it provides that instance.
|
||||
If it doesn't, it needs to make one using the provider associated with the token.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
@ -346,7 +348,7 @@ If the search fails, the injector throws an error—unless the request was [
|
||||
|
||||
A new injector has no providers.
|
||||
Angular initializes the injectors it creates with a set of preferred providers.
|
||||
You have to configure providers for your own app-specific dependencies.
|
||||
You have to configure providers for your own app-specific dependencies.
|
||||
|
||||
|
||||
{@a defining-providers}
|
||||
@ -355,7 +357,7 @@ You have to configure providers for your own app-specific dependencies.
|
||||
### Defining providers
|
||||
|
||||
A dependency can't always be created by the default method of instantiating a class.
|
||||
You learned about some other methods in [Dependency Providers](guide/dependency-injection-providers).
|
||||
You learned about some other methods in [Dependency Providers](guide/dependency-injection-providers).
|
||||
The following `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why you need them.
|
||||
It's visually simple: a few properties and the logs produced by a logger.
|
||||
|
||||
@ -364,7 +366,7 @@ It's visually simple: a few properties and the logs produced by a logger.
|
||||
</figure>
|
||||
|
||||
The code behind it customizes how and where the DI framework provides dependencies.
|
||||
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
|
||||
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" header="hero-of-the-month.component.ts">
|
||||
|
||||
@ -389,13 +391,13 @@ The `HeroOfTheMonthComponent` example has two value providers.
|
||||
</code-example>
|
||||
|
||||
* The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than
|
||||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||
Here, the token is the class itself.
|
||||
|
||||
* The second specifies a literal string resource to use for the `TITLE` token.
|
||||
The `TITLE` provider token is *not* a class, but is instead a
|
||||
special kind of provider lookup key called an [injection token](guide/dependency-injection-in-action#injection-token), represented by
|
||||
an `InjectionToken` instance.
|
||||
an `InjectionToken` instance.
|
||||
|
||||
You can use an injection token for any kind of provider but it's particularly
|
||||
helpful when the dependency is a simple value like a string, a number, or a function.
|
||||
@ -414,12 +416,12 @@ Other types of providers can create their values *lazily*; that is, when they're
|
||||
{@a useclass}
|
||||
|
||||
|
||||
#### Class providers: `useClass`
|
||||
#### Class providers: `useClass`
|
||||
|
||||
The `useClass` provider key lets you create and return a new instance of the specified class.
|
||||
|
||||
You can use this type of provider to substitute an *alternative implementation*
|
||||
for a common or default class.
|
||||
for a common or default class.
|
||||
The alternative implementation could, for example, implement a different strategy,
|
||||
extend the default class, or emulate the behavior of the real class in a test case.
|
||||
|
||||
@ -502,7 +504,7 @@ This is illustrated in the following image, which displays the logging date.
|
||||
|
||||
{@a usefactory}
|
||||
|
||||
#### Factory providers: `useFactory`
|
||||
#### Factory providers: `useFactory`
|
||||
|
||||
The `useFactory` provider key lets you create a dependency object by calling a factory function,
|
||||
as in the following example.
|
||||
@ -537,7 +539,7 @@ the passed-in state value and the injected services `Hero` and `HeroService`.
|
||||
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
||||
the string of names.
|
||||
|
||||
* The function takes a winning `Hero` and a `HeroService` as arguments.
|
||||
* The function takes a winning `Hero` and a `HeroService` as arguments.
|
||||
Angular supplies these arguments from injected values identified by
|
||||
the two *tokens* in the `deps` array.
|
||||
|
||||
@ -588,7 +590,7 @@ But they did neither.
|
||||
`MinimalLogger` is used only as a dependency injection token.
|
||||
|
||||
When you use a class this way, it's called a *class interface*.
|
||||
|
||||
|
||||
As mentioned in [DI Providers](guide/dependency-injection-providers#interface-not-valid-token),
|
||||
an interface is not a valid DI token because it is a TypeScript artifact that doesn't exist at run time.
|
||||
Use this abstract class interface to get the strong typing of an interface,
|
||||
@ -609,7 +611,7 @@ The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for
|
||||
</code-example>
|
||||
|
||||
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
||||
as long as those members are typed but not implemented.
|
||||
as long as those members are typed but not implemented.
|
||||
|
||||
Look again at the TypeScript `MinimalLogger` class to confirm that it has no implementation.
|
||||
|
||||
@ -736,7 +738,7 @@ Break the circularity with `forwardRef`.
|
||||
</code-example>
|
||||
|
||||
|
||||
<!--- Waiting for good examples
|
||||
<!--- Waiting for good examples
|
||||
|
||||
{@a directive-level-providers}
|
||||
|
||||
@ -744,15 +746,15 @@ Break the circularity with `forwardRef`.
|
||||
|
||||
## Element-level providers
|
||||
|
||||
A component is a specialization of directive, and the `@Component()` decorator inherits the `providers` property from `@Directive`. The injector is at the element level, so a provider configured with any element-level injector is available to any component, directive, or pipe attached to the same element.
|
||||
A component is a specialization of directive, and the `@Component()` decorator inherits the `providers` property from `@Directive`. The injector is at the element level, so a provider configured with any element-level injector is available to any component, directive, or pipe attached to the same element.
|
||||
|
||||
Here's a live example that implements a custom form control, taking advantage of an injector that is shared by a component and a directive on the same element.
|
||||
|
||||
https://stackblitz.com/edit/basic-form-control
|
||||
|
||||
The component, `custom-control`, configures a provider for the DI token `NG_VALUE_ACCESSOR`.
|
||||
The component, `custom-control`, configures a provider for the DI token `NG_VALUE_ACCESSOR`.
|
||||
In the template, the `FormControlName` directive is instantiated along with the custom component.
|
||||
It can inject the `NG_VALUE_ACCESSOR` dependency because they share the same injector.
|
||||
It can inject the `NG_VALUE_ACCESSOR` dependency because they share the same injector.
|
||||
(Notice that this example also makes use of `forwardRef()` to resolve a circularity in the definitions.)
|
||||
|
||||
### Sharing a service among components
|
||||
@ -784,4 +786,3 @@ If you want to show only one of them, use the directive to make sure __??of what
|
||||
`<hero-overview heroCache></hero-overview>`
|
||||
|
||||
--->
|
||||
|
||||
|
@ -182,8 +182,7 @@ Child modules and component injectors are independent of each other, and create
|
||||
|
||||
Thanks to [injector inheritance](guide/hierarchical-dependency-injection),
|
||||
you can still inject application-wide services into these components.
|
||||
A component's injector is a child of its parent component's injector,
|
||||
and a descendent of its parent's parent's injector, and so on all the way back to the application's _root_ injector. Angular can inject a service provided by any injector in that lineage.
|
||||
A component's injector is a child of its parent component's injector, and inherits from all ancestor injectors all the way back to the application's _root_ injector. Angular can inject a service provided by any injector in that lineage.
|
||||
|
||||
For example, Angular can inject `HeroListComponent` with both the `HeroService` provided in `HeroComponent` and the `UserService` provided in `AppModule`.
|
||||
|
||||
|
@ -149,7 +149,7 @@ In either style, the template data bindings have the same access to the componen
|
||||
Although this example uses variable assignment to initialize the components, you could instead declare and initialize the properties using a constructor:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app-ctor.component.ts" linenums="false" region="class">
|
||||
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" linenums="false" region="class">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
@ -42,7 +42,7 @@ Learn more about dependency resolution through the injector hierarchy:
|
||||
|
||||
*NgModule-level* providers can be specified with `@NgModule()` `providers` metadata option, or in the `@Injectable()` `providedIn` option (with some module other than the root `AppModule`).
|
||||
|
||||
Use the `@NgModule()` `provides` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app.
|
||||
Use the `@NgModule()` `providers` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app.
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
|
@ -476,7 +476,7 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
|
||||
<code-example
|
||||
path="http/src/app/package-search/package-search.component.ts"
|
||||
region="debounce"
|
||||
header="app/package-search/package-search.component.ts (excerpt))">
|
||||
header="app/package-search/package-search.component.ts (excerpt)">
|
||||
</code-example>
|
||||
|
||||
The `searchText$` is the sequence of search-box values coming from the user.
|
||||
@ -865,6 +865,9 @@ with the `reportProgress` option set true to enable tracking of progress events.
|
||||
|
||||
Every progress event triggers change detection, so only turn them on if you truly intend to report progress in the UI.
|
||||
|
||||
When using [`HttpClient#request()`](api/common/http/HttpClient#request) with an HTTP method, configure with
|
||||
[`observe: 'events'`](api/common/http/HttpClient#request) to see all events, including the progress of transfers.
|
||||
|
||||
</div>
|
||||
|
||||
Next, pass this request object to the `HttpClient.request()` method, which
|
||||
|
@ -896,11 +896,11 @@ Replace the contents of each component with the sample HTML below.
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/crisis-list/crisis-list.component.html" path="router/src/app/crisis-list/crisis-list.component.html">
|
||||
<code-pane header="src/app/crisis-list/crisis-list.component.html" path="router/src/app/crisis-list/crisis-list.component.1.html">
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/hero-list/hero-list.component.html" path="router/src/app/hero-list/hero-list.component.html" region="template">
|
||||
<code-pane header="src/app/hero-list/hero-list.component.html" path="router/src/app/hero-list/hero-list.component.1.html" region="template">
|
||||
|
||||
</code-pane>
|
||||
|
||||
@ -972,7 +972,7 @@ Be sure it is the _last_ route in the configuration.
|
||||
|
||||
To test this feature, add a button with a `RouterLink` to the `HeroListComponent` template and set the link to `"/sidekicks"`.
|
||||
|
||||
<code-example path="router/src/app/hero-list/hero-list.component.html" linenums="false" header="src/app/hero-list/hero-list.component.html (excerpt)">
|
||||
<code-example path="router/src/app/hero-list/hero-list.component.1.html" linenums="false" header="src/app/hero-list/hero-list.component.html (excerpt)">
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -1239,11 +1239,11 @@ Here are the files discussed in this milestone.
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="hero-list/hero-list.component.html" path="router/src/app/hero-list/hero-list.component.html">
|
||||
<code-pane header="hero-list/hero-list.component.html" path="router/src/app/hero-list/hero-list.component.1.html">
|
||||
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="crisis-list/crisis-list.component.html" path="router/src/app/crisis-list/crisis-list.component.html">
|
||||
<code-pane header="crisis-list/crisis-list.component.html" path="router/src/app/crisis-list/crisis-list.component.1.html">
|
||||
|
||||
</code-pane>
|
||||
|
||||
@ -2242,10 +2242,10 @@ This file does the following:
|
||||
|
||||
You could also create more transitions for other routes. This trigger is sufficient for the current milestone.
|
||||
|
||||
Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInDownAnimation` from
|
||||
Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInAnimation` from
|
||||
`'./animations.ts`.
|
||||
|
||||
Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`.
|
||||
Add an `animations` array to the `@Component` metadata's that contains the `slideInAnimation`.
|
||||
|
||||
<code-example path="router/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (animations)" region="animation-imports">
|
||||
|
||||
|
@ -50,6 +50,9 @@ script will never be registered with the browser.
|
||||
You can avoid that by waiting for the app to stabilize first, before starting to poll for updates
|
||||
(as shown in the example above).
|
||||
|
||||
Note that this is true for any kind of polling done by your application.
|
||||
Check the {@link ApplicationRef#isStable isStable} documentation for more information.
|
||||
|
||||
</div>
|
||||
|
||||
### Forcing update activation
|
||||
|
@ -301,7 +301,7 @@ an administrator ever needs to deactivate the service worker quickly.
|
||||
### Fail-safe
|
||||
|
||||
To deactivate the service worker, remove or rename the
|
||||
`ngsw-config.json` file. When the service worker's request
|
||||
`ngsw.json` file. When the service worker's request
|
||||
for `ngsw.json` returns a `404`, then the service worker
|
||||
removes all of its caches and de-registers itself,
|
||||
essentially self-destructing.
|
||||
|
@ -23,7 +23,7 @@ Just run the [`ng test`](cli/test) CLI command:
|
||||
</code-example>
|
||||
|
||||
The `ng test` command builds the app in _watch mode_,
|
||||
and launches the [karma test runner](https://karma-runner.github.io).
|
||||
and launches the [Karma test runner](https://karma-runner.github.io).
|
||||
|
||||
The console output looks a bit like this:
|
||||
|
||||
@ -55,15 +55,15 @@ The tests run again, the browser refreshes, and the new test results appear.
|
||||
|
||||
#### Configuration
|
||||
|
||||
The CLI takes care of Jasmine and karma configuration for you.
|
||||
The CLI takes care of Jasmine and Karma configuration for you.
|
||||
|
||||
You can fine-tune many options by editing the `karma.conf.js` and
|
||||
the `test.ts` files in the `src/` folder.
|
||||
|
||||
The `karma.conf.js` file is a partial karma configuration file.
|
||||
The `karma.conf.js` file is a partial Karma configuration file.
|
||||
The CLI constructs the full runtime configuration in memory, based on application structure specified in the `angular.json` file, supplemented by `karma.conf.js`.
|
||||
|
||||
Search the web for more details about Jasmine and karma configuration.
|
||||
Search the web for more details about Jasmine and Karma configuration.
|
||||
|
||||
#### Other test frameworks
|
||||
|
||||
@ -2650,10 +2650,10 @@ It takes two arguments: the component type to override (`HeroDetailComponent`) a
|
||||
The [override metadata object](#metadata-override-object) is a generic defined as follows:
|
||||
|
||||
<code-example format="." language="javascript">
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
};
|
||||
</code-example>
|
||||
|
||||
@ -2816,7 +2816,7 @@ Consider adding component tests such as this one:
|
||||
|
||||
Debug specs in the browser in the same way that you debug an application.
|
||||
|
||||
1. Reveal the karma browser window (hidden earlier).
|
||||
1. Reveal the Karma browser window (hidden earlier).
|
||||
1. Click the **DEBUG** button; it opens a new browser tab and re-runs the tests.
|
||||
1. Open the browser's “Developer Tools” (`Ctrl-Shift-I` on windows; `Command-Option-I` in OSX).
|
||||
1. Pick the "sources" section.
|
||||
@ -3008,10 +3008,10 @@ appropriate to the method, that is, the parameter of an `@NgModule`,
|
||||
`@Component`, `@Directive`, or `@Pipe`.
|
||||
|
||||
<code-example format="." language="javascript">
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
};
|
||||
</code-example>
|
||||
|
||||
|
@ -34,7 +34,21 @@ For details about `tsconfig.json`, see the official
|
||||
|
||||
The [Setup](guide/setup) guide uses the following `tsconfig.json`:
|
||||
|
||||
<code-example path="quickstart/src/tsconfig.1.json" header="tsconfig.json" linenums="false"></code-example>
|
||||
<code-example lang="json" header="tsconfig.json" linenums="false">
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [ "es2015", "dom" ],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
}
|
||||
}
|
||||
</code-example>
|
||||
|
||||
This file contains options and flags that are essential for Angular applications.
|
||||
|
||||
|
@ -17,9 +17,6 @@ For an example, see [Angular Material](https://material.angular.io/) docs.
|
||||
|
||||
Library packages often include typings in `.d.ts` files; see examples in `node_modules/@angular/material`. If your library's package does not include typings and your IDE complains, you may need to install the library's associated `@types/<lib_name>` package.
|
||||
|
||||
To configure a library that does not include typings in the same package, install the related `@types` package with npm.
|
||||
TypeScript looks for types in the `node_modules/@types` folder by default, so you don't have to add each type package individually.
|
||||
|
||||
For example, suppose you have a library named `d3`:
|
||||
|
||||
<code-example format="." language="bash">
|
||||
@ -27,15 +24,8 @@ npm install d3 --save
|
||||
npm install @types/d3 --save-dev
|
||||
</code-example>
|
||||
|
||||
Types defined in the library need to be added to the TypeScript configuration for the project that uses it.
|
||||
|
||||
* Add the library to the "types" array in `src/tsconfig.app.json`.
|
||||
|
||||
```
|
||||
"types":[
|
||||
"d3"
|
||||
]
|
||||
```
|
||||
Types defined in a `@types/` package for a library installed into the workspace are automatically added to the TypeScript configuration for the project that uses that library.
|
||||
TypeScript looks for types in the `node_modules/@types` folder by default, so you don't have to add each type package individually.
|
||||
|
||||
If a library doesn't have typings available at `@types/`, you can still use it by manually adding typings for it.
|
||||
To do this:
|
||||
|
Before Width: | Height: | Size: 350 KiB After Width: | Height: | Size: 343 KiB |
BIN
aio/content/images/bios/keilla.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
aio/content/images/bios/leonardo.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
aio/content/images/bios/mira.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
aio/content/images/bios/sharon.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 20 KiB |
BIN
aio/content/images/guide/forms-overview/dataflow-reactive-forms-mtv.png
Executable file → Normal file
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 14 KiB |
BIN
aio/content/images/guide/forms-overview/dataflow-reactive-forms-vtm.png
Executable file → Normal file
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 14 KiB |
BIN
aio/content/images/guide/forms-overview/dataflow-td-forms-mtv.png
Executable file → Normal file
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 26 KiB |