build: enable bundle_dts for core package (#28884)

`ng_module` will now include an `src/r3_symbol.d.ts` when compiling the core package under `ngc` togather with `dts bundling`, This is due that `ngcc` relies on this file to be present, but the `r3_symbols` file which is not part of our public api.

With this change, we can now ship an addition dts file which is flattened.

PR Close #28884
This commit is contained in:
Alan 2019-03-06 09:04:18 +01:00 committed by Kara Erickson
parent a746b5b1ea
commit 7b0e9eddd1
7 changed files with 83 additions and 54 deletions

View File

@ -114,5 +114,19 @@ api-extractor: running with
}
const [tsConfig, entryPoint, dtsBundleOut] = process.argv.slice(2);
process.exitCode = runMain(tsConfig, entryPoint, dtsBundleOut);
const entryPoints = entryPoint.split(',');
const dtsBundleOuts = dtsBundleOut.split(',');
if (entryPoints.length !== entryPoints.length) {
throw new Error(
`Entry points count (${entryPoints.length}) does not match Bundle out count (${dtsBundleOuts.length})`);
}
for (let i = 0; i < entryPoints.length; i++) {
process.exitCode = runMain(tsConfig, entryPoints[i], dtsBundleOuts[i]);
if (process.exitCode !== 0) {
break;
}
}
}

View File

