feat(bazel): ng_module produces bundle index (#22176)
It creates the bundle index .d.ts and .metadata.json files. The names are based on the ng_module target. PR Close #22176
This commit is contained in:
parent
bba65e0f41
commit
029dbf0e18
16
WORKSPACE
16
WORKSPACE
|
@ -1,10 +1,14 @@
|
|||
workspace(name = "angular")
|
||||
|
||||
# Using a pre-release snapshot to pick up a commit that makes all nodejs_binary
|
||||
# programs produce source-mapped stack traces.
|
||||
RULES_NODEJS_VERSION = "926349cea4cd360afcd5647ccdd09d2d2fb471aa"
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.4.1.zip",
|
||||
strip_prefix = "rules_nodejs-0.4.1",
|
||||
sha256 = "e9bc013417272b17f302dc169ad597f05561bb277451f010043f4da493417607",
|
||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/%s.zip" % RULES_NODEJS_VERSION,
|
||||
strip_prefix = "rules_nodejs-%s" % RULES_NODEJS_VERSION,
|
||||
sha256 = "5ba3c8c209078c2e3f0c6aa4abd01a1a561f92a5bfda04e25604af5f4734d69d",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||
|
@ -12,10 +16,12 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_reposi
|
|||
check_bazel_version("0.9.0")
|
||||
node_repositories(package_json = ["//:package.json"])
|
||||
|
||||
RULES_TYPESCRIPT_VERSION = "0.10.1"
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_typescript",
|
||||
url = "https://github.com/bazelbuild/rules_typescript/archive/0.10.1.zip",
|
||||
strip_prefix = "rules_typescript-0.10.1",
|
||||
url = "https://github.com/bazelbuild/rules_typescript/archive/%s.zip" % RULES_TYPESCRIPT_VERSION,
|
||||
strip_prefix = "rules_typescript-%s" % RULES_TYPESCRIPT_VERSION,
|
||||
sha256 = "a2c81776a4a492ff9f878f9705639f5647bef345f7f3e1da09c9eeb8dec80485",
|
||||
)
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
|
||||
|
||||
nodejs_binary(
|
||||
|
@ -8,12 +10,22 @@ nodejs_binary(
|
|||
# additional npm dependencies when we run rollup or uglify.
|
||||
entry_point = "build_bazel_rules_nodejs_rollup_deps/node_modules/rollup/bin/rollup",
|
||||
node_modules = "@build_bazel_rules_nodejs_rollup_deps//:node_modules",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
nodejs_binary(
|
||||
name = "modify_tsconfig",
|
||||
data = ["modify_tsconfig.js"],
|
||||
entry_point = "angular/packages/bazel/src/modify_tsconfig.js",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
nodejs_binary(
|
||||
name = "index_bundler",
|
||||
data = [
|
||||
# BEGIN-INTERNAL
|
||||
# Only needed when compiling within the Angular repo.
|
||||
# Users will get this dependency from node_modules.
|
||||
"//packages/compiler-cli",
|
||||
# END-INTERNAL
|
||||
],
|
||||
entry_point = "@angular/compiler-cli/src/metadata/bundle_index_main.js",
|
||||
)
|
||||
|
|
|
@ -12,6 +12,7 @@ load(":rules_typescript.bzl",
|
|||
"compile_ts",
|
||||
"DEPS_ASPECTS",
|
||||
"ts_providers_dict_to_struct",
|
||||
"json_marshal",
|
||||
)
|
||||
|
||||
def _basename_of(ctx, file):
|
||||
|
@ -236,6 +237,43 @@ def _ts_expected_outs(ctx, label):
|
|||
_ignored = [label]
|
||||
return _expected_outs(ctx)
|
||||
|
||||
def _write_bundle_index(ctx):
|
||||
basename = "_%s.bundle_index" % ctx.label.name
|
||||
tsconfig_file = ctx.actions.declare_file("%s.tsconfig.json" % basename)
|
||||
metadata_file = ctx.actions.declare_file("%s.metadata.json" % basename)
|
||||
tstyping_file = ctx.actions.declare_file("%s.d.ts" % basename)
|
||||
|
||||
tsconfig = dict(tsc_wrapped_tsconfig(ctx, ctx.files.srcs, ctx.files.srcs), **{
|
||||
"angularCompilerOptions": {
|
||||
"flatModuleOutFile": basename,
|
||||
},
|
||||
})
|
||||
if ctx.attr.module_name:
|
||||
tsconfig["angularCompilerOptions"]["flatModuleId"] = ctx.attr.module_name
|
||||
|
||||
# createBundleIndexHost in bundle_index_host.ts will throw if the "files" has more than one entry.
|
||||
# We don't want to fail() here, however, because not all ng_module's will have the bundle index written.
|
||||
# So we make the assumption that the index.ts file in the highest parent directory is the entry point.
|
||||
index_file = None
|
||||
for f in tsconfig["files"]:
|
||||
if f.endswith("/index.ts"):
|
||||
if not index_file or len(f) < len(index_file):
|
||||
index_file = f
|
||||
tsconfig["files"] = [index_file]
|
||||
|
||||
ctx.actions.write(tsconfig_file, json_marshal(tsconfig))
|
||||
|
||||
outputs = [metadata_file, tstyping_file]
|
||||
|
||||
ctx.action(
|
||||
progress_message = "Producing metadata for bundle %s" % ctx.label.name,
|
||||
executable = ctx.executable._index_bundler,
|
||||
inputs = ctx.files.srcs + [tsconfig_file],
|
||||
outputs = outputs,
|
||||
arguments = ["-p", tsconfig_file.path],
|
||||
)
|
||||
return outputs
|
||||
|
||||
def ng_module_impl(ctx, ts_compile_actions):
|
||||
"""Implementation function for the ng_module rule.
|
||||
|
||||
|
@ -263,6 +301,13 @@ def ng_module_impl(ctx, ts_compile_actions):
|
|||
}
|
||||
providers["ngc_messages"] = outs.i18n_messages
|
||||
|
||||
# Only produces the flattened "index bundle" metadata when requested by some other rule
|
||||
# and only under Bazel
|
||||
if hasattr(ctx.executable, "_index_bundler"):
|
||||
bundle_index_metadata = _write_bundle_index(ctx)
|
||||
# note, not recursive
|
||||
providers["angular"]["flat_module_metadata"] = depset(bundle_index_metadata)
|
||||
|
||||
return providers
|
||||
|
||||
def _ng_module_impl(ctx):
|
||||
|
@ -315,6 +360,10 @@ ng_module = rule(
|
|||
"node_modules": attr.label(
|
||||
default = Label("@//:node_modules")
|
||||
),
|
||||
"_index_bundler": attr.label(
|
||||
executable = True,
|
||||
cfg = "host",
|
||||
default = Label("//packages/bazel/src:index_bundler")),
|
||||
}),
|
||||
outputs = COMMON_OUTPUTS,
|
||||
)
|
||||
|
|
|
@ -17,7 +17,6 @@ ts_library(
|
|||
],
|
||||
exclude = [
|
||||
"src/extract_i18n.ts",
|
||||
"src/main.ts",
|
||||
"src/integrationtest/**/*.ts",
|
||||
],
|
||||
),
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
load("//packages/bazel:index.bzl", "ng_module")
|
||||
|
||||
ng_module(
|
||||
name = "test_module",
|
||||
srcs = glob(["*.ts"]),
|
||||
module_name = "some_npm_module",
|
||||
deps = ["//packages/core"],
|
||||
)
|
||||
|
||||
load(":extract_flat_module_index.bzl", "extract_flat_module_index")
|
||||
|
||||
extract_flat_module_index(
|
||||
name = "flat_module_index",
|
||||
deps = [":test_module"],
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "jasmine_node_test")
|
||||
|
||||
jasmine_node_test(
|
||||
name = "test",
|
||||
srcs = ["spec.js"],
|
||||
data = [":flat_module_index"],
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* @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 {NgModule} from '@angular/core';
|
||||
import {Parent} from './parent';
|
||||
|
||||
@NgModule({imports: [Parent]})
|
||||
export class Child {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
# 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
|
||||
"""Test utility to extract the "flat_module_metadata" from transitive Angular deps.
|
||||
"""
|
||||
|
||||
def _extract_flat_module_index(ctx):
|
||||
return [DefaultInfo(files = depset(transitive = [
|
||||
dep.angular.flat_module_metadata
|
||||
for dep in ctx.attr.deps
|
||||
if hasattr(dep, "angular")
|
||||
]))]
|
||||
|
||||
extract_flat_module_index = rule(
|
||||
implementation = _extract_flat_module_index,
|
||||
attrs = {
|
||||
"deps": attr.label_list(),
|
||||
},
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export * from './child';
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* @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 {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({})
|
||||
export class Parent {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const PKG = 'angular/packages/compiler-cli/integrationtest/bazel/ng_module';
|
||||
describe('flat module index', () => {
|
||||
describe('child metadata', () => {
|
||||
it('should have contents', () => {
|
||||
const metadata = fs.readFileSync(
|
||||
require.resolve(`${PKG}/_test_module.bundle_index.metadata.json`), {encoding: 'utf-8'});
|
||||
expect(metadata).toContain('"__symbolic":"module"');
|
||||
expect(metadata).toContain('"__symbolic":"reference","module":"@angular/core"');
|
||||
expect(metadata).toContain('"origins":{"Child":"./child","ɵa":"./parent"}');
|
||||
expect(metadata).toContain('"importAs":"some_npm_module"');
|
||||
});
|
||||
});
|
||||
describe('child typings', () => {
|
||||
it('should have contents', () => {
|
||||
const dts = fs.readFileSync(
|
||||
require.resolve(`${PKG}/_test_module.bundle_index.d.ts`), {encoding: 'utf-8'});
|
||||
|
||||
expect(dts).toContain('export * from \'./index\';');
|
||||
expect(dts).toContain('export { Parent as ɵa } from \'./parent\';');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
// Must be imported first, because Angular decorators throw on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as path from 'path';
|
||||
import {readCommandLineAndConfiguration} from '../main';
|
||||
import {createBundleIndexHost} from './bundle_index_host';
|
||||
import * as ng from '../transformers/entry_points';
|
||||
|
||||
export function main(args: string[], consoleError: (s: string) => void = console.error): number {
|
||||
const {options, rootNames} = readCommandLineAndConfiguration(args);
|
||||
const host = ng.createCompilerHost({options});
|
||||
const {host: bundleHost, indexName, errors} = createBundleIndexHost(options, rootNames, host);
|
||||
if (!indexName) {
|
||||
console.error('Did not find an index.ts in the top-level of the package.');
|
||||
return 1;
|
||||
}
|
||||
// The index file is synthetic, so we have to add it to the program after parsing the tsconfig
|
||||
rootNames.push(indexName);
|
||||
const program = ts.createProgram(rootNames, options, bundleHost);
|
||||
const indexSourceFile = program.getSourceFile(indexName);
|
||||
if (!indexSourceFile) {
|
||||
console.error(`${indexSourceFile} is not in the program. Please file a bug.`);
|
||||
return 1;
|
||||
}
|
||||
program.emit(indexSourceFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CLI entry point
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
process.exitCode = main(args);
|
||||
}
|
|
@ -597,6 +597,7 @@ export class CompilerHostAdapter implements MetadataBundlerHost {
|
|||
constructor(private host: ts.CompilerHost) {}
|
||||
|
||||
getMetadataFor(fileName: string): ModuleMetadata|undefined {
|
||||
if (!this.host.fileExists(fileName + '.ts')) return undefined;
|
||||
const sourceFile = this.host.getSourceFile(fileName + '.ts', ts.ScriptTarget.Latest);
|
||||
return sourceFile && this.collector.getMetadata(sourceFile);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue