angular/aio/content/examples/examples.bzl

240 lines
11 KiB
Python
Raw Normal View History

load("@build_bazel_rules_nodejs//:index.bzl", "npm_package_bin")
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load("//tools:defaults.bzl", "nodejs_test")
load("//:yarn.bzl", "YARN_LABEL")
load("//:packages.bzl", "AIO_EXAMPLE_PACKAGES", "to_package_label")
# This map controls which examples are included and whether or not to generate
# a stackblitz live examples and zip archives. Keys are the example name, and values
# take the form:
#
# {"stackblitz": boolean, "zip": boolean}
#
# Set "stackblitz" to True to generate live examples from any stackblitz config files
# found in the example. Set "zip" to True to generate archives for any stackblitz or
# zipper configuration file found in the example.
#
# To ignore an example, comment out its row.
EXAMPLES = {
"accessibility": {"stackblitz": True, "zip": True},
"ajs-quick-reference": {"stackblitz": True, "zip": True},
"angular-compiler-options": {"stackblitz": True, "zip": True},
"animations": {"stackblitz": True, "zip": True},
"architecture": {"stackblitz": True, "zip": True},
"attribute-binding": {"stackblitz": True, "zip": True},
"attribute-directives": {"stackblitz": True, "zip": True},
"binding-syntax": {"stackblitz": True, "zip": True},
"bootstrapping": {"stackblitz": True, "zip": True},
"built-in-directives": {"stackblitz": True, "zip": True},
"built-in-template-functions": {"stackblitz": True, "zip": True},
"comparing-observables": {"stackblitz": False, "zip": False},
"component-interaction": {"stackblitz": True, "zip": True},
"component-overview": {"stackblitz": True, "zip": True},
"component-styles": {"stackblitz": True, "zip": True},
"content-projection": {"stackblitz": True, "zip": True},
"dependency-injection": {"stackblitz": True, "zip": True},
"dependency-injection-in-action": {"stackblitz": True, "zip": True},
"deprecation-guide": {"stackblitz": True, "zip": True},
"docs-style-guide": {"stackblitz": True, "zip": True},
"dynamic-component-loader": {"stackblitz": True, "zip": True},
"dynamic-form": {"stackblitz": True, "zip": True},
"elements": {"stackblitz": True, "zip": True},
"event-binding": {"stackblitz": True, "zip": True},
"feature-modules": {"stackblitz": True, "zip": True},
"first-app-lesson-00": {"stackblitz": True, "zip": True},
"first-app-lesson-01": {"stackblitz": True, "zip": True},
"first-app-lesson-02": {"stackblitz": True, "zip": True},
"first-app-lesson-03": {"stackblitz": True, "zip": True},
"first-app-lesson-04": {"stackblitz": True, "zip": True},
"first-app-lesson-05": {"stackblitz": True, "zip": True},
"first-app-lesson-06": {"stackblitz": True, "zip": True},
"first-app-lesson-07": {"stackblitz": True, "zip": True},
"first-app-lesson-08": {"stackblitz": True, "zip": True},
"first-app-lesson-09": {"stackblitz": True, "zip": True},
"first-app-lesson-10": {"stackblitz": True, "zip": True},
"first-app-lesson-11": {"stackblitz": True, "zip": True},
"first-app-lesson-12": {"stackblitz": True, "zip": True},
"first-app-lesson-13": {"stackblitz": True, "zip": True},
"first-app-lesson-14": {"stackblitz": True, "zip": True},
"form-validation": {"stackblitz": True, "zip": True},
"forms": {"stackblitz": True, "zip": True},
"forms-overview": {"stackblitz": True, "zip": True},
"getting-started": {"stackblitz": True, "zip": True},
"getting-started-v0": {"stackblitz": True, "zip": True},
"hierarchical-dependency-injection": {"stackblitz": True, "zip": True},
"http": {"stackblitz": True, "zip": True},
"i18n": {"stackblitz": True, "zip": True},
"inputs-outputs": {"stackblitz": True, "zip": True},
"injection-token": {"stackblitz": False, "zip": False},
"interpolation": {"stackblitz": True, "zip": True},
"lazy-loading-ngmodules": {"stackblitz": True, "zip": True},
"lifecycle-hooks": {"stackblitz": True, "zip": True},
"ngcontainer": {"stackblitz": True, "zip": True},
"ngmodules": {"stackblitz": True, "zip": True},
"observables": {"stackblitz": False, "zip": False},
"observables-in-angular": {"stackblitz": False, "zip": False},
"pipes": {"stackblitz": True, "zip": True},
"practical-observable-usage": {"stackblitz": False, "zip": False},
"property-binding": {"stackblitz": True, "zip": True},
"providers": {"stackblitz": True, "zip": True},
"providers-viewproviders": {"stackblitz": True, "zip": True},
"reactive-forms": {"stackblitz": True, "zip": True},
"resolution-modifiers": {"stackblitz": True, "zip": True},
"router": {"stackblitz": True, "zip": True},
"router-tutorial": {"stackblitz": True, "zip": True},
"routing-with-urlmatcher": {"stackblitz": True, "zip": True},
docs: Migrate Observables guides & code examples to standalone (#51516) None of the guide pages mentions ngModules. Only `observables-in-angular` needed conversion to Standalone. However, some of the guide pages reflect old versions of RxJS, including signatures that are no longer valid. These have been corrected. More significantly, *the existing guide is pretty bad at explaining RxJS and its usage*. It was written (by me I think) in the very early days of Angular and Angular RxJS instruction. I've taught numerous "RxJS in Angular" classes since and learned from that experience what does and does not work with students. There was neither the time nor the charter to completely overhaul this guide. But this commit attempts to remove what flops with students and to bring the teaching closer to what seems more effectively. I hope reviewers agree that my revisions are an improvement. **Revised Overview** The overview doc, `observables.md`, had a few errors (ex: `next` is NOT REQUIRED) and deprecated patterns (you now must pass the Observer object to `subscribe`). More importantly, it was wildly overcomplicated and scary, especially when it got into multi-casting. Moved the multi-casting section to "RxJS Library" and rewrote it (with working example) for simplicity and context. I made other changes in an effort to make this an overview that is more comprehensive and more clear. I paid particular attention to the "Basic usage and terms" section. Finally, I relocated the "Naming conventions for observables" section here from `rx-library`. This is the section that describes the dollar-sign convention. It made more sense for it to be here. **Revised "RxJS Library" page and code** *RxJS no longer supports chaining* and hasn't for a very long time. Removed note in `rx-library.md` that suggested you could use operator chaining. The RxJS `pipe` discussion in the "Operators" section was just weird. Almost no one calls the `pipe` function. We certainly should *start* there. We should start with how people actually use operators - by adding them to the argument list of the `Observable.pipe()` method. I kept the original `pipe` function example but subordinated it in a "callout". Most readers will (and should) ignore it. `Subject` is a *critically important RxJS mechanism for creating custom observables*. It was completely missing from the list of observable creators on this guide page. So I added it to the "Observable creation functions" section of the guide and wrote an accompanying `MessageService` code sample (see the new `rx-library/app/` folder). The `MessageService` is a pretty common pattern in Angular apps - far more common than creating an observable from a counter or an event, two of the creation patterns currently on this page. This new section also afforded an opportunity to show how RxJS helps with building loosely coupled applications. We will soon be talking about Signals. Many will wonder whether and when they should still use RxJS. At least a partial answer is that RxJS is really good at progressively combining and enhancing streams of data as they cross component boundaries. Of course you can pass signals around; but they are not as rich in transformers as RxJS. This is where RxJS shines. **Revised "Comparing observables"** The Promises section in `comparing-observables.md` had many errors and misleading remarks. The comparison of error handling was especially egregious; the code example for that was nonsense. The "Chain" sub-section was really about transforming values. It also failed to demonstrate chaining promise `.then`s. Reworked these sub-sections and improved the code samples to match. PR Close #51516
2023-08-25 09:06:52 +00:00
"rx-library": {"stackblitz": True, "zip": True},
"schematics-for-libraries": {"stackblitz": False, "zip": True},
"security": {"stackblitz": True, "zip": True},
docs: Migrate Service Worker to Standalone (#51687) Although there are several pages, only `service-worker-getting-started.md` has an example. That example code was migrated. Worked around the few references to NgModule. Other changes as follows: **Revised "Getting Started"** The original service worker example page (`service-worker-getting-started.md`) is full of holes! I don’t know how anyone got this working just by following this page - it doesn’t tell you where to get the example (and it isn’t generated by AIO) - it doesn’t tell you that ng serve doesn’t support service worker apps - it mentions http-server in passing but not what that is or where to get it. - several commands tell you to supply the “project-name” but (a) it doesn’t tell you how to find that name and (b) you never actually have to provide a name at all. That includes on the command that gets http-server going. **Hid section on `ngsw-config` tool** Hid the discussion of the `ngsw-config` tool in `service-worker-config.md` because (a) the command invoke it didn't seem to work and (b) it referenced `<project-name>` without explaining what that is or where to find it. Left the hidden text in the page in case someone wants to do something about this. Meanwhile, you seem to be able to edit the `ngsw-config.json` and then rebuild. That should suffice. **Disabled E2E** The AIO CI will no longer attempt to run the (thin) E2E tests. These tests could lightly test the app with the dev server but couldn't test the Service Worker aspects; that would require launching the app with something other than `ng serve` and the AIO CI is not set up for that. The existing tests appeared to pass when run locally with the dev server. However, only one of them actually ran; test runner reported. "There were tests whose specified size is too big." Decided to bypass E2E testing of this project for now. PR Close #51687
2023-09-06 19:18:30 +00:00
"service-worker-getting-started": {"stackblitz": False, "zip": True},
"setup": {"stackblitz": False, "zip": False},
"structural-directives": {"stackblitz": True, "zip": True},
"styleguide": {"stackblitz": False, "zip": False},
"template-expression-operators": {"stackblitz": True, "zip": True},
"template-reference-variables": {"stackblitz": True, "zip": True},
"template-syntax": {"stackblitz": True, "zip": True},
"testing": {"stackblitz": True, "zip": True},
"toh-pt0": {"stackblitz": True, "zip": True},
"toh-pt1": {"stackblitz": True, "zip": True},
"toh-pt2": {"stackblitz": True, "zip": True},
"toh-pt3": {"stackblitz": True, "zip": True},
"toh-pt4": {"stackblitz": True, "zip": True},
"toh-pt5": {"stackblitz": True, "zip": True},
"toh-pt6": {"stackblitz": True, "zip": True},
"two-way-binding": {"stackblitz": True, "zip": True},
"ssr": {"stackblitz": False, "zip": True},
"upgrade-lazy-load-ajs": {"stackblitz": False, "zip": True},
"upgrade-module": {"stackblitz": False, "zip": False},
"upgrade-phonecat-1-typescript": {"stackblitz": False, "zip": False},
"upgrade-phonecat-2-hybrid": {"stackblitz": False, "zip": False},
"upgrade-phonecat-3-final": {"stackblitz": False, "zip": False},
"user-input": {"stackblitz": True, "zip": True},
"view-encapsulation": {"stackblitz": True, "zip": True},
"what-is-angular": {"stackblitz": True, "zip": True},
}
def docs_example(name, test = True, test_tags = [], test_exec_properties = {}, flaky = False):
"""Stamp targets for adding boilerplate to examples, creating live examples, and creating zips.
Args:
name: name of the example
test: whether to run e2e tests
test_tags: tags to add to the test target
test_exec_properties: exec properties to add to the test's execution platform
"""
if name not in EXAMPLES:
# buildifier: disable=print
print("WARNING: Example '%s' is being ignored. To include it, add an entry to the EXAMPLES map in aio/content/examples/examples.bzl." % name)
return
native.filegroup(
name = "files",
srcs = native.glob(["**"], exclude = [
"**/node_modules/**", # Node modules may exist from the legacy setup.
]),
)
# Generate example boilerplate
npm_package_bin(
name = "boilerplate",
args = ["add", native.package_name(), "$(@D)"],
data = [":files"],
output_dir = True,
tool = "//aio/tools/examples:example-boilerplate",
)
# Copy example files and boilerplate to the output tree
copy_to_directory(
name = name,
# Prevent sorting so that boilerplate overwrites example sources
# buildifier: do not sort
srcs = [
":files",
":boilerplate",
],
replace_prefixes = {
"boilerplate": "",
"aio/tools/examples/shared": "",
},
allow_overwrites = True,
)
stackblitz_configs = native.glob(["*stackblitz.json"])
if EXAMPLES[name]["stackblitz"] and len(stackblitz_configs) > 0:
# Generate stackblitz live example(s)
outs = [file_name.replace(".json", ".html") for file_name in stackblitz_configs]
npm_package_bin(
name = "stackblitz",
args = [
"$(execpath :%s)" % name,
"$(RULEDIR)",
],
data = [":%s" % name],
outs = outs,
tool = "//aio/tools/stackblitz-builder:generate-stackblitz",
)
zip_configs = stackblitz_configs + native.glob(["zipper.json"])
if EXAMPLES[name]["zip"] and len(zip_configs) > 0:
# Generate example zip(s)
outs = [file_name.replace("stackblitz", name).replace("zipper", name).replace(".json", ".zip") for file_name in zip_configs]
npm_package_bin(
name = "example-zip",
args = [
"$(execpath :%s)" % name,
"$(RULEDIR)",
],
data = [":%s" % name],
outs = outs,
tool = "//aio/tools/example-zipper:generate-example-zip",
)
if test:
EXAMPLE_DEPS_WORKSPACE_NAME = "aio_example_deps"
LOCAL_PACKAGE_DEPS = [to_package_label(dep) for dep in AIO_EXAMPLE_PACKAGES]
# Local package deps are passed as args to the test script in the form "@package/name#path/to/package"
# for the script's convenience.
LOCAL_PACKAGE_ARGS = ["--localPackage=%s#$(rootpath %s)" % (dep, to_package_label(dep)) for dep in AIO_EXAMPLE_PACKAGES]
nodejs_test(
name = "e2e",
data = [
":%s" % name,
YARN_LABEL,
"@aio_npm//@angular/build-tooling/bazel/browsers/chromium",
"//aio/tools/examples:run-example-e2e",
"//aio/tools:windows-chromium-path",
# We install the whole node modules for runtime deps of e2e tests
"@{workspace}//:node_modules_files".format(workspace = EXAMPLE_DEPS_WORKSPACE_NAME),
] + select({
"//aio:aio_local_deps": LOCAL_PACKAGE_DEPS,
"//conditions:default": [],
}),
args = [
"$(rootpath :%s)" % name,
"$(rootpath %s)" % YARN_LABEL,
EXAMPLE_DEPS_WORKSPACE_NAME,
] + select({
"//aio:aio_local_deps": LOCAL_PACKAGE_ARGS,
"//conditions:default": [],
}),
entry_point = "//aio/tools/examples:run-example-e2e.mjs",
env = {
"CHROME_BIN": "$(CHROMIUM)",
"CHROMEDRIVER_BIN": "$(CHROMEDRIVER)",
},
toolchains = [
"@aio_npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias",
],
exec_properties = test_exec_properties,
flaky = flaky,
# RBE complains about superseeding the max inputs limit (70,000) due to the
# size of the input tree.
tags = ["no-remote-exec"] + test_tags,
)