mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
f82898436e
There is quite some trickery going on with the adev build related to local packages: - Adev builds using npm packages from `/node_modules` - At runtime, we are adding `HEAD` packages for e.g. `@angular/core` to the bundles. - At build time, the CLI, or Angular devkit may accidentally resolve to `@angular/core` from `/node_modules/`— which is the core version from npm, transitively installed via `@angular/docs`. This causes a version mismatch, leading to issues like: - CLI throwing because of a mismatch. https://github.com/angular/angular/issues/54858#issuecomment-2047188739 - Compiler changes not being picked up. https://github.com/angular/angular/issues/54858#issuecomment-2041322427 This commit attempts to fix this by: - Linking all Angular `HEAD` packages into `adev/node_modules`. The current logic attempts to link into `/node_modules`, but this does not override existing `@angular/core`! - Linking all direct external NPM packages, like `@angular_devkit/build-angular` into `adev/node_modules` without their transitive deps. This allows proper resolution of e.g. compiler as node looks in `adev/node_modules` first, and falls back for the rest to the execroot `node_modules`, or symlink target destination (if `preserveSymlinks=false`). Note: This is still not 100% ideal because a direct external NPM dependency may have a transitive dependency that has another transitive dependency on `@angular/core`. In those cases, the may be a conflict that is not resolvable until we switch to a Bazel toolchain with better first party resolution support. PR Close #55282
85 lines
3.3 KiB
Python
85 lines
3.3 KiB
Python
load("//:packages.bzl", "ALL_PACKAGES", "to_package_label")
|
|
load("@build_bazel_rules_nodejs//internal/linker:npm_link.bzl", "npm_link")
|
|
load("//adev/tools/local_deps:filter_external_npm_deps.bzl", "filter_external_npm_deps")
|
|
|
|
def ensure_local_package_deps(deps):
|
|
"""Replaces dependencies with their local-linked variants."""
|
|
return [":%s" % _filtered_transitives_name(dep) for dep in deps]
|
|
|
|
def link_local_packages(all_deps):
|
|
"""Create targets needed for building adev against local angular packages.
|
|
|
|
Creates targets that link Angular packages, as well as targets to be used
|
|
in place of any deps required to build and test adev. These targets filter
|
|
out any transitive deps on the npm packages and must be used in place of
|
|
any original list of deps.
|
|
|
|
Use the helper `ensure_local_package_deps()` to translate a list of deps
|
|
to the equivalent "filtered" target that this rule creates.
|
|
|
|
Args:
|
|
all_deps: label list of all deps required to build and test adev
|
|
"""
|
|
|
|
local_angular_deps = [dep for dep in all_deps if _is_angular_dep(dep)]
|
|
local_angular_package_names = [_angular_dep_to_pkg_name(dep) for dep in local_angular_deps]
|
|
|
|
# Link local angular packages in place of their npm equivalent
|
|
for dep in local_angular_deps:
|
|
pkg_name = _angular_dep_to_pkg_name(dep)
|
|
npm_link(
|
|
name = _npm_link_name(pkg_name),
|
|
target = to_package_label(pkg_name),
|
|
package_name = pkg_name,
|
|
package_path = native.package_name(),
|
|
tags = ["manual"],
|
|
)
|
|
|
|
# Special case deps that must be testonly
|
|
testonly_deps = [
|
|
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
|
]
|
|
|
|
# Stamp a corresponding target for each dep that filters out transitive
|
|
# dependencies on external npm packages. This help the rules_nodejs linker,
|
|
# which fails to link local packages into transitive dependencies of npm deps.
|
|
for dep in all_deps:
|
|
target = dep
|
|
if dep in local_angular_deps:
|
|
pkg_name = _angular_dep_to_pkg_name(dep)
|
|
|
|
# We don't need to filter transitives on local packages as they
|
|
# depend on each other locally.
|
|
native.alias(
|
|
name = _filtered_transitives_name(dep),
|
|
actual = ":%s" % _npm_link_name(pkg_name),
|
|
tags = ["manual"],
|
|
)
|
|
else:
|
|
filter_external_npm_deps(
|
|
name = _filtered_transitives_name(dep),
|
|
target = target,
|
|
testonly = True if dep in testonly_deps else False,
|
|
angular_packages = local_angular_package_names,
|
|
tags = ["manual"],
|
|
)
|
|
|
|
def _is_angular_dep(dep):
|
|
"""Check if a dep , e.g., @npm//@angular/core corresonds to a local Angular pacakge."""
|
|
return dep.startswith("@npm//") and (_angular_dep_to_pkg_name(dep) in ALL_PACKAGES)
|
|
|
|
def _angular_dep_to_pkg_name(dep):
|
|
"""E.g., @npm//@angular/core => '@angular/core'"""
|
|
label = Label(dep)
|
|
return label.package
|
|
|
|
def _npm_link_name(pkg_name):
|
|
return "local_head_%s" % pkg_name.replace("@", "_").replace("/", "_")
|
|
|
|
def _filtered_transitives_name(dep):
|
|
if dep.startswith(":"):
|
|
return "%s_without_transitive_deps" % dep[1:]
|
|
else:
|
|
label = Label(dep)
|
|
return "%s_without_transitive_deps" % label.package.replace("@", "_").replace("/", "_")
|