@ -21,6 +21,7 @@ load(
)
_FLAT_DTS_FILE_SUFFIX = ".bundle.d.ts"
_R3_SYMBOLS_DTS_FILE = "src/r3_symbols.d.ts"
def compile_strategy(ctx):
"""Detect which strategy should be used to implement ng_module.
@ -142,6 +143,25 @@ def _should_produce_dts_bundle(ctx):
# see: https://github.com/Microsoft/web-build-tools/issues/1029
return _is_legacy_ngc(ctx) and hasattr(ctx.attr, "bundle_dts") and ctx.attr.bundle_dts
def _should_produce_r3_symbols_bundle(ctx):
"""Should we produce r3_symbols bundle.
NGCC relies on having r3_symbols file. This file is located in @angular/core
And should only be included when bundling core in legacy mode.
Args:
ctx: skylark rule execution context
Returns:
true when we should produce r3_symbols dts.
"""
# iif we are compiling @angular/core with ngc we should add this addition dts bundle
# because ngcc relies on having this file.
# see: https://github.com/angular/angular/blob/84406e4d6d93b28b23efbb1701bc5ae1084da67b/packages/compiler-cli/src/ngcc/src/packages/entry_point_bundle.ts#L56
# todo: alan-agius4: remove when ngcc doesn't need this anymore
return _is_legacy_ngc(ctx) and ctx.attr.module_name == "@angular/core"
def _should_produce_flat_module_outs(ctx):
"""Should we produce flat module outputs.
@ -221,13 +241,16 @@ def _expected_outs(ctx):
if not _is_bazel():
metadata_files += [ctx.actions.declare_file(basename + ext) for ext in metadata]
dts_bundle = None
dts_bundles = None
if _should_produce_dts_bundle(ctx):
# We need to add a suffix to bundle as it might collide with the flat module dts.
# The flat module dts out contains several other exports
# https://github.com/angular/angular/blob/master/packages/compiler-cli/src/metadata/index_writer.ts#L18
# https://github.com/angular/angular/blob/84406e4d6d93b28b23efbb1701bc5ae1084da67b/packages/compiler-cli/src/metadata/index_writer.ts#L18
# the file name will be like 'core.bundle.d.ts'
dts_bundle = ctx.actions.declare_file(ctx.label.name + _FLAT_DTS_FILE_SUFFIX)
dts_bundles = [ctx.actions.declare_file(ctx.label.name + _FLAT_DTS_FILE_SUFFIX)]
if _should_produce_r3_symbols_bundle(ctx):
dts_bundles.append(ctx.actions.declare_file(_R3_SYMBOLS_DTS_FILE.replace(".d.ts", _FLAT_DTS_FILE_SUFFIX)))
# We do this just when producing a flat module index for a publishable ng_module
if _should_produce_flat_module_outs(ctx):
@ -254,7 +277,7 @@ def _expected_outs(ctx):
declarations = declaration_files,
summaries = summary_files,
metadata = metadata_files,
dts_bundle = dts_bundle,
dts_bundles = dts_bundles,
bundle_index_typings = bundle_index_typings,
i18n_messages = i18n_messages_files,
)
@ -337,7 +360,7 @@ def ngc_compile_action(
node_opts,
locale = None,
i18n_args = [],
dts_bundle_out = None):
dts_bundles_out = None):
"""Helper function to create the ngc action.
This is exposed for google3 to wire up i18n replay rules, and is not intended
@ -353,7 +376,7 @@ def ngc_compile_action(
node_opts: list of strings, extra nodejs options.
locale: i18n locale, or None
i18n_args: additional command-line arguments to ngc
dts_bundle_out: produced flattened dts file
dts_bundles_out: produced flattened dts file
Returns:
the parameters of the compilation which will be used to replay the ngc action for i18N.
@ -412,25 +435,28 @@ def ngc_compile_action(
mnemonic = "Angular2MessageExtractor",
)
if dts_bundle_out != None:
if dts_bundles_out != None:
# combine the inputs and outputs and filter .d.ts and json files
filter_inputs = [f for f in inputs + outputs if f.path.endswith(".d.ts") or f.path.endswith(".json")]
if _should_produce_flat_module_outs(ctx):
dts_entry_point = "%s.d.ts" % _flat_module_out_file(ctx)
dts_entry_points = ["%s.d.ts" % _flat_module_out_file(ctx)]
else:
dts_entry_point = ctx.attr.entry_point.replace(".ts", ".d.ts")
dts_entry_points = [ctx.attr.entry_point.replace(".ts", ".d.ts")]
if _should_produce_r3_symbols_bundle(ctx):
dts_entry_points.append(_R3_SYMBOLS_DTS_FILE)
ctx.actions.run(
progress_message = "Bundling DTS %s" % str(ctx.label),
mnemonic = "APIExtractor",
executable = ctx.executable._api_extractor,
inputs = filter_inputs,
outputs = [dts_bundle_out],
outputs = dts_bundles_out,
arguments = [
tsconfig_file.path,
"/".join([ctx.bin_dir.path, ctx.label.package, dts_entry_point]),
dts_bundle_out.path,
",".join(["/".join([ctx.bin_dir.path, ctx.label.package, f]) for f in dts_entry_points]),
",".join([f.path for f in dts_bundles_out]),
],
)
@ -454,7 +480,7 @@ def _filter_ts_inputs(all_inputs):
if f.path.endswith(".js") or f.path.endswith(".ts") or f.path.endswith(".json")
]
def _compile_action(ctx, inputs, outputs, dts_bundle_out, messages_out, tsconfig_file, node_opts):
def _compile_action(ctx, inputs, outputs, dts_bundles_out, messages_out, tsconfig_file, node_opts):
# Give the Angular compiler all the user-listed assets
file_inputs = list(ctx.files.assets)
@ -483,7 +509,7 @@ def _compile_action(ctx, inputs, outputs, dts_bundle_out, messages_out, tsconfig
],
)
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, tsconfig_file, node_opts, None, [], dts_bundle_out)
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, tsconfig_file, node_opts, None, [], dts_bundles_out)
def _prodmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
outs = _expected_outs(ctx)
@ -492,7 +518,7 @@ def _prodmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
def _devmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
outs = _expected_outs(ctx)
compile_action_outputs = outputs + outs.devmode_js + outs.declarations + outs.summaries + outs.metadata
_compile_action(ctx, inputs, compile_action_outputs, outs.dts_bundle, None, tsconfig_file, node_opts)
_compile_action(ctx, inputs, compile_action_outputs, outs.dts_bundles, None, tsconfig_file, node_opts)
def _ts_expected_outs(ctx, label, srcs_files = []):
# rules_typescript expects a function with two or more arguments, but our
@ -553,8 +579,8 @@ def ng_module_impl(ctx, ts_compile_actions):
flat_module_out_file = _flat_module_out_file(ctx),
)
if outs.dts_bundle != None:
providers["dts_bundle"] = outs.dts_bundle
if outs.dts_bundles != None:
providers["dts_bundles"] = outs.dts_bundles
return providers

View File

@ -229,8 +229,8 @@ def _ng_package_impl(ctx):
# fallback to a reasonable default
flat_module_out_file = "index.js"
if hasattr(dep, "dts_bundle"):
bundled_type_definitions.append(dep.dts_bundle)
if hasattr(dep, "dts_bundles"):
bundled_type_definitions += dep.dts_bundles
elif len(type_definitions) == 0:
# Filter out all TypeScript definitions generated by NGC as well as definition files
# that do not belong to the current package. We only want to package types that belong

View File

@ -27,13 +27,9 @@ function p(templateStringArray: TemplateStringsArray) {
return path.join(...segments);
}
describe('@angular/core ng_package', () => {
describe('misc root files', () => {
describe('README.md', () => {
it('should have a README.md file with basic info', () => {
expect(shx.cat('README.md')).toContain(`Angular`);
expect(shx.cat('README.md')).toContain(`https://github.com/angular/angular`);
@ -41,17 +37,13 @@ describe('@angular/core ng_package', () => {
});
});
describe('primary entry-point', () => {
describe('package.json', () => {
const packageJson = 'package.json';
it('should have a package.json file',
() => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); });
it('should contain correct version number with the PLACEHOLDER string replaced', () => {
expect(shx.grep('"version":', packageJson)).toMatch(/\d+\.\d+\.\d+(?!-PLACEHOLDER)/);
});
@ -72,31 +64,33 @@ describe('@angular/core ng_package', () => {
});
});
describe('typescript support', () => {
it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain(`export *`); });
if (ivyEnabled) {
it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain(`export *`); });
it('should not have amd module names',
() => { expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); });
it('should not have amd module names',
() => { expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); });
} else {
it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain('export declare'); });
it('should have an r3_symbols d.ts file',
() => { expect(shx.cat('src/r3_symbols.d.ts')).toContain('export declare'); });
}
});
describe('closure', () => {
it('should contain externs', () => {
expect(shx.cat('src/testability/testability.externs.js')).toContain('/** @externs */');
});
});
obsoleteInIvy('metadata files are no longer needed or produced in Ivy')
.describe('angular metadata', () => {
it('should have metadata.json files',
() => { expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); });
});
describe('fesm2015', () => {
it('should have a fesm15 file in the /fesm2015 directory',
() => { expect(shx.cat('fesm2015/core.js')).toContain(`export {`); });
@ -117,9 +111,7 @@ describe('@angular/core ng_package', () => {
});
});
describe('fesm5', () => {
it('should have a fesm5 file in the /fesm5 directory',
() => { expect(shx.cat('fesm5/core.js')).toContain(`export {`); });
@ -151,7 +143,6 @@ describe('@angular/core ng_package', () => {
() => { expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator'); });
});
describe('esm2015', () => {
it('should not contain any *.ngfactory.js files', () => {
expect(shx.find('esm2015').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]);
@ -162,7 +153,6 @@ describe('@angular/core ng_package', () => {
});
});
describe('esm5', () => {
it('should not contain any *.ngfactory.js files',
() => { expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); });
@ -171,9 +161,7 @@ describe('@angular/core ng_package', () => {
() => { expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]); });
});
describe('umd', () => {
it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found'); });
@ -204,7 +192,6 @@ describe('@angular/core ng_package', () => {
describe('secondary entry-point', () => {
describe('package.json', () => {
const packageJson = p `testing/package.json`;
it('should have a package.json file',
@ -222,9 +209,15 @@ describe('@angular/core ng_package', () => {
});
describe('typings', () => {
const typingsFile = p `testing/index.d.ts`;
it('should have a typings file',
() => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); });
if (ivyEnabled) {
const typingsFile = p `testing/index.d.ts`;
it('should have a typings file',
() => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); });
} else {
const typingsFile = p `testing/testing.d.ts`;
it('should have a typings file',
() => { expect(shx.cat(typingsFile)).toContain('export declare'); });
}
obsoleteInIvy(
'now that we don\'t need metadata files, we don\'t need these redirects to help resolve paths to them')
@ -268,7 +261,6 @@ describe('@angular/core ng_package', () => {
});
describe('umd', () => {
it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found'); });
@ -292,7 +284,6 @@ describe('@angular/core ng_package', () => {
it('should define ng global symbols', () => {
expect(shx.cat('bundles/core-testing.umd.js')).toContain('global.ng.core.testing = {}');
});
});
});
});

View File

@ -10,8 +10,6 @@ ng_module(
"src/**/*.ts",
],
),
# PR to support this https://github.com/angular/angular/pull/28884
bundle_dts = False,
deps = [
"//packages:types",
"//packages/core/src/compiler",

View File

@ -19,7 +19,9 @@ import {stringify} from '../util/stringify';
import {EMPTY_ARRAY, EMPTY_OBJ} from './empty';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
import {BaseDef, ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveType, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction} from './interfaces/definition';
import {CssSelectorList} from './interfaces/projection';
// while SelectorFlags is unused here, it's required so that types don't get resolved lazily
// see: https://github.com/Microsoft/web-build-tools/issues/1050
import {CssSelectorList, SelectorFlags} from './interfaces/projection';
let _renderCompCount = 0;

View File

@ -9,8 +9,6 @@ ng_module(
srcs = glob(
["**/*.ts"],
),
# PR to support this https://github.com/angular/angular/pull/28884
bundle_dts = False,
deps = [
"//packages:types",
"//packages/compiler",