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); 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" _FLAT_DTS_FILE_SUFFIX = ".bundle.d.ts"
_R3_SYMBOLS_DTS_FILE = "src/r3_symbols.d.ts"
def compile_strategy(ctx): def compile_strategy(ctx):
"""Detect which strategy should be used to implement ng_module. """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 # 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 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): def _should_produce_flat_module_outs(ctx):
"""Should we produce flat module outputs. """Should we produce flat module outputs.
@ -221,13 +241,16 @@ def _expected_outs(ctx):
if not _is_bazel(): if not _is_bazel():
metadata_files += [ctx.actions.declare_file(basename + ext) for ext in metadata] metadata_files += [ctx.actions.declare_file(basename + ext) for ext in metadata]
dts_bundle = None dts_bundles = None
if _should_produce_dts_bundle(ctx): if _should_produce_dts_bundle(ctx):
# We need to add a suffix to bundle as it might collide with the flat module dts. # 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 # 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' # 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 # We do this just when producing a flat module index for a publishable ng_module
if _should_produce_flat_module_outs(ctx): if _should_produce_flat_module_outs(ctx):
@ -254,7 +277,7 @@ def _expected_outs(ctx):
declarations = declaration_files, declarations = declaration_files,
summaries = summary_files, summaries = summary_files,
metadata = metadata_files, metadata = metadata_files,
dts_bundle = dts_bundle, dts_bundles = dts_bundles,
bundle_index_typings = bundle_index_typings, bundle_index_typings = bundle_index_typings,
i18n_messages = i18n_messages_files, i18n_messages = i18n_messages_files,
) )
@ -337,7 +360,7 @@ def ngc_compile_action(
node_opts, node_opts,
locale = None, locale = None,
i18n_args = [], i18n_args = [],
dts_bundle_out = None): dts_bundles_out = None):
"""Helper function to create the ngc action. """Helper function to create the ngc action.
This is exposed for google3 to wire up i18n replay rules, and is not intended 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. node_opts: list of strings, extra nodejs options.
locale: i18n locale, or None locale: i18n locale, or None
i18n_args: additional command-line arguments to ngc i18n_args: additional command-line arguments to ngc
dts_bundle_out: produced flattened dts file dts_bundles_out: produced flattened dts file
Returns: Returns:
the parameters of the compilation which will be used to replay the ngc action for i18N. 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", mnemonic = "Angular2MessageExtractor",
) )
if dts_bundle_out != None: if dts_bundles_out != None:
# combine the inputs and outputs and filter .d.ts and json files # 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")] 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): 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: 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( ctx.actions.run(
progress_message = "Bundling DTS %s" % str(ctx.label), progress_message = "Bundling DTS %s" % str(ctx.label),
mnemonic = "APIExtractor", mnemonic = "APIExtractor",
executable = ctx.executable._api_extractor, executable = ctx.executable._api_extractor,
inputs = filter_inputs, inputs = filter_inputs,
outputs = [dts_bundle_out], outputs = dts_bundles_out,
arguments = [ arguments = [
tsconfig_file.path, tsconfig_file.path,
"/".join([ctx.bin_dir.path, ctx.label.package, dts_entry_point]), ",".join(["/".join([ctx.bin_dir.path, ctx.label.package, f]) for f in dts_entry_points]),
dts_bundle_out.path, ",".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") 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 # Give the Angular compiler all the user-listed assets
file_inputs = list(ctx.files.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): def _prodmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
outs = _expected_outs(ctx) 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): def _devmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
outs = _expected_outs(ctx) outs = _expected_outs(ctx)
compile_action_outputs = outputs + outs.devmode_js + outs.declarations + outs.summaries + outs.metadata 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 = []): def _ts_expected_outs(ctx, label, srcs_files = []):
# rules_typescript expects a function with two or more arguments, but our # 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), flat_module_out_file = _flat_module_out_file(ctx),
) )
if outs.dts_bundle != None: if outs.dts_bundles != None:
providers["dts_bundle"] = outs.dts_bundle providers["dts_bundles"] = outs.dts_bundles
return providers return providers

View File

