build: rules_nodejs 0.26.0 & use @npm instead of @ngdeps now that downstream angular build uses angular bundles (#29063)

* removed /tools/http_server and uses http_server from rules_nodejs
* updated bazel schematics to use angular bundles

PR Close #29063
This commit is contained in:
Greg Magolan
2019-02-20 09:54:42 -08:00
committed by Kara Erickson
parent 2edb87e7f8
commit ea495d958f
222 changed files with 1238 additions and 1300 deletions

View File

@ -20,8 +20,6 @@ npm_package(
replacements = {
"(#|\/\/)\\s+BEGIN-DEV-ONLY[\\w\W]+?(#|\/\/)\\s+END-DEV-ONLY": "",
"//packages/bazel/": "//",
"@ngdeps//": "@npm//",
"@angular//:@angular/bazel/ngc-wrapped": "@npm//@angular/bazel/bin:ngc-wrapped",
"angular/packages/bazel/": "npm_angular_bazel/",
},
tags = ["release-with-framework"],

View File

@ -5,7 +5,6 @@ skylark_doc(
srcs = [
"//packages/bazel/src:ng_module.bzl",
"//packages/bazel/src:ng_rollup_bundle.bzl",
"//packages/bazel/src:ng_setup_workspace.bzl",
"//packages/bazel/src/ng_package:ng_package.bzl",
"//packages/bazel/src/protractor:protractor_web_test.bzl",
],

View File

@ -8,7 +8,6 @@ Users should not load files under "/src"
"""
load("//packages/bazel/src:ng_module.bzl", _ng_module = "ng_module")
load("//packages/bazel/src:ng_setup_workspace.bzl", _ng_setup_workspace = "ng_setup_workspace")
load("//packages/bazel/src/ng_package:ng_package.bzl", _ng_package = "ng_package")
load(
"//packages/bazel/src/protractor:protractor_web_test.bzl",
@ -20,6 +19,12 @@ ng_module = _ng_module
ng_package = _ng_package
protractor_web_test = _protractor_web_test
protractor_web_test_suite = _protractor_web_test_suite
ng_setup_workspace = _ng_setup_workspace
# DO NOT ADD PUBLIC API without including in the documentation generation
# Run `yarn bazel build //packages/bazel/docs` to verify
def ng_setup_workspace():
print("""DEPRECATION WARNING:
ng_setup_workspace is no longer needed, and will be removed in a future release.
We assume you will fetch rules_nodejs in your WORKSPACE file, and no other dependencies remain here.
Simply remove any calls to this function and the corresponding load statement.
""")

View File

@ -21,7 +21,7 @@
"@angular-devkit/architect": "^0.10.6",
"@angular-devkit/core": "^7.0.4",
"@angular-devkit/schematics": "^7.3.0-rc.0",
"@bazel/typescript": "^0.25.1",
"@bazel/typescript": "^0.26.0",
"@schematics/angular": "^7.0.4",
"@types/node": "6.0.84",
"semver": "^5.6.0",

View File

@ -13,13 +13,13 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
nodejs_binary(
name = "rollup_with_build_optimizer",
data = [
"@ngdeps//@angular-devkit/build-optimizer",
"@ngdeps//is-builtin-module",
"@ngdeps//rollup",
"@ngdeps//rollup-plugin-node-resolve",
"@ngdeps//rollup-plugin-sourcemaps",
"@npm//@angular-devkit/build-optimizer",
"@npm//is-builtin-module",
"@npm//rollup",
"@npm//rollup-plugin-node-resolve",
"@npm//rollup-plugin-sourcemaps",
],
entry_point = "ngdeps/node_modules/rollup/bin/rollup",
entry_point = "npm/node_modules/rollup/bin/rollup",
install_source_map_support = False,
visibility = ["//visibility:public"],
)

View File

@ -22,9 +22,9 @@ ts_library(
],
module_name = "@angular/bazel/src/builders",
deps = [
"@ngdeps//@angular-devkit/architect",
"@ngdeps//@angular-devkit/core",
"@ngdeps//@types/node",
"@ngdeps//rxjs",
"@npm//@angular-devkit/architect",
"@npm//@angular-devkit/core",
"@npm//@types/node",
"@npm//rxjs",
],
)

View File

@ -28,5 +28,5 @@ compile_ts = _compile_ts
DEPS_ASPECTS = _DEPS_ASPECTS
ts_providers_dict_to_struct = _ts_providers_dict_to_struct
DEFAULT_NG_COMPILER = "@angular//:@angular/bazel/ngc-wrapped"
DEFAULT_NG_COMPILER = "@npm//@angular/bazel/bin:ngc-wrapped"
DEFAULT_NG_XI18N = "@npm//@angular/bazel/bin:xi18n"

View File

@ -3,16 +3,16 @@ package(default_visibility = ["//visibility:public"])
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
# BEGIN-DEV-ONLY
load("@npm_bazel_typescript//:defs.bzl", "ts_library")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "lib",
srcs = glob(["*.ts"]),
node_modules = "@ngdeps//typescript:typescript__typings",
node_modules = "@npm//typescript:typescript__typings",
tsconfig = ":tsconfig.json",
deps = [
"@ngdeps//@types/node",
"@ngdeps//@types/shelljs",
"@npm//@types/node",
"@npm//@types/shelljs",
],
)
@ -21,7 +21,7 @@ nodejs_binary(
name = "packager",
data = [
"lib",
"@ngdeps//shelljs",
"@npm//shelljs",
],
entry_point = "angular/packages/bazel/src/ng_package/packager.js",
install_source_map_support = False,

View File

@ -31,7 +31,7 @@ PACKAGES = ["packages/core/src", "packages/common/src", "packages/compiler/src",
PLUGIN_CONFIG = "{sideEffectFreeModules: [\n%s]}" % ",\n".join(
[" '.esm5/{0}'".format(p) for p in PACKAGES],
)
BO_ROLLUP = "ngdeps/node_modules/@angular-devkit/build-optimizer/src/build-optimizer/rollup-plugin.js"
BO_ROLLUP = "npm/node_modules/@angular-devkit/build-optimizer/src/build-optimizer/rollup-plugin.js"
BO_PLUGIN = "require('%s').default(%s)" % (BO_ROLLUP, PLUGIN_CONFIG)
def _use_plain_rollup(ctx):

View File

@ -1,13 +0,0 @@
# Copyright Google Inc. All Rights Reserved.
#
# Use of this source code is governed by an MIT-style license that can be
# found in the LICENSE file at https://angular.io/license
"Install toolchain dependencies"
def ng_setup_workspace():
"""This repository rule should be called from your WORKSPACE file.
It creates some additional Bazel external repositories that are used internally
by the Angular rules.
"""

View File

@ -1,5 +1,5 @@
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("@npm_bazel_typescript//:defs.bzl", "ts_library")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "ngc_lib",
@ -8,7 +8,7 @@ ts_library(
"index.ts",
],
module_name = "@angular/bazel",
node_modules = "@ngdeps//typescript:typescript__typings",
node_modules = "@npm//typescript:typescript__typings",
tsconfig = ":tsconfig.json",
visibility = [
"//packages/bazel:__pkg__",
@ -20,10 +20,10 @@ ts_library(
# Users will get this dependency from node_modules.
"//packages/compiler-cli",
# END-INTERNAL
"@ngdeps//@bazel/typescript",
"@ngdeps//@types/node",
"@ngdeps//tsickle",
"@ngdeps//typescript",
"@npm//@bazel/typescript",
"@npm//@types/node",
"@npm//tsickle",
"@npm//typescript",
],
)
@ -32,8 +32,8 @@ nodejs_binary(
configuration_env_vars = ["compile"],
data = [
":ngc_lib",
"@ngdeps//source-map-support",
"@ngdeps//tslib",
"@npm//source-map-support",
"@npm//tslib",
"@npm_bazel_typescript//third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto",
],
entry_point = "angular/packages/bazel/src/ngc-wrapped/index.js",
@ -44,7 +44,7 @@ nodejs_binary(
name = "xi18n",
data = [
":ngc_lib",
"@ngdeps//source-map-support",
"@npm//source-map-support",
],
entry_point = "angular/packages/bazel/src/ngc-wrapped/extract_i18n.js",
visibility = ["//visibility:public"],

View File

@ -1,12 +1,12 @@
package(default_visibility = ["//visibility:public"])
load("@npm_bazel_typescript//:defs.bzl", "ts_library")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "utils",
srcs = ["index.ts"],
module_name = "@angular/bazel/protractor-utils",
node_modules = "@ngdeps//typescript:typescript__typings",
node_modules = "@npm//typescript:typescript__typings",
tsconfig = ":tsconfig.json",
deps = ["@ngdeps//@types/node"],
deps = ["@npm//@types/node"],
)

View File

@ -16,6 +16,7 @@ jasmine_node_test(
deps = [
"//packages/bazel/src/schematics/bazel-workspace:test",
"//packages/bazel/src/schematics/ng-new:test",
"//packages/bazel/src/schematics/utility:test",
"//tools/testing:node",
],
)

View File

@ -12,9 +12,9 @@ ts_library(
"schema.json",
],
deps = [
"@ngdeps//@angular-devkit/core",
"@ngdeps//@angular-devkit/schematics",
"@ngdeps//@schematics/angular",
"@npm//@angular-devkit/core",
"@npm//@angular-devkit/schematics",
"@npm//@schematics/angular",
],
)
@ -29,6 +29,6 @@ ts_library(
],
deps = [
":bazel-workspace",
"@ngdeps//@angular-devkit/schematics",
"@npm//@angular-devkit/schematics",
],
)

View File

@ -13,26 +13,18 @@ workspace(name = "<%= utils.underscore(name) %>")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_NODEJS_VERSION = "<%= RULES_NODEJS_VERSION %>"
RULES_NODEJS_SHA256 = "<%= RULES_NODEJS_SHA256 %>"
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "%s" % RULES_NODEJS_SHA256,
sha256 = "<%= RULES_NODEJS_SHA256 %>",
url = "https://github.com/bazelbuild/rules_nodejs/releases/download/%s/rules_nodejs-%s.tar.gz" % (RULES_NODEJS_VERSION, RULES_NODEJS_VERSION),
)
# The @angular repo contains rule for building Angular applications
ANGULAR_VERSION = "<%= ANGULAR_VERSION %>"
http_archive(
name = "angular",
url = "https://github.com/angular/angular/archive/%s.zip" % ANGULAR_VERSION,
strip_prefix = "angular-%s" % ANGULAR_VERSION,
)
<% if (sass) { %>
# Rules for compiling sass
RULES_SASS_VERSION = "<%= RULES_SASS_VERSION %>"
http_archive(
name = "io_bazel_rules_sass",
sha256 = "<%= RULES_SASS_SHA256 %>",
url = "https://github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION,
strip_prefix = "rules_sass-%s" % RULES_SASS_VERSION,
)
@ -46,6 +38,7 @@ check_bazel_version("0.18.0")
node_repositories()
yarn_install(
name = "npm",
data = ["//:angular-metadata.tsconfig.json"],
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
)
@ -62,11 +55,9 @@ web_test_repositories()
load("@npm_bazel_karma//:browser_repositories.bzl", "browser_repositories")
browser_repositories()
load("@npm_bazel_typescript//:defs.bzl", "ts_setup_workspace")
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
<% if (sass) { %>
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
sass_repositories()
<% } %>
load("@angular//:index.bzl", "ng_setup_workspace")
ng_setup_workspace()

View File

@ -13,6 +13,16 @@ build --strategy=AngularTemplateCompile=worker
# `bazel-out` directory that is created in the workspace root.
build --symlink_prefix=dist/
# Turn on --incompatible_strict_action_env which was on by default
# in Bazel 0.21.0 but turned off again in 0.22.0. Follow
# https://github.com/bazelbuild/bazel/issues/7026 for more details.
# This flag is needed to so that the bazel cache is not invalidated
# when running bazel via `yarn bazel`.
# See https://github.com/angular/angular/issues/27514.
build --incompatible_strict_action_env
run --incompatible_strict_action_env
test --incompatible_strict_action_env
test --test_output=errors
# Use the Angular 6 compiler

View File

@ -0,0 +1,21 @@
// Workaround for https://github.com/angular/angular/issues/18810
// This file is required because when using the Angular NPM packages and building
// with AOT compilation, NGC needs the "ngsummary.json" files.
{
"compilerOptions": {
"lib": [
"dom",
"es2015"
],
"experimentalDecorators": true,
"types": []
},
"include": [
"node_modules/@angular/**/*"
],
"exclude": [
"node_modules/@angular/bazel/**",
"node_modules/@angular/compiler-cli/**",
"node_modules/@angular/**/testing/**"
]
}

View File

@ -1,5 +1,5 @@
load("@npm_bazel_typescript//:defs.bzl", "ts_library")
load("@angular//:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm_angular_bazel//:index.bzl", "protractor_web_test_suite")
ts_library(
name = "e2e_lib",
@ -22,7 +22,7 @@ ts_library(
protractor_web_test_suite(
name = "prodserver_test",
data = [
"@angular//" + "packages/bazel/src/protractor/utils",
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":protractor.on-prepare.js",
@ -33,7 +33,7 @@ protractor_web_test_suite(
protractor_web_test_suite(
name = "devserver_test",
data = [
"@angular//" + "packages/bazel/src/protractor/utils",
"@npm//@angular/bazel",
"@npm//protractor",
],
on_prepare = ":protractor.on-prepare.js",

View File

@ -1,31 +1,17 @@
package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@npm_bazel_karma//:defs.bzl", "ts_web_test_suite")
load("@npm_angular_bazel//:index.bzl", "ng_module")
load("@npm_bazel_karma//:index.bzl", "ts_web_test_suite")
load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "history_server")
load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_package")
load("@npm_bazel_typescript//:defs.bzl", "ts_devserver", "ts_library")
<% if (sass) { %>load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
<% if (sass) { %>load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary")
[
sass_binary(
name = "style_" + x,
src = x,
deps = [],
multi_sass_binary(
name = "styles",
srcs = glob(["**/*.scss"]),
)
for x in glob(["**/*.scss"])
]
<% } %>
filegroup(
name = "rxjs_umd_modules",
srcs = [
# do not sort
"@npm//node_modules/rxjs:bundles/rxjs.umd.js",
":rxjs_shims.js",
],
)
ng_module(
name = "src",
srcs = glob(
@ -40,11 +26,11 @@ ng_module(
assets = glob([
"**/*.css",
"**/*.html",
])<% if (sass) { %> + [":style_" + x for x in glob(["**/*.scss"])]<% } %>,
])<% if (sass) { %> + [":styles"]<% } %>,
deps = [
"@angular//packages/core",
"@angular//packages/platform-browser",<% if (routing) { %>
"@angular//packages/router",<% } %>
"@npm//@angular/core",
"@npm//@angular/platform-browser",<% if (routing) { %>
"@npm//@angular/router",<% } %>
"@npm//@types",
"@npm//rxjs",
],
@ -67,7 +53,7 @@ web_package(
":bundle.min.js",
],
data = [
":bundle",
"favicon.ico",
],
index_html = "index.html",
)
@ -78,18 +64,34 @@ history_server(
templated_args = ["src/prodapp"],
)
filegroup(
name = "rxjs_umd_modules",
srcs = [
# do not sort
"@npm//node_modules/rxjs:bundles/rxjs.umd.js",
":rxjs_shims.js",
],
)
ts_devserver(
name = "devserver",
port = 4200,
entry_module = "<%= utils.underscore(name) %>/src/main.dev",
serving_path = "/bundle.min.js",
scripts = [
"@npm//node_modules/@angular/common:bundles/common.umd.js",
"@npm//node_modules/@angular/common:bundles/common-http.umd.js",
"@npm//node_modules/@angular/core:bundles/core.umd.js",
"@npm//node_modules/@angular/platform-browser:bundles/platform-browser.umd.js",
"@npm//node_modules/tslib:tslib.js",
":rxjs_umd_modules",
],
static_files = [
"@npm//node_modules/zone.js:dist/zone.min.js",
],
data = [
"favicon.ico",
],
index_html = "index.html",
deps = [":src"],
)
@ -100,7 +102,7 @@ ts_library(
srcs = glob(["**/*.spec.ts"]),
deps = [
":src",
"@angular//packages/core/testing",
"@npm//@angular/core",
"@npm//@types",
],
)
@ -112,15 +114,26 @@ ts_library(
"initialize_testbed.ts",
],
deps = [
"@angular//packages/core/testing",
"@angular//packages/platform-browser-dynamic/testing",
"@npm//@angular/core",
"@npm//@angular/platform-browser-dynamic",
"@npm//@types",
],
)
ts_web_test_suite(
name = "test",
srcs = ["@npm//node_modules/tslib:tslib.js"],
srcs = [
"@npm//node_modules/@angular/common:bundles/common.umd.js",
"@npm//node_modules/@angular/compiler:bundles/compiler.umd.js",
"@npm//node_modules/@angular/compiler:bundles/compiler-testing.umd.js",
"@npm//node_modules/@angular/core:bundles/core.umd.js",
"@npm//node_modules/@angular/core:bundles/core-testing.umd.js",
"@npm//node_modules/@angular/platform-browser:bundles/platform-browser.umd.js",
"@npm//node_modules/@angular/platform-browser:bundles/platform-browser-testing.umd.js",
"@npm//node_modules/@angular/platform-browser-dynamic:bundles/platform-browser-dynamic.umd.js",
"@npm//node_modules/@angular/platform-browser-dynamic:bundles/platform-browser-dynamic-testing.umd.js",
"@npm//node_modules/tslib:tslib.js",
],
runtime_deps = [
":initialize_testbed",
],

View File

@ -9,32 +9,12 @@
*/
import {strings} from '@angular-devkit/core';
import {Rule, SchematicContext, SchematicsException, Tree, apply, applyTemplates, mergeWith, move, url} from '@angular-devkit/schematics';
import {Rule, SchematicContext, Tree, apply, applyTemplates, mergeWith, url} from '@angular-devkit/schematics';
import {getWorkspace} from '@schematics/angular/utility/config';
import {latestVersions} from '@schematics/angular/utility/latest-versions';
import {validateProjectName} from '@schematics/angular/utility/validation';
import {Schema as BazelWorkspaceOptions} from './schema';
/**
* Look for package.json file for package with `packageName` in node_modules and
* extract its version.
*/
function findVersion(packageName: string, host: Tree): string|null {
const candidate = `node_modules/${packageName}/package.json`;
if (host.exists(candidate)) {
try {
const packageJson = JSON.parse(host.read(candidate).toString());
if (packageJson.name === packageName && packageJson.version) {
return packageJson.version;
}
} catch {
}
}
return null;
}
/**
* Clean the version string and return version in the form "1.2.3". Return
* null if version string is invalid. This is similar to semver.clean() but
@ -72,26 +52,15 @@ export default function(options: BazelWorkspaceOptions): Rule {
}
validateProjectName(name);
// If the project already has some deps installed, Bazel should use existing
// versions.
const existingVersions = {
Angular: findVersion('@angular/core', host),
RxJs: findVersion('rxjs', host),
};
Object.keys(existingVersions).forEach((name: 'Angular' | 'RxJs') => {
const version = existingVersions[name] as string;
if (version) {
context.logger.info(`Bazel will reuse existing version for ${name}: ${version}`);
}
});
if (!host.exists('yarn.lock')) {
host.create('yarn.lock', '');
}
const workspaceVersions = {
'RULES_NODEJS_VERSION': '0.18.6',
'RULES_NODEJS_SHA256': '1416d03823fed624b49a0abbd9979f7c63bbedfd37890ddecedd2fe25cccebc6',
'ANGULAR_VERSION': existingVersions.Angular || clean(latestVersions.Angular),
// TODO(kyliau): Consider moving this to latest-versions.ts
'RULES_SASS_VERSION': '1.15.1',
'RULES_NODEJS_VERSION': '0.26.0',
'RULES_NODEJS_SHA256': '5c86b055c57e15bf32d9009a15bcd6d8e190c41b1ff2fb18037b75e0012e4e7c',
'RULES_SASS_VERSION': '1.17.2',
'RULES_SASS_SHA256': 'e5316ee8a09d1cbb732d3938b400836bf94dba91a27476e9e27706c4c0edae1f',
};
return mergeWith(apply(url('./files'), [

View File

@ -29,17 +29,19 @@ describe('Bazel-workspace Schematic', () => {
expect(files).toContain('/yarn.lock');
});
it('should find existing Angular version', () => {
let host = new UnitTestTree(new HostTree);
host.create('/node_modules/@angular/core/package.json', JSON.stringify({
name: '@angular/core',
version: '6.6.6',
}));
const options = {...defaultOptions};
host = schematicRunner.runSchematic('bazel-workspace', options, host);
expect(host.files).toContain('/WORKSPACE');
const workspace = host.readContent('/WORKSPACE');
expect(workspace).toMatch('ANGULAR_VERSION = "6.6.6"');
it('should generate empty yarn.lock file', () => {
const host = schematicRunner.runSchematic('bazel-workspace', defaultOptions);
expect(host.files).toContain('/yarn.lock');
expect(host.readContent('/yarn.lock')).toBe('');
});
it('should not replace yarn.lock if it exists', () => {
let host = new UnitTestTree(new HostTree());
host.create('yarn.lock', 'some content');
expect(host.files).toContain('/yarn.lock');
host = schematicRunner.runSchematic('bazel-workspace', defaultOptions, host);
expect(host.files).toContain('/yarn.lock');
expect(host.readContent('/yarn.lock')).toBe('some content');
});
it('should have the correct entry_module for devserver', () => {
@ -59,7 +61,7 @@ describe('Bazel-workspace Schematic', () => {
host = schematicRunner.runSchematic('bazel-workspace', options, host);
expect(host.files).toContain('/src/BUILD.bazel');
const content = host.readContent('/src/BUILD.bazel');
expect(content).toContain('@angular//packages/router');
expect(content).toContain('@npm//@angular/router');
});
describe('WORKSPACE', () => {
@ -98,9 +100,9 @@ describe('Bazel-workspace Schematic', () => {
'load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")');
});
it('should add sass_binary rules in src/BUILD', () => {
it('should add multi_sass_binary rule in src/BUILD', () => {
const content = host.readContent('/src/BUILD.bazel');
expect(content).toContain('load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")');
expect(content).toContain('load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary")');
expect(content).toContain('glob(["**/*.scss"])');
});
});

View File

@ -13,10 +13,11 @@ ts_library(
],
deps = [
"//packages/bazel/src/schematics/bazel-workspace",
"@ngdeps//@angular-devkit/core",
"@ngdeps//@angular-devkit/schematics",
"@ngdeps//@schematics/angular",
"@ngdeps//typescript",
"//packages/bazel/src/schematics/utility",
"@npm//@angular-devkit/core",
"@npm//@angular-devkit/schematics",
"@npm//@schematics/angular",
"@npm//typescript",
],
)
@ -31,6 +32,6 @@ ts_library(
],
deps = [
":ng-new",
"@ngdeps//@angular-devkit/schematics",
"@npm//@angular-devkit/schematics",
],
)

View File

@ -11,6 +11,7 @@
import {SchematicContext, apply, applyTemplates, chain, externalSchematic, MergeStrategy, mergeWith, move, Rule, schematic, Tree, url, SchematicsException, UpdateRecorder,} from '@angular-devkit/schematics';
import {parseJsonAst, JsonAstObject, strings, JsonValue} from '@angular-devkit/core';
import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils';
import {isJsonAstObject, replacePropertyInAstObject} from '../utility/json-utils';
import {validateProjectName} from '@schematics/angular/utility/validation';
import {getWorkspace} from '@schematics/angular/utility/config';
import {Schema} from './schema';
@ -43,8 +44,9 @@ function addDevDependenciesToPackageJson(options: Schema) {
// TODO(kyliau): Consider moving this to latest-versions.ts
'@bazel/bazel': '^0.23.0',
'@bazel/ibazel': '^0.9.0',
'@bazel/karma': '^0.25.1',
'@bazel/typescript': '^0.25.1',
'@bazel/jasmine': '^0.26.0',
'@bazel/karma': '^0.26.0',
'@bazel/typescript': '^0.26.0',
};
const recorder = host.beginUpdate(packageJson);
@ -109,21 +111,6 @@ function overwriteGitignore(options: Schema) {
};
}
function replacePropertyInAstObject(
recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue,
indent: number) {
const property = findPropertyInAstObject(node, propertyName);
if (property === null) {
throw new Error(`Property ${propertyName} does not exist in JSON object`);
}
const {start, text} = property;
recorder.remove(start.offset, text.length);
const indentStr = '\n' +
' '.repeat(indent);
const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr);
recorder.insertLeft(start.offset, content);
}
function updateWorkspaceFileToUseBazelBuilder(options: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
const {name} = options;
@ -196,6 +183,81 @@ function updateWorkspaceFileToUseBazelBuilder(options: Schema): Rule {
};
}
/**
* @angular/bazel requires minimum version of rxjs to be 6.4.0. This function
* upgrades the version of rxjs in package.json if necessary.
*/
function upgradeRxjs(options: Schema) {
return (host: Tree, context: SchematicContext) => {
const packageJson = `${options.name}/package.json`;
if (!host.exists(packageJson)) {
throw new Error(`Could not find ${packageJson}`);
}
const content = host.read(packageJson).toString();
const jsonAst = parseJsonAst(content);
if (!isJsonAstObject(jsonAst)) {
throw new Error(`Failed to parse JSON for ${packageJson}`);
}
const deps = findPropertyInAstObject(jsonAst, 'dependencies');
if (!isJsonAstObject(deps)) {
throw new Error(`Failed to find dependencies in ${packageJson}`);
}
const rxjs = findPropertyInAstObject(deps, 'rxjs');
if (!rxjs) {
throw new Error(`Failed to find rxjs in dependencies of ${packageJson}`);
}
const value = rxjs.value as string; // value can be version or range
const match = value.match(/(\d)+\.(\d)+.(\d)+$/);
if (match) {
const [_, major, minor] = match;
if (major < '6' || (major === '6' && minor < '4')) {
const recorder = host.beginUpdate(packageJson);
replacePropertyInAstObject(recorder, deps, 'rxjs', '~6.4.0');
host.commitUpdate(recorder);
}
} else {
context.logger.info(
'Could not determine version of rxjs. \n' +
'Please make sure that version is at least 6.4.0.');
}
return host;
};
}
/**
* When using Angular NPM packages and building with AOT compilation, ngc
* requires ngsumamry files but they are not shipped. This function adds a
* postinstall step to generate these files.
*/
function addPostinstallToGenerateNgSummaries(options: Schema) {
return (host: Tree, context: SchematicContext) => {
const angularMetadataTsConfig = `${options.name}/angular-metadata.tsconfig.json`;
if (!host.exists(angularMetadataTsConfig)) {
return;
}
const packageJson = `${options.name}/package.json`;
if (!host.exists(packageJson)) {
throw new Error(`Could not find ${packageJson}`);
}
const content = host.read(packageJson).toString();
const jsonAst = parseJsonAst(content) as JsonAstObject;
const scripts = findPropertyInAstObject(jsonAst, 'scripts') as JsonAstObject;
const recorder = host.beginUpdate(packageJson);
if (scripts) {
insertPropertyInAstObjectInOrder(
recorder, scripts, 'postinstall', 'ngc -p ./angular-metadata.tsconfig.json', 4);
} else {
insertPropertyInAstObjectInOrder(
recorder, jsonAst, 'scripts', {
postinstall: 'ngc -p ./angular-metadata.tsconfig.json',
},
2);
}
host.commitUpdate(recorder);
return host;
};
}
export default function(options: Schema): Rule {
return (host: Tree) => {
validateProjectName(options.name);
@ -207,11 +269,13 @@ export default function(options: Schema): Rule {
...options,
}),
addDevDependenciesToPackageJson(options),
upgradeRxjs(options),
addDevAndProdMainForAot(options),
schematic('bazel-workspace', options, {
scope: options.name,
}),
overwriteGitignore(options),
addPostinstallToGenerateNgSummaries(options),
updateWorkspaceFileToUseBazelBuilder(options),
]);
};

View File

@ -0,0 +1,30 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "utility",
srcs = [
"json-utils.ts",
],
module_name = "@angular/bazel/src/schematics/utility",
deps = [
"@npm//@angular-devkit/core",
"@npm//@angular-devkit/schematics",
"@npm//@schematics/angular",
"@npm//typescript",
],
)
ts_library(
name = "test",
testonly = True,
srcs = [
"json-utils_spec.ts",
],
deps = [
":utility",
"@npm//@angular-devkit/core",
"@npm//@angular-devkit/schematics",
],
)

View File

@ -0,0 +1,65 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {JsonAstNode, JsonAstObject, JsonValue} from '@angular-devkit/core';
import {UpdateRecorder} from '@angular-devkit/schematics';
import {findPropertyInAstObject} from '@schematics/angular/utility/json-utils';
/**
* Replace the value of the key-value pair in the 'node' object with a different
* 'value' and record the update using the specified 'recorder'.
*/
export function replacePropertyInAstObject(
recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue,
indent: number = 0) {
const property = findPropertyInAstObject(node, propertyName);
if (property === null) {
throw new Error(`Property '${propertyName}' does not exist in JSON object`);
}
const {start, text} = property;
recorder.remove(start.offset, text.length);
const indentStr = '\n' +
' '.repeat(indent);
const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr);
recorder.insertLeft(start.offset, content);
}
/**
* Remove the key-value pair with the specified 'key' in the specified 'node'
* object and record the update using the specified 'recorder'.
*/
export function removeKeyValueInAstObject(
recorder: UpdateRecorder, content: string, node: JsonAstObject, key: string) {
for (const [i, prop] of node.properties.entries()) {
if (prop.key.value === key) {
const start = prop.start.offset;
const end = prop.end.offset;
let length = end - start;
const match = content.slice(end).match(/[,\s]+/);
if (match) {
length += match.pop() !.length;
}
recorder.remove(start, length);
if (i === node.properties.length - 1) { // last property
let offset = 0;
while (/(,|\s)/.test(content.charAt(start - offset - 1))) {
offset++;
}
recorder.remove(start - offset, offset);
}
return;
}
}
}
/**
* Returns true if the specified 'node' is a JsonAstObject, false otherwise.
*/
export function isJsonAstObject(node: JsonAstNode | null): node is JsonAstObject {
return !!node && node.kind === 'object';
}

View File

@ -0,0 +1,109 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {JsonAstObject, parseJsonAst} from '@angular-devkit/core';
import {HostTree} from '@angular-devkit/schematics';
import {UnitTestTree} from '@angular-devkit/schematics/testing';
import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from './json-utils';
describe('JsonUtils', () => {
let tree: UnitTestTree;
beforeEach(() => { tree = new UnitTestTree(new HostTree()); });
describe('replacePropertyInAstObject', () => {
it('should replace property', () => {
const content = JSON.stringify({foo: {bar: 'baz'}});
tree.create('tmp', content);
const ast = parseJsonAst(content) as JsonAstObject;
const recorder = tree.beginUpdate('tmp');
replacePropertyInAstObject(recorder, ast, 'foo', [1, 2, 3]);
tree.commitUpdate(recorder);
const value = tree.readContent('tmp');
expect(JSON.parse(value)).toEqual({
foo: [1, 2, 3],
});
expect(value).toBe(`{"foo":[
1,
2,
3
]}`);
});
it('should respect the indent parameter', () => {
const content = JSON.stringify({hello: 'world'}, null, 2);
tree.create('tmp', content);
const ast = parseJsonAst(content) as JsonAstObject;
const recorder = tree.beginUpdate('tmp');
replacePropertyInAstObject(recorder, ast, 'hello', 'world!', 2);
tree.commitUpdate(recorder);
const value = tree.readContent('tmp');
expect(JSON.parse(value)).toEqual({
hello: 'world!',
});
expect(value).toBe(`{
"hello": "world!"
}`);
});
it('should throw error if property is not found', () => {
const content = JSON.stringify({});
tree.create('tmp', content);
const ast = parseJsonAst(content) as JsonAstObject;
const recorder = tree.beginUpdate('tmp');
expect(() => replacePropertyInAstObject(recorder, ast, 'foo', 'bar'))
.toThrowError(`Property 'foo' does not exist in JSON object`);
});
});
describe('removeKeyValueInAstObject', () => {
it('should remove key-value pair', () => {
const content = JSON.stringify({hello: 'world', foo: 'bar'});
tree.create('tmp', content);
const ast = parseJsonAst(content) as JsonAstObject;
let recorder = tree.beginUpdate('tmp');
removeKeyValueInAstObject(recorder, content, ast, 'foo');
tree.commitUpdate(recorder);
const tmp = tree.readContent('tmp');
expect(JSON.parse(tmp)).toEqual({
hello: 'world',
});
expect(tmp).toBe('{"hello":"world"}');
recorder = tree.beginUpdate('tmp');
const newContent = tree.readContent('tmp');
removeKeyValueInAstObject(recorder, newContent, ast, 'hello');
tree.commitUpdate(recorder);
const value = tree.readContent('tmp');
expect(JSON.parse(value)).toEqual({});
expect(value).toBe('{}');
});
it('should be a noop if key is not found', () => {
const content = JSON.stringify({foo: 'bar'});
tree.create('tmp', content);
const ast = parseJsonAst(content) as JsonAstObject;
let recorder = tree.beginUpdate('tmp');
expect(() => removeKeyValueInAstObject(recorder, content, ast, 'hello')).not.toThrow();
tree.commitUpdate(recorder);
const value = tree.readContent('tmp');
expect(JSON.parse(value)).toEqual({foo: 'bar'});
expect(value).toBe('{"foo":"bar"}');
});
});
describe('isJsonAstObject', () => {
it('should return true for an object', () => {
const ast = parseJsonAst(JSON.stringify({}));
expect(isJsonAstObject(ast)).toBe(true);
});
it('should return false for a non-object', () => {
const ast = parseJsonAst(JSON.stringify([]));
expect(isJsonAstObject(ast)).toBe(false);
});
});
});

View File

@ -13,7 +13,7 @@ ts_library(
deps = [
"//packages:types",
"//packages/private/testing",
"@ngdeps//@types/shelljs",
"@npm//@types/shelljs",
],
)
@ -22,8 +22,8 @@ jasmine_node_test(
srcs = [":core_spec_lib"],
data = [
"//packages/core:npm_package",
"@ngdeps//@types/shelljs",
"@ngdeps//shelljs",
"@npm//@types/shelljs",
"@npm//shelljs",
],
)
@ -34,7 +34,7 @@ ts_library(
deps = [
"//packages:types",
"//packages/private/testing",
"@ngdeps//@types/shelljs",
"@npm//@types/shelljs",
],
)
@ -43,7 +43,7 @@ jasmine_node_test(
srcs = [":common_spec_lib"],
data = [
"//packages/common:npm_package",
"@ngdeps//shelljs",
"@npm//shelljs",
],
)
@ -53,7 +53,7 @@ ts_library(
srcs = ["example_package.spec.ts"],
deps = [
"//packages:types",
"@ngdeps//@types/diff",
"@npm//@types/diff",
],
)
@ -68,7 +68,7 @@ jasmine_node_test(
# file is based on non-ivy output and therefore won't work for ngc and Ivy at the same time.
# TODO: We should be able to have another golden for ivy-aot as well.
tags = ["no-ivy-aot"],
deps = ["@ngdeps//diff"],
deps = ["@npm//diff"],
)
nodejs_binary(
@ -78,7 +78,7 @@ nodejs_binary(
"example_package.golden",
":example_spec_lib",
"//packages/bazel/test/ng_package/example:npm_package",
"@ngdeps//diff",
"@npm//diff",
],
entry_point = "angular/packages/bazel/test/ng_package/example_package.spec.js",
templated_args = ["--accept"],

View File

@ -8,7 +8,7 @@ ng_module(
module_name = "example",
deps = [
"//packages/bazel/test/ng_package/example/secondary",
"@ngdeps//@types",
"@npm//@types",
],
)

View File

@ -8,6 +8,6 @@ ng_module(
module_name = "example/secondary",
deps = [
"//packages/core",
"@ngdeps//@types",
"@npm//@types",
],
)

View File

@ -12,7 +12,7 @@ ts_library(
deps = [
"//packages/bazel/src/ngc-wrapped:ngc_lib",
"//packages/compiler-cli",
"@ngdeps//typescript",
"@npm//typescript",
],
)

View File

@ -8,6 +8,6 @@ ng_module(
tsconfig = ":tsconfig.json",
deps = [
"//packages/core",
"@ngdeps//@types",
"@npm//@types",
],
)

View File

@ -71,7 +71,7 @@ export function createTsConfig(options: TsConfigOptions) {
'tsickleExternsPath': '',
// we don't copy the node_modules into our tmp dir, so we should look in
// the original workspace directory for it
'nodeModulesPrefix': '../ngdeps/node_modules',
'nodeModulesPrefix': '../npm/node_modules',
},
'files': options.files,
'angularCompilerOptions': {

View File

@ -1,8 +1,7 @@
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
load("@npm_bazel_typescript//:defs.bzl", "ts_devserver")
load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle")
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
load("@build_bazel_rules_nodejs//:defs.bzl", "http_server", "rollup_bundle")
load("//tools:defaults.bzl", "ts_library")
load("//tools/http-server:http_server.bzl", "http_server")
ts_library(
name = "app",
@ -37,8 +36,8 @@ ts_library(
srcs = ["test.spec.ts"],
tsconfig = ":tsconfig.test.json",
deps = [
"@ngdeps//@types/selenium-webdriver",
"@ngdeps//protractor",
"@npm//@types/selenium-webdriver",
"@npm//protractor",
],
)
@ -50,7 +49,7 @@ protractor_web_test_suite(
server = ":prodserver",
deps = [
":ts_spec",
"@ngdeps//protractor",
"@npm//protractor",
],
)
@ -62,6 +61,6 @@ protractor_web_test_suite(
server = ":devserver",
deps = [
":ts_spec",
"@ngdeps//protractor",
"@npm//protractor",
],
)

View File

@ -14,7 +14,7 @@ nodejs_binary(
testonly = True,
data = [
"fake-devserver.js",
"@ngdeps//minimist",
"@npm//minimist",
],
entry_point = "angular/packages/bazel/test/protractor-utils/fake-devserver.js",
)

View File

@ -7,8 +7,8 @@ ts_library(
srcs = ["test.spec.ts"],
tsconfig = ":tsconfig.json",
deps = [
"@ngdeps//@types/selenium-webdriver",
"@ngdeps//protractor",
"@npm//@types/selenium-webdriver",
"@npm//protractor",
],
)
@ -19,7 +19,7 @@ ts_library(
tsconfig = ":tsconfig.json",
deps = [
"//packages/bazel/src/protractor/utils",
"@ngdeps//protractor",
"@npm//protractor",
],
)
@ -29,6 +29,6 @@ protractor_web_test_suite(
data = ["//packages/bazel/src/protractor/utils"],
deps = [
":ts_spec",
"@ngdeps//protractor",
"@npm//protractor",
],
)