@ -229,8 +229,8 @@ def _ng_package_impl(ctx):
# fallback to a reasonable default # fallback to a reasonable default
flat_module_out_file = "index.js" flat_module_out_file = "index.js"
if hasattr(dep, "dts_bundle"): if hasattr(dep, "dts_bundles"):
bundled_type_definitions.append(dep.dts_bundle) bundled_type_definitions += dep.dts_bundles
elif len(type_definitions) == 0: elif len(type_definitions) == 0:
# Filter out all TypeScript definitions generated by NGC as well as definition files # 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 # 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); return path.join(...segments);
} }
describe('@angular/core ng_package', () => { describe('@angular/core ng_package', () => {
describe('misc root files', () => { describe('misc root files', () => {
describe('README.md', () => { describe('README.md', () => {
it('should have a README.md file with basic info', () => { it('should have a README.md file with basic info', () => {
expect(shx.cat('README.md')).toContain(`Angular`); expect(shx.cat('README.md')).toContain(`Angular`);
expect(shx.cat('README.md')).toContain(`https://github.com/angular/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('primary entry-point', () => {
describe('package.json', () => { describe('package.json', () => {
const packageJson = 'package.json'; const packageJson = 'package.json';
it('should have a package.json file', it('should have a package.json file',
() => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); }); () => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); });
it('should contain correct version number with the PLACEHOLDER string replaced', () => { it('should contain correct version number with the PLACEHOLDER string replaced', () => {
expect(shx.grep('"version":', packageJson)).toMatch(/\d+\.\d+\.\d+(?!-PLACEHOLDER)/); expect(shx.grep('"version":', packageJson)).toMatch(/\d+\.\d+\.\d+(?!-PLACEHOLDER)/);
}); });
@ -72,31 +64,33 @@ describe('@angular/core ng_package', () => {
}); });
}); });
describe('typescript support', () => { describe('typescript support', () => {
it('should have an index d.ts file', if (ivyEnabled) {
() => { expect(shx.cat('core.d.ts')).toContain(`export *`); }); it('should have an index d.ts file',
() => { expect(shx.cat('core.d.ts')).toContain(`export *`); });
it('should not have amd module names', it('should not have amd module names',
() => { expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); }); () => { 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', () => { describe('closure', () => {
it('should contain externs', () => { it('should contain externs', () => {
expect(shx.cat('src/testability/testability.externs.js')).toContain('/** @externs */'); expect(shx.cat('src/testability/testability.externs.js')).toContain('/** @externs */');
}); });
}); });
obsoleteInIvy('metadata files are no longer needed or produced in Ivy') obsoleteInIvy('metadata files are no longer needed or produced in Ivy')
.describe('angular metadata', () => { .describe('angular metadata', () => {
it('should have metadata.json files', it('should have metadata.json files',
() => { expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); }); () => { expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); });
}); });
describe('fesm2015', () => { describe('fesm2015', () => {
it('should have a fesm15 file in the /fesm2015 directory', it('should have a fesm15 file in the /fesm2015 directory',
() => { expect(shx.cat('fesm2015/core.js')).toContain(`export {`); }); () => { expect(shx.cat('fesm2015/core.js')).toContain(`export {`); });
@ -117,9 +111,7 @@ describe('@angular/core ng_package', () => {
}); });
}); });
describe('fesm5', () => { describe('fesm5', () => {
it('should have a fesm5 file in the /fesm5 directory', it('should have a fesm5 file in the /fesm5 directory',
() => { expect(shx.cat('fesm5/core.js')).toContain(`export {`); }); () => { 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'); }); () => { expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator'); });
}); });
describe('esm2015', () => { describe('esm2015', () => {
it('should not contain any *.ngfactory.js files', () => { it('should not contain any *.ngfactory.js files', () => {
expect(shx.find('esm2015').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); expect(shx.find('esm2015').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]);
@ -162,7 +153,6 @@ describe('@angular/core ng_package', () => {
}); });
}); });
describe('esm5', () => { describe('esm5', () => {
it('should not contain any *.ngfactory.js files', it('should not contain any *.ngfactory.js files',
() => { expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); }); () => { 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([]); }); () => { expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]); });
}); });
describe('umd', () => { describe('umd', () => {
it('should have a umd file in the /bundles directory', it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found'); }); () => { 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('secondary entry-point', () => {
describe('package.json', () => { describe('package.json', () => {
const packageJson = p `testing/package.json`; const packageJson = p `testing/package.json`;
it('should have a package.json file', it('should have a package.json file',
@ -222,9 +209,15 @@ describe('@angular/core ng_package', () => {
}); });
describe('typings', () => { describe('typings', () => {
const typingsFile = p `testing/index.d.ts`; if (ivyEnabled) {
it('should have a typings file', const typingsFile = p `testing/index.d.ts`;
() => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); }); 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( obsoleteInIvy(
'now that we don\'t need metadata files, we don\'t need these redirects to help resolve paths to them') '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', () => { describe('umd', () => {
it('should have a umd file in the /bundles directory', it('should have a umd file in the /bundles directory',
() => { expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found'); }); () => { 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', () => { it('should define ng global symbols', () => {
expect(shx.cat('bundles/core-testing.umd.js')).toContain('global.ng.core.testing = {}'); expect(shx.cat('bundles/core-testing.umd.js')).toContain('global.ng.core.testing = {}');
}); });
}); });
}); });
}); });

View File

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

View File

@ -19,7 +19,9 @@ import {stringify} from '../util/stringify';
import {EMPTY_ARRAY, EMPTY_OBJ} from './empty'; import {EMPTY_ARRAY, EMPTY_OBJ} from './empty';
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields'; 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 {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; let _renderCompCount = 0;

View File